diff options
Diffstat (limited to 'libtest/common.h')
| -rw-r--r-- | libtest/common.h | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/libtest/common.h b/libtest/common.h new file mode 100644 index 0000000..070b217 --- /dev/null +++ b/libtest/common.h @@ -0,0 +1,242 @@ +/* See LICENSE file for copyright and license details. */ +#ifdef WITH_BACKTRACE +# define UNW_LOCAL_ONLY +# include <libunwind.h> +# include <elfutils/libdwfl.h> +#endif +#include <sys/mman.h> +#include <errno.h> +#include <inttypes.h> +#include <stdatomic.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "libtest.h" + + +#if __STDC_VERSION__ >= 202311L +# define _Alignof alignof +# define _Alignas alignas +# define _Thread_local thread_local +#endif + + +#if defined(__GNUC__) +# define HIDDEN __attribute__((__visibility__("hidden"))) +# define CONST __attribute__((__const__)) +# define PURE __attribute__((__pure__)) +#else +# define HIDDEN +# define CONST +# define PURE +#endif + + +#if defined(__GNUC__) +# pragma GCC diagnostic ignored "-Wpadded" +#endif + + +#ifndef MAP_UNINITIALIZED +# define MAP_UNINITIALIZED 0 +#endif + + +#define ELEMSOF(A) (sizeof(A) / sizeof(*(A))) + + +#define BASE_POINTER(PTR) (*libtest_base_pointer((PTR))) +#define GET_MEMINFO(PTR) ((struct meminfo *)BASE_POINTER(PTR)) +#define SPINLOCK(LOCK) do {} while (atomic_flag_test_and_set_explicit(&(LOCK), memory_order_acquire)) +#define SPINUNLOCK(LOCK) atomic_flag_clear_explicit(&(LOCK), memory_order_release) + + +enum libtest_zero_check { + DO_NOT_REQUIRE_ZEROED, + REQUIRE_ZEROED +}; + +enum align_type { + DEFAULT_ALIGNMENT, + PAGE_ALIGNMENT, + CUSTOM_ALIGNMENT +}; + +enum memory_origin { + FROM_MALLOC, + FROM_CALLOC, + FROM_REALLOC, + FROM_REALLOCARRAY, + FROM_VALLOC, + FROM_PVALLOC, + FROM_MEMALIGN, + FROM_ALIGNED_ALLOC, + FROM_POSIX_MEMALIGN, + FROM_MMAP_FILE, + FROM_MMAP_ANON +}; + +#ifdef WITH_BACKTRACE +struct backtrace { + size_t n; + Dwarf_Addr trace[]; +}; +#endif + +struct meminfo { +#ifdef WITH_BACKTRACE + struct backtrace *backtrace; +#endif + struct meminfo *next, *prev; + void *usable_area; + size_t real_alloc_size; + size_t usable_alloc_size; + size_t requested_alloc_size; + size_t requested_alignment; + size_t actual_alignment; + enum align_type alignment_type; + int initialised_on_alloc; + enum memory_origin origin; + int accept_leakage; /* implies DO_NOT_REQUIRE_ZEROED */ +}; + + +extern volatile int libtest_malloc_is_custom; +extern volatile int libtest_calloc_is_custom; +extern volatile int libtest_realloc_is_custom; +extern volatile int libtest_reallocarray_is_custom; +extern volatile int libtest_valloc_is_custom; +extern volatile int libtest_pvalloc_is_custom; +extern volatile int libtest_memalign_is_custom; +extern volatile int libtest_aligned_alloc_is_custom; +extern volatile int libtest_posix_memalign_is_custom; +extern volatile int libtest_malloc_usable_size_is_custom; +extern volatile int libtest_free_is_custom; +extern volatile int libtest_free_sized_is_custom; +extern volatile int libtest_free_aligned_sized_is_custom; + +extern struct meminfo libtest_allocs_head; +extern struct meminfo libtest_allocs_tail; +extern int libtest_allocs_list_inited; +extern atomic_flag libtest_allocs_list_spinlock; + +extern int libtest_zero_on_alloc; +extern int libtest_expect_zeroed; +extern int libtest_malloc_accept_leakage; + +extern _Thread_local size_t libtest_malloc_internal_usage; +extern _Thread_local size_t libtest_kill_malloc_tracking; + + +HIDDEN inline void ** +libtest_base_pointer(void *ptr) +{ + uintptr_t addr = (uintptr_t)ptr - (uintptr_t)sizeof(void *); + addr -= addr % _Alignof(void *); + return (void **)addr; +} + + +HIDDEN size_t libtest_get_pagesize(void); +HIDDEN void *libtest_alloc(struct meminfo *); +HIDDEN void libtest_free(void *, enum libtest_zero_check); + +#ifdef WITH_BACKTRACE +HIDDEN void libtest_print_backtrace(FILE *, const char *indent, size_t first, const struct backtrace *); +#else +# define libtest_print_backtrace(FP, INDENT, FIRST, BACKTRACE) ((void)0) +#endif + + +void *__mmap(void *, size_t, int, int, int, off_t); +int __munmap(void *, size_t); +void *__mremap(void *, size_t, size_t, int, ...); +#define libtest_real_mmap __mmap +#define libtest_real_munmap __munmap +#define libtest_real_mremap __mremap + + +#define assert(EXPR)\ + do {\ + if (!(EXPR)) {\ + libtest_malloc_internal_usage++;\ + fprintf(stderr, "Assetion failure at %s:%i: %s\n", __FILE__, __LINE__, #EXPR);\ + libtest_print_backtrace(stderr, "\t", 0u, NULL);\ + exit(2);\ + }\ + } while (0) + + +#ifdef TEST +# ifdef __linux__ +# include <sys/prctl.h> +# endif +# include <sys/resource.h> +# include <sys/types.h> +# include <sys/wait.h> +# include <signal.h> +# include <string.h> +# include <unistd.h> + +# define SET_UP_ALARM()\ + do {\ + unsigned int alarm_time__ = alarm(10u);\ + if (alarm_time__ > 10u)\ + alarm(alarm_time__);\ + } while (0) + +# if defined(PR_SET_DUMPABLE) +# define INIT_TEST_ABORT()\ + do {\ + struct rlimit rl__;\ + rl__.rlim_cur = 0;\ + rl__.rlim_max = 0;\ + (void) setrlimit(RLIMIT_CORE, &rl__);\ + (void) prctl(PR_SET_DUMPABLE, 0);\ + EXPECT_ABORT(abort());\ + } while (0) +# else +# define INIT_TEST_ABORT()\ + do {\ + struct rlimit rl__;\ + rl__.rlim_cur = 0;\ + rl__.rlim_max = 0;\ + (void) setrlimit(RLIMIT_CORE, &rl__);\ + EXPECT_ABORT(abort());\ + } while (0) +# endif + +# define EXPECT__(EXPR, HOW, RETEXTRACT, RETEXPECT)\ + do {\ + pid_t pid__;\ + int status__;\ + pid__ = fork();\ + EXPECT(pid__ != -1);\ + if (pid__ == 0) {\ + (EXPR);\ + _exit(0);\ + }\ + EXPECT(waitpid(pid__, &status__, 0) == pid__);\ + EXPECT(HOW(status__));\ + EXPECT(RETEXTRACT(status__) == RETEXPECT);\ + } while (0) + +# define EXPECT_ABORT(EXPR)\ + do {\ + EXPECT__(EXPR, WIFSIGNALED, WTERMSIG, SIGABRT);\ + } while (0) + +# define EXPECT(EXPR)\ + do {\ + if (!(EXPR)) {\ + libtest_malloc_internal_usage++;\ + fprintf(stderr, "Failure at %s:%i: %s\n", __FILE__, __LINE__, #EXPR);\ + libtest_print_backtrace(stderr, "\t", 0u, NULL);\ + exit(1);\ + }\ + } while (0) +#endif |
