/* See LICENSE file for copyright and license details. */ #include "common.h" #ifndef TEST void libtest_free(void *ptr, enum libtest_zero_check zero_checking) { struct meminfo *mem; int saved_errno = errno; int unmap_err, memory_zeroed; uint8_t *usable_area; size_t i; #ifdef WITH_BACKTRACE static _Thread_local int inside_free = 0; #endif /* free(3) can be called with NULL */ if (!ptr) return; /* Optionally print out trace */ #ifdef WITH_BACKTRACE if (!inside_free && getenv("PRETRACE_FREE")) { inside_free = 1; fprintf(stderr, "Deallocating: %p\n", ptr); libtest_print_backtrace(stderr, NULL, "\tat ", 0u, NULL, NULL); fflush(stderr); inside_free = 0; } #endif /* Get the start of the allocation, which * is where the book-keeping is located */ mem = GET_MEMINFO(ptr); /* It is illegal to use free(3) on memory allocated with mmap(3)/mmap(2) */ assert(mem->origin != FROM_MMAP_FILE); assert(mem->origin != FROM_MMAP_ANON); /* Delist allocation */ SPINLOCK(libtest_allocs_list_spinlock); if (!libtest_kill_malloc_tracking) { mem->prev->next = mem->next; mem->next->prev = mem->prev; } for (i = 0u; i < libtest_npretends; i++) { if (libtest_pretend_list[i] == ptr) { libtest_pretend_list[i] = libtest_pretend_list[--libtest_npretends]; break; } } SPINUNLOCK(libtest_allocs_list_spinlock); /* Check memory is zeroed */ if (zero_checking && libtest_expect_zeroed && !mem->accept_leakage) { usable_area = mem->usable_area; memory_zeroed = 1; for (i = 0u; i < mem->usable_alloc_size; i++) { if (usable_area[i]) { memory_zeroed = 0; libtest_expect_zeroed = 0; break; } } #ifdef WITH_BACKTRACE if (!memory_zeroed && mem->backtrace) { libtest_malloc_internal_usage++; inside_free = 1; fprintf(stderr, "Memory not zeroed out before deallocation: %p\n", ptr); libtest_print_backtrace(stderr, "\tAllocated at ", "\t at ", 0u, mem->backtrace, NULL); inside_free = 0; } #endif assert(memory_zeroed); } /* Optionally print out trace */ #ifdef WITH_BACKTRACE if (!inside_free && getenv("TRACE_MALLOC")) { inside_free = 1; fprintf(stderr, "Memory deallocated: %p (alloc-size=%zu, real-size=%zu)\n", ptr, mem->requested_alloc_size, mem->real_alloc_size); if (getenv("TRACE_FREE") && !getenv("PRETRACE_FREE")) libtest_print_backtrace(stderr, NULL, "\tat ", 0u, NULL, NULL); fflush(stderr); inside_free = 0; } #endif /* Deallocate memory */ unmap_err = libtest_real_munmap(mem, mem->real_alloc_size); assert(!unmap_err); errno = saved_errno; } #else CONST int main(void) { /* Tested via alloc.c */ return 0; } #endif