diff options
Diffstat (limited to 'libtest')
| -rw-r--r-- | libtest/Makefile | 6 | ||||
| -rw-r--r-- | libtest/alloc.c | 335 | ||||
| -rw-r--r-- | libtest/alloc_have_custom.c | 15 | ||||
| -rw-r--r-- | libtest/common-config.mk | 16 | ||||
| -rw-r--r-- | libtest/common.h | 63 | ||||
| -rw-r--r-- | libtest/config.mk | 1 | ||||
| -rw-r--r-- | libtest/config_backtraces=false.mk | 10 | ||||
| -rw-r--r-- | libtest/config_backtraces=true.mk | 10 | ||||
| -rw-r--r-- | libtest/globals.c | 6 | ||||
| -rw-r--r-- | libtest/libtest.h | 387 | ||||
| -rw-r--r-- | libtest/libtest_alloc.c | 17 | ||||
| -rw-r--r-- | libtest/libtest_check_no_leaks.c | 2 | ||||
| -rw-r--r-- | libtest/libtest_dump_stack.c | 5 | ||||
| -rw-r--r-- | libtest/libtest_free.c | 4 | ||||
| -rw-r--r-- | libtest/libtest_get_alloc_failure_in.c | 31 | ||||
| -rw-r--r-- | libtest/libtest_print_backtrace.c | 24 | ||||
| -rw-r--r-- | libtest/libtest_set_alloc_failure_in.c | 32 | ||||
| -rw-r--r-- | libtest/libtest_stack_on_signal.c | 102 | ||||
| -rw-r--r-- | libtest/mmap.c | 72 |
19 files changed, 1091 insertions, 47 deletions
diff --git a/libtest/Makefile b/libtest/Makefile index 1bb870b..86b30ed 100644 --- a/libtest/Makefile +++ b/libtest/Makefile @@ -11,6 +11,7 @@ include ../mk/$(OS).mk OBJ =\ + $(OBJ_MMAP)\ alloc.o\ alloc_have_custom.o\ globals.o\ @@ -24,7 +25,10 @@ OBJ =\ libtest_start_tracking.o\ libtest_stop_tracking.o\ libtest_dump_stack.o\ - $(OBJ_BACKTRACE) + libtest_stack_on_signal.o\ + libtest_get_alloc_failure_in.o\ + libtest_set_alloc_failure_in.o\ + $(OBJ_BACKTRACE)\ HDR =\ libtest.h\ diff --git a/libtest/alloc.c b/libtest/alloc.c index 842f856..65eda04 100644 --- a/libtest/alloc.c +++ b/libtest/alloc.c @@ -75,6 +75,7 @@ void * { libtest_malloc_is_custom = 1; assert(libtest_have_custom_free()); + assert(libtest_have_custom_free_sized()); return common_malloc(n, FROM_MALLOC); } @@ -87,6 +88,7 @@ void * libtest_calloc_is_custom = 1; assert(libtest_have_custom_free()); + assert(libtest_have_custom_free_sized()); assert(n); assert(m); @@ -112,6 +114,7 @@ void * { libtest_realloc_is_custom = 1; assert(libtest_have_custom_free()); + assert(libtest_have_custom_free_sized()); return common_realloc(old_ptr, new_n, FROM_REALLOC); } @@ -122,6 +125,7 @@ void * { libtest_reallocarray_is_custom = 1; assert(libtest_have_custom_free()); + assert(libtest_have_custom_free_sized()); assert(new_n); assert(new_m); @@ -182,6 +186,7 @@ void * { libtest_memalign_is_custom = 1; assert(libtest_have_custom_free()); + assert(libtest_have_custom_free_aligned_sized()); return common_memalign(alignment, size, FROM_MEMALIGN); } @@ -192,6 +197,7 @@ void * { libtest_aligned_alloc_is_custom = 1; assert(libtest_have_custom_free()); + assert(libtest_have_custom_free_aligned_sized()); assert(alignment); assert(!(size % alignment)); @@ -209,6 +215,7 @@ int libtest_posix_memalign_is_custom = 1; assert(libtest_have_custom_free()); + assert(libtest_have_custom_free_aligned_sized()); assert(size); assert(alignment); @@ -232,8 +239,7 @@ int } -PURE -size_t +PURE size_t (malloc_usable_size)(void *ptr) { libtest_malloc_usable_size_is_custom = 1; @@ -248,6 +254,21 @@ void { libtest_free_is_custom = 1; + assert(libtest_have_custom_malloc()); + assert(libtest_have_custom_calloc()); + assert(libtest_have_custom_realloc()); + assert(libtest_have_custom_reallocarray()); + assert(libtest_have_custom_valloc()); + assert(libtest_have_custom_pvalloc()); + assert(libtest_have_custom_memalign()); + assert(libtest_have_custom_aligned_alloc()); + assert(libtest_have_custom_posix_memalign()); + assert(libtest_have_custom_strdup()); + assert(libtest_have_custom_strndup()); + assert(libtest_have_custom_wcsdup()); + assert(libtest_have_custom_wcsdup()); + assert(libtest_have_custom_memdup()); + if (ptr) { struct meminfo *meminfo; meminfo = GET_MEMINFO(ptr); @@ -266,6 +287,12 @@ void { libtest_free_sized_is_custom = 1; + assert(libtest_have_custom_malloc()); + assert(libtest_have_custom_calloc()); + assert(libtest_have_custom_realloc()); + assert(libtest_have_custom_reallocarray()); + assert(libtest_have_custom_memdup()); + if (ptr) { struct meminfo *meminfo; meminfo = GET_MEMINFO(ptr); @@ -282,18 +309,113 @@ void { libtest_free_aligned_sized_is_custom = 1; + assert(libtest_have_custom_memalign()); + assert(libtest_have_custom_aligned_alloc()); + assert(libtest_have_custom_posix_memalign()); + if (ptr) { struct meminfo *meminfo; meminfo = GET_MEMINFO(ptr); assert(meminfo->alignment_type == CUSTOM_ALIGNMENT); assert(meminfo->requested_alloc_size == size); assert(meminfo->requested_alignment == alignment); + assert(meminfo->origin != FROM_STRDUP); + assert(meminfo->origin != FROM_STRNDUP); + assert(meminfo->origin != FROM_WCSDUP); + assert(meminfo->origin != FROM_WCSDUP); } libtest_free(ptr, REQUIRE_ZEROED); } +char * +(strdup)(const char *s) +{ + size_t n; + char *p; + + libtest_strdup_is_custom = 1; + assert(libtest_have_custom_free()); + + n = strlen(s) + 1u; + p = common_memalign(_Alignof(char), n * sizeof(*s), FROM_STRDUP); + if (p) + memcpy(p, s, n * sizeof(*s)); + return p; +} + + +char * +(strndup)(const char *s, size_t n) +{ + char *p; + + libtest_strndup_is_custom = 1; + assert(libtest_have_custom_free()); + + n = strnlen(s, n); + p = common_memalign(_Alignof(char), (n + 1u) * sizeof(*s), FROM_STRNDUP); + if (p) { + memcpy(p, s, n * sizeof(*s)); + p[n] = '\0'; + } + return p; +} + + +wchar_t * +(wcsdup)(const wchar_t *s) +{ + size_t n; + wchar_t *p; + + libtest_wcsdup_is_custom = 1; + assert(libtest_have_custom_free()); + + n = wcslen(s) + 1u; + p = common_memalign(_Alignof(wchar_t), n * sizeof(*s), FROM_WCSDUP); + if (p) + memcpy(p, s, n * sizeof(*s)); + return p; +} + + +wchar_t * +(wcsndup)(const wchar_t *s, size_t n) +{ + wchar_t *p; + + libtest_wcsndup_is_custom = 1; + assert(libtest_have_custom_free()); + + n = wcsnlen(s, n); + p = common_memalign(_Alignof(wchar_t), (n + 1u) * sizeof(*s), FROM_WCSNDUP); + if (p) { + memcpy(p, s, n * sizeof(*s)); + p[n] = 0; + } + return p; +} + + +void * +(memdup)(const void *s, size_t n) +{ + char *p; + + libtest_memdup_is_custom = 1; + assert(libtest_have_custom_free()); + assert(libtest_have_custom_free_sized()); + + p = common_malloc(n, FROM_MEMDUP); + if (p) + memcpy(p, s, n); + return p; +} + + + #else @@ -315,6 +437,11 @@ size_t (malloc_usable_size)(void *ptr); void (free)(void *ptr); void (free_sized)(void *ptr, size_t size); void (free_aligned_sized)(void *ptr, size_t alignment, size_t size); +char *(strdup)(const char *s); +char *(strndup)(const char *s, size_t n); +wchar_t *(wcsdup)(const wchar_t *s); +wchar_t *(wcsndup)(const wchar_t *s, size_t n); +void *(memdup)(const void *s, size_t n); static void @@ -463,14 +590,12 @@ check(int use_free) } -int -main(void) +static void +check_successfuls(void) { size_t pagesize; - - SET_UP_ALARM(); - - libtest_start_tracking(); + char *s; + wchar_t *w; check(1); check(0); @@ -495,10 +620,198 @@ main(void) assert(malloc_usable_size(p) >= pagesize); /* cannot be free(3)ed */ - assert(libtest_check_no_leaks()); - return 0; + libtest_start_tracking(); + + s = strdup("test string"); + assert(s); + assert(malloc_usable_size(s) >= sizeof("test string")); + assert(GET_MEMINFO(s)->requested_alignment == _Alignof(char)); + assert((uintptr_t)s % (uintptr_t)_Alignof(char) == 0u); + assert(GET_MEMINFO(s)->requested_alloc_size == sizeof("test string")); + EXPECT(!strcmp(s, "test string")); + free(s); + + s = strndup("test string", 100u); + assert(s); + assert(malloc_usable_size(s) >= sizeof("test string")); + assert(GET_MEMINFO(s)->requested_alignment == _Alignof(char)); + assert((uintptr_t)s % (uintptr_t)_Alignof(char) == 0u); + assert(GET_MEMINFO(s)->requested_alloc_size == sizeof("test string")); + EXPECT(!strcmp(s, "test string")); + free(s); + + s = strndup("test string", 4u); + assert(s); + assert(malloc_usable_size(s) >= sizeof("test")); + assert(GET_MEMINFO(s)->requested_alignment == _Alignof(char)); + assert((uintptr_t)s % (uintptr_t)_Alignof(char) == 0u); + assert(GET_MEMINFO(s)->requested_alloc_size == sizeof("test")); + EXPECT(!strcmp(s, "test")); + free(s); + + s = memdup("test", 4u); + assert(s); + assert(malloc_usable_size(s) >= 4u); + assert(GET_MEMINFO(s)->requested_alignment == _Alignof(max_align_t)); + assert((uintptr_t)s % (uintptr_t)_Alignof(max_align_t) == 0u); + assert(GET_MEMINFO(s)->requested_alloc_size == 4u); + EXPECT(!memcmp(s, "test", 4u)); + free(s); + + w = wcsdup((wchar_t[]){11, 22, 33, 0}); + assert(w); + assert(malloc_usable_size(w) >= 4u * sizeof(wchar_t)); + assert(GET_MEMINFO(w)->requested_alignment == _Alignof(wchar_t)); + assert((uintptr_t)w % (uintptr_t)_Alignof(wchar_t) == 0u); + assert(GET_MEMINFO(w)->requested_alloc_size == 4u * sizeof(wchar_t)); + EXPECT(!memcmp(w, (wchar_t[]){11, 22, 33, 0}, 4u * sizeof(wchar_t))); + free(w); + + w = wcsndup((wchar_t[]){11, 22, 33, 0}, 100u); + assert(w); + assert(malloc_usable_size(w) >= 4u * sizeof(wchar_t)); + assert(GET_MEMINFO(w)->requested_alignment == _Alignof(wchar_t)); + assert((uintptr_t)w % (uintptr_t)_Alignof(wchar_t) == 0u); + assert(GET_MEMINFO(w)->requested_alloc_size == 4u * sizeof(wchar_t)); + EXPECT(!memcmp(w, (wchar_t[]){11, 22, 33, 0}, 4u * sizeof(wchar_t))); + free(w); + + w = wcsndup((wchar_t[]){11, 22, 33, 0}, 2u); + assert(w); + assert(malloc_usable_size(w) >= 3u * sizeof(wchar_t)); + assert(GET_MEMINFO(w)->requested_alignment == _Alignof(wchar_t)); + assert((uintptr_t)w % (uintptr_t)_Alignof(wchar_t) == 0u); + assert(GET_MEMINFO(w)->requested_alloc_size == 3u * sizeof(wchar_t)); + EXPECT(!memcmp(w, (wchar_t[]){11, 22, 0}, 3u * sizeof(wchar_t))); + free(w); +} + + +static void +check_failures(void) +{ + void *q; + + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(!malloc(1u)); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(!calloc(1u, 1u)); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(!realloc(NULL, 1u)); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + q = realloc(NULL, 1u); + assert(q); + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(!realloc(q, 1u)); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + free(q); + + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(!reallocarray(NULL, 1u, 1u)); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + q = reallocarray(NULL, 1u, 1u); + assert(q); + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(!reallocarray(q, 1u, 1u)); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + free(q); - /* TODO test failures */ + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(!memalign(1u, 1u)); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(!aligned_alloc(1u, 1u)); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(posix_memalign(&q, sizeof(void *), 1u) == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(!valloc(1u)); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(!pvalloc(1u)); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(!strdup("x")); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(!strndup("x", 1u)); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(!wcsdup((wchar_t[]){1, 0})); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(!wcsndup((wchar_t[]){1, 0}, 1u)); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); + + libtest_set_alloc_failure_in(1u); + errno = 0; + EXPECT(!memdup("x", 1u)); + EXPECT(errno == ENOMEM); + EXPECT(!libtest_get_alloc_failure_in()); +} + + +int +main(void) +{ + SET_UP_ALARM(); + + libtest_start_tracking(); + + check_successfuls(); + libtest_set_alloc_failure_in(1000u); + check_successfuls(); + EXPECT(libtest_get_alloc_failure_in() == 1000u - 31u); + check_failures(); + + p = NULL; + free(p); + + libtest_stop_tracking(); + EXPECT(libtest_check_no_leaks()); + return 0; } diff --git a/libtest/alloc_have_custom.c b/libtest/alloc_have_custom.c index ae67be0..d532c3f 100644 --- a/libtest/alloc_have_custom.c +++ b/libtest/alloc_have_custom.c @@ -21,6 +21,11 @@ PURE size_t (malloc_usable_size)(void *ptr); void (free)(void *ptr); void (free_sized)(void *ptr, size_t size); void (free_aligned_sized)(void *ptr, size_t alignment, size_t size); +char *(strdup)(const char *s); +char *(strndup)(const char *s, size_t n); +wchar_t *(wcsdup)(const wchar_t *s); +wchar_t *(wcsndup)(const wchar_t *s, size_t n); +void *(memdup)(const void *s, size_t n); #if defined(__GNUC__) # pragma GCC diagnostic pop @@ -100,6 +105,11 @@ int libtest_have_custom_valloc(void) { CHECK_CUSTOM_ALLOC(freeable_valloc, 1u); int libtest_have_custom_pvalloc(void) { CHECK_CUSTOM_ALLOC(freeable_pvalloc, 1u); } int libtest_have_custom_memalign(void) { CHECK_CUSTOM_ALLOC(memalign, 1u, 1u); } int libtest_have_custom_aligned_alloc(void) { CHECK_CUSTOM_ALLOC(aligned_alloc, 1u, 1u); } +int libtest_have_custom_strdup(void) { CHECK_CUSTOM_ALLOC(strdup, "x"); } +int libtest_have_custom_strndup(void) { CHECK_CUSTOM_ALLOC(strndup, "x", 1u); } +int libtest_have_custom_wcsdup(void) { CHECK_CUSTOM_ALLOC(wcsdup, (wchar_t[]){1, 0}); } +int libtest_have_custom_wcsndup(void) { CHECK_CUSTOM_ALLOC(wcsndup, &(wchar_t){1}, 1u); } +int libtest_have_custom_memdup(void) { CHECK_CUSTOM_ALLOC(memdup, "x", 1u); } int @@ -228,6 +238,11 @@ main(void) CHECK(libtest_have_custom_free); CHECK(libtest_have_custom_free_sized); CHECK(libtest_have_custom_free_aligned_sized); + CHECK(libtest_have_custom_strdup); + CHECK(libtest_have_custom_strndup); + CHECK(libtest_have_custom_wcsdup); + CHECK(libtest_have_custom_wcsndup); + CHECK(libtest_have_custom_memdup); return 0; } diff --git a/libtest/common-config.mk b/libtest/common-config.mk new file mode 100644 index 0000000..65c0ddd --- /dev/null +++ b/libtest/common-config.mk @@ -0,0 +1,16 @@ +C17 !=\ + if command -v c17 >/dev/null || ! command -v cc >/dev/null; then\ + echo c17;\ + else\ + echo cc -std=c17;\ + fi + +IMPLEMENT_MMAP_CPPFLAGS !=\ + if $(IMPLEMENT_MMAP); then\ + echo -DIMPLEMENT_MMAP;\ + fi + +OBJ_MMAP !=\ + if $(IMPLEMENT_MMAP); then\ + echo mmap.o;\ + fi diff --git a/libtest/common.h b/libtest/common.h index 070b217..667743a 100644 --- a/libtest/common.h +++ b/libtest/common.h @@ -7,13 +7,28 @@ #include <sys/mman.h> #include <errno.h> #include <inttypes.h> +#include <limits.h> +#include <signal.h> +#include <stdarg.h> #include <stdatomic.h> #include <stddef.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <string.h> #include <unistd.h> +#include <wchar.h> + + +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wpre-c11-compat" /* clang is being silly: it complains about _Thread_local */ +# pragma clang diagnostic ignored "-Wc++-keyword" /* clang is being silly: it complains about using wchar_t */ +# pragma clang diagnostic ignored "-Wimplicit-void-ptr-cast" /* clang is being silly: this is C, not C++ */ +# pragma clang diagnostic ignored "-Wunsafe-buffer-usage" /* completely broken warning */ +# pragma clang diagnostic ignored "-Wdisabled-macro-expansion" /* clang is being silly: it is common practice, and it complains about libc code */ +#endif + #include "libtest.h" @@ -76,6 +91,11 @@ enum memory_origin { FROM_MEMALIGN, FROM_ALIGNED_ALLOC, FROM_POSIX_MEMALIGN, + FROM_STRDUP, + FROM_STRNDUP, + FROM_WCSDUP, + FROM_WCSNDUP, + FROM_MEMDUP, FROM_MMAP_FILE, FROM_MMAP_ANON }; @@ -118,6 +138,11 @@ 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 volatile int libtest_strdup_is_custom; +extern volatile int libtest_strndup_is_custom; +extern volatile int libtest_wcsdup_is_custom; +extern volatile int libtest_wcsndup_is_custom; +extern volatile int libtest_memdup_is_custom; extern struct meminfo libtest_allocs_head; extern struct meminfo libtest_allocs_tail; @@ -130,6 +155,7 @@ extern int libtest_malloc_accept_leakage; extern _Thread_local size_t libtest_malloc_internal_usage; extern _Thread_local size_t libtest_kill_malloc_tracking; +extern _Thread_local size_t libtest_malloc_fail_in; HIDDEN inline void ** @@ -146,18 +172,41 @@ 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 *); +HIDDEN void libtest_print_backtrace(FILE *, const char *prefix, const char *indent, + size_t first, const struct backtrace *, ucontext_t *); #else -# define libtest_print_backtrace(FP, INDENT, FIRST, BACKTRACE) ((void)0) +# define libtest_print_backtrace(FP, PREFIX, INDENT, FIRST, BACKTRACE, CONTEXT)\ + do {\ + (void) (FP);\ + (void) (PREFIX);\ + (void) (INDENT);\ + (void) (FIRST);\ + (void) (BACKTRACE);\ + (void) (CONTEXT);\ + } while (0) #endif + +#ifdef IMPLEMENT_MMAP +void *libtest_real_mmap(void *, size_t, int, int, int, off_t); +int libtest_real_munmap(void *, size_t); +void *libtest_real_mremap(void *, size_t, size_t, int, ...); +#else +# if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wreserved-identifier" +# 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 libtest_real_mmap __mmap +# define libtest_real_munmap __munmap +# define libtest_real_mremap __mremap +# if defined(__clang__) +# pragma clang diagnostic pop +# endif +#endif #define assert(EXPR)\ @@ -165,7 +214,7 @@ void *__mremap(void *, size_t, size_t, int, ...); 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);\ + libtest_print_backtrace(stderr, NULL, "\t", 0u, NULL, NULL);\ exit(2);\ }\ } while (0) @@ -235,7 +284,7 @@ void *__mremap(void *, size_t, size_t, int, ...); if (!(EXPR)) {\ libtest_malloc_internal_usage++;\ fprintf(stderr, "Failure at %s:%i: %s\n", __FILE__, __LINE__, #EXPR);\ - libtest_print_backtrace(stderr, "\t", 0u, NULL);\ + libtest_print_backtrace(stderr, NULL, "\t", 0u, NULL, NULL);\ exit(1);\ }\ } while (0) diff --git a/libtest/config.mk b/libtest/config.mk index b2519f0..aa20790 100644 --- a/libtest/config.mk +++ b/libtest/config.mk @@ -1,4 +1,5 @@ WITH_BACKTRACE = true +IMPLEMENT_MMAP = false TEST_CONFIGFILE = config_backtraces=$(WITH_BACKTRACE).mk include $(TEST_INCLUDE_PREFIX)$(TEST_CONFIGFILE) diff --git a/libtest/config_backtraces=false.mk b/libtest/config_backtraces=false.mk index f508390..633d25a 100644 --- a/libtest/config_backtraces=false.mk +++ b/libtest/config_backtraces=false.mk @@ -1,10 +1,6 @@ -C17 !=\ - if command -v c17 >/dev/null || ! command -v cc >/dev/null; then\ - echo c17;\ - else\ - echo cc -std=c17;\ - fi +include common-config.mk -TEST_CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE +TEST_CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE\ + $(IMPLEMENT_MMAP_CPPFLAGS) TEST_CFLAGS = TEST_LDFLAGS = diff --git a/libtest/config_backtraces=true.mk b/libtest/config_backtraces=true.mk index 8233aaa..4331d96 100644 --- a/libtest/config_backtraces=true.mk +++ b/libtest/config_backtraces=true.mk @@ -1,11 +1,7 @@ -C17 !=\ - if command -v c17 >/dev/null || ! command -v cc >/dev/null; then\ - echo c17;\ - else\ - echo cc -std=c17;\ - fi +include common-config.mk -TEST_CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE -DWITH_BACKTRACE +TEST_CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE\ + $(IMPLEMENT_MMAP_CPPFLAGS) -DWITH_BACKTRACE TEST_CFLAGS = -g TEST_LDFLAGS = -lunwind -ldw diff --git a/libtest/globals.c b/libtest/globals.c index 9e9ec2f..430f037 100644 --- a/libtest/globals.c +++ b/libtest/globals.c @@ -16,6 +16,11 @@ volatile int libtest_malloc_usable_size_is_custom = -1; volatile int libtest_free_is_custom = -1; volatile int libtest_free_sized_is_custom = -1; volatile int libtest_free_aligned_sized_is_custom = -1; +volatile int libtest_strdup_is_custom = -1; +volatile int libtest_strndup_is_custom = -1; +volatile int libtest_wcsdup_is_custom = -1; +volatile int libtest_wcsndup_is_custom = -1; +volatile int libtest_memdup_is_custom = -1; struct meminfo libtest_allocs_head; struct meminfo libtest_allocs_tail; @@ -28,6 +33,7 @@ int libtest_malloc_accept_leakage = 1; _Thread_local size_t libtest_malloc_internal_usage = 0u; _Thread_local size_t libtest_kill_malloc_tracking = 0u; +_Thread_local size_t libtest_malloc_fail_in = 0u; #else diff --git a/libtest/libtest.h b/libtest/libtest.h index 3a3d963..b6484b2 100644 --- a/libtest/libtest.h +++ b/libtest/libtest.h @@ -1,23 +1,404 @@ /* See LICENSE file for copyright and license details. */ +#include <stddef.h> +#include <signal.h> + +/** + * Start tracking resources which `libtest_check_no_leaks` + * will detect if they are not released + */ void libtest_start_tracking(void); + +/** + * Stop tracking resources, so that `libtest_check_no_leaks` + * will not detect if they are not released + */ void libtest_stop_tracking(void); + +/** + * Check for resource leaks + * + * Any leak will be printed to standard error + * + * @return 1 if there was no leaks, 0 otherwise + */ int libtest_check_no_leaks(void); -void libtest_force_zero_on_alloc(int); -void libtest_expect_zeroed_on_free(int); + +/** + * Make all overriden memory allocation functions + * full the usable memory area with null bytes, + * or disable this feature + * + * @param enabled 1 to enable, 0 to disable + */ +void libtest_force_zero_on_alloc(int enabled); + +/** + * Make all overriden memory deallocation functions + * check that the entire usable memory area is filled + * with null bytes, or disable this feature + * + * @param enabled 1 to enable, 0 to disable + */ +void libtest_expect_zeroed_on_free(int enabled); + + +/** + * Test whether malloc(3) has been overridden, allowing + * allocations to be tracked, and memory allocation + * failures to be injected + * + * Tools like valgrind(1) prevent resource allocation + * functions from being overridden as they may override + * such functions themselves in order to detect leaks + * and invalid memory access patterns + * + * @return 1 if overridden, 0 otherwise + */ int libtest_have_custom_malloc(void); + +/** + * Test whether calloc(3) has been overridden, allowing + * allocations to be tracked, and memory allocation + * failures to be injected + * + * Tools like valgrind(1) prevent resource allocation + * functions from being overridden as they may override + * such functions themselves in order to detect leaks + * and invalid memory access patterns + * + * @return 1 if overridden, 0 otherwise + */ int libtest_have_custom_calloc(void); + +/** + * Test whether realloc(3) has been overridden, allowing + * allocations to be tracked, and memory allocation + * failures to be injected + * + * Tools like valgrind(1) prevent resource allocation + * functions from being overridden as they may override + * such functions themselves in order to detect leaks + * and invalid memory access patterns + * + * @return 1 if overridden, 0 otherwise + */ int libtest_have_custom_realloc(void); + +/** + * Test whether reallocarray(3) has been overridden, + * allowing allocations to be tracked, and memory + * allocation failures to be injected + * + * Tools like valgrind(1) prevent resource allocation + * functions from being overridden as they may override + * such functions themselves in order to detect leaks + * and invalid memory access patterns + * + * @return 1 if overridden, 0 otherwise + */ int libtest_have_custom_reallocarray(void); + +/** + * Test whether valloc(3) has been overridden, allowing + * allocations to be tracked, and memory allocation + * failures to be injected + * + * Tools like valgrind(1) prevent resource allocation + * functions from being overridden as they may override + * such functions themselves in order to detect leaks + * and invalid memory access patterns + * + * @return 1 if overridden, 0 otherwise + */ int libtest_have_custom_valloc(void); + +/** + * Test whether pvalloc(3) has been overridden, allowing + * allocations to be tracked, and memory allocation + * failures to be injected + * + * Tools like valgrind(1) prevent resource allocation + * functions from being overridden as they may override + * such functions themselves in order to detect leaks + * and invalid memory access patterns + * + * @return 1 if overridden, 0 otherwise + */ int libtest_have_custom_pvalloc(void); + +/** + * Test whether memalign(3) has been overridden, allowing + * allocations to be tracked, and memory allocation + * failures to be injected + * + * Tools like valgrind(1) prevent resource allocation + * functions from being overridden as they may override + * such functions themselves in order to detect leaks + * and invalid memory access patterns + * + * @return 1 if overridden, 0 otherwise + */ int libtest_have_custom_memalign(void); + +/** + * Test whether aligned_alloc(3) has been overridden, + * allowing allocations to be tracked, and memory + * allocation failures to be injected + * + * Tools like valgrind(1) prevent resource allocation + * functions from being overridden as they may override + * such functions themselves in order to detect leaks + * and invalid memory access patterns + * + * @return 1 if overridden, 0 otherwise + */ int libtest_have_custom_aligned_alloc(void); + +/** + * Test whether posix_memalign(3) has been overridden, + * allowing allocations to be tracked, and memory + * allocation failures to be injected + * + * Tools like valgrind(1) prevent resource allocation + * functions from being overridden as they may override + * such functions themselves in order to detect leaks + * and invalid memory access patterns + * + * @return 1 if overridden, 0 otherwise + */ int libtest_have_custom_posix_memalign(void); + +/** + * Test whether strdup(3) has been overridden, allowing + * allocations to be tracked, and memory allocation + * failures to be injected + * + * Tools like valgrind(1) prevent resource allocation + * functions from being overridden as they may override + * such functions themselves in order to detect leaks + * and invalid memory access patterns + * + * @return 1 if overridden, 0 otherwise + */ +int libtest_have_custom_strdup(void); + +/** + * Test whether strndup(3) has been overridden, allowing + * allocations to be tracked, and memory allocation + * failures to be injected + * + * Tools like valgrind(1) prevent resource allocation + * functions from being overridden as they may override + * such functions themselves in order to detect leaks + * and invalid memory access patterns + * + * @return 1 if overridden, 0 otherwise + */ +int libtest_have_custom_strndup(void); + +/** + * Test whether wcsdup(3) has been overridden, allowing + * allocations to be tracked, and memory allocation + * failures to be injected + * + * Tools like valgrind(1) prevent resource allocation + * functions from being overridden as they may override + * such functions themselves in order to detect leaks + * and invalid memory access patterns + * + * @return 1 if overridden, 0 otherwise + */ +int libtest_have_custom_wcsdup(void); + +/** + * Test whether wcsndup(3) has been overridden, allowing + * allocations to be tracked, and memory allocation + * failures to be injected + * + * Tools like valgrind(1) prevent resource allocation + * functions from being overridden as they may override + * such functions themselves in order to detect leaks + * and invalid memory access patterns + * + * @return 1 if overridden, 0 otherwise + */ +int libtest_have_custom_wcsndup(void); + +/** + * Test whether memdup(3) has been overridden, allowing + * allocations to be tracked, and memory allocation + * failures to be injected + * + * Tools like valgrind(1) prevent resource allocation + * functions from being overridden as they may override + * such functions themselves in order to detect leaks + * and invalid memory access patterns + * + * @return 1 if overridden, 0 otherwise + */ +int libtest_have_custom_memdup(void); + +/** + * Test whether malloc_usable_size(3) has been overridden, + * allowing it to be used for override implementations of + * memory allocation functions + * + * Tools like valgrind(1) prevent resource allocation + * inspection functions from being overridden as they + * may override such functions themselves as they may + * override memory allocation functions to detect leaks + * and invalid memory access patterns + * + * @return 1 if overridden, 0 otherwise + */ int libtest_have_custom_malloc_usable_size(void); + +/** + * Test whether free(3) has been overridden, allowing it + * to be used for override implementations of memory + * allocation functions + * + * Tools like valgrind(1) prevent resource deallocation + * functions from being overridden as they may override + * such functions themselves as they may override memory + * allocation functions to detect leaks and invalid + * memory access patterns + * + * You don't have to call this function yourself, + * overriden memory allocation function will call it + * and abort the process if this function return 0, + * likewise free(3) will abort the process if one of + * the memory allocation functions have not been + * overriden + * + * @return 1 if overridden, 0 otherwise + */ int libtest_have_custom_free(void); + +/** + * Test whether free_sized(3) has been overridden, + * allowing it to be used for override implementations + * of memory allocation functions + * + * Tools like valgrind(1) prevent resource deallocation + * functions from being overridden as they may override + * such functions themselves as they may override memory + * allocation functions to detect leaks and invalid + * memory access patterns + * + * You don't have to call this function yourself, + * overriden memory allocation function will call it + * and abort the process if this function return 0, + * likewise free_sized(3) will abort the process if + * one of the memory allocation functions, whose + * alloactions it can deallocate, have not been + * overriden + * + * @return 1 if overridden, 0 otherwise + */ int libtest_have_custom_free_sized(void); + +/** + * Test whether free_aligned_sized(3) has been overridden, + * allowing it to be used for override implementations + * of memory allocation functions + * + * Tools like valgrind(1) prevent resource deallocation + * functions from being overridden as they may override + * such functions themselves as they may override memory + * allocation functions to detect leaks and invalid + * memory access patterns + * + * You don't have to call this function yourself, + * overriden memory allocation function will call it + * and abort the process if this function return 0, + * likewise free_aligned_sized(3) will abort the process + * if one of the memory allocation functions, whose + * alloactions it can deallocate, have not been + * overriden + * + * @return 1 if overridden, 0 otherwise + */ int libtest_have_custom_free_aligned_sized(void); -void libtest_dump_stack(const char *indent); + +/** + * Print a stack trace, to standard error, provided + * that backtrace support was enabled at compile-time + * + * @param prefix The text to print at the beginning of the first line + * @param indent The text to print at the beginning of the other lines + * + * If one if `prefix` or `indent` is `NULL`, the other + * will be used as both. Both may not be `NULL` at the + * same time. + */ +void libtest_dump_stack(const char *prefix, const char *indent); + +/** + * Set up a signal handler to print a stack trace when + * a signal is received + * + * This function has no affect if backtrace support + * was disbled at compile-time, and therefore `*old_out` + * is only set if backtrace support was enabled + * + * @param signo The signal to catch + * @param old_out Output parameter for the older signal handler + */ +void libtest_stack_on_signal(int signo, struct sigaction *old_out); + +/** + * Undo `libtest_stack_on_signal` + * + * This function has no affect if backtrace support + * was disbled at compile-time, making it safe, + * unlike sigaction(3), to use to to restore the + * old signal handler returned by `libtest_stack_on_signal` + * when backtrace support is disabled. Additionally, + * this function will deallocate the alternative stack + * set up by `libtest_stack_on_signal` once it has been + * called as many times as `libtest_stack_on_signal`. + * + * @param signo The signal handler to stop catching + * @param old The old signal handler to restore + */ +void libtest_stop_stack_on_signal(int signo, const struct sigaction *old); + + +/** + * Get the number of allocation attempts + * before the next allocation will fail + * (ENOMEM), including that attempt in + * the count + * + * @return 0 if no memory allocation failure is scheduled, + * 1 if the next memory allocation will fail, + * 2 if the attempt after that will fail, + * and so on + */ +#if defined(__GNUC__) +__attribute__((__pure__)) +#endif +size_t libtest_get_alloc_failure_in(void); + +/** + * Get the number of allocation attempts + * before the next allocation will fail + * (ENOMEM), including that attempt in + * the count + * + * @param n 0 if no memory allocation should fail, + * 1 if the next memory allocation shall fail, + * 2 if the attempt after that shall fail, + * and so on + * + * Once the scheduled memory allocation + * failure as occurred, the schedule is + * cleared and the next attempt will be + * successful (provided that there isn't + * a real failure) + */ +void libtest_set_alloc_failure_in(size_t n); diff --git a/libtest/libtest_alloc.c b/libtest/libtest_alloc.c index 5aa3218..dc9cc8f 100644 --- a/libtest/libtest_alloc.c +++ b/libtest/libtest_alloc.c @@ -62,7 +62,7 @@ libtest_alloc(struct meminfo *meminfo) size_t bookkeeping; int saved_errno; #ifdef WITH_BACKTRACE - size_t backtrace_realignment; + size_t backtrace_realignment = 0u; /* initialised to make clang(1) happy */ size_t i, backtrace_n; unw_cursor_t cursor; unw_context_t context; @@ -121,6 +121,12 @@ libtest_alloc(struct meminfo *meminfo) bookkeeping -= meminfo->actual_alignment; /* Allocate memory */ + if (!libtest_malloc_internal_usage) { + if (libtest_malloc_fail_in && !--libtest_malloc_fail_in) { + errno = ENOMEM; + return NULL; + } + } base_ptr = mmap_anon(meminfo->real_alloc_size); if (!base_ptr) return NULL; @@ -152,6 +158,13 @@ libtest_alloc(struct meminfo *meminfo) meminfo->usable_alloc_size = meminfo->real_alloc_size; meminfo->usable_alloc_size -= (size_t)((char *)ret_ptr - (char *)base_ptr); + /* See CEVEATS section in mmap(2) */ + if (meminfo->usable_alloc_size > PTRDIFF_MAX) { + assert(!libtest_real_munmap(base_ptr, meminfo->real_alloc_size)); + errno = ENOMEM; + return NULL; + } + /* Store book-keeping */ meminfo->usable_area = ret_ptr; memcpy(base_ptr, meminfo, sizeof(*meminfo)); @@ -183,7 +196,7 @@ libtest_alloc(struct meminfo *meminfo) libtest_malloc_internal_usage++; fprintf(stderr, "Memory allocated: %p (alloc-size=%zu, real-size=%zu, leak-allowed=%i)\n", ret_ptr, meminfo->requested_alloc_size, meminfo->real_alloc_size, meminfo->accept_leakage); - libtest_print_backtrace(stderr, "\tat ", 0u, NULL); + libtest_print_backtrace(stderr, NULL, "\tat ", 0u, NULL, NULL); fflush(stderr); libtest_malloc_internal_usage--; } diff --git a/libtest/libtest_check_no_leaks.c b/libtest/libtest_check_no_leaks.c index 15f7e58..40e3a80 100644 --- a/libtest/libtest_check_no_leaks.c +++ b/libtest/libtest_check_no_leaks.c @@ -30,7 +30,7 @@ check_no_memory_leaks(void) mem->usable_area, mem->requested_alloc_size); #ifdef WITH_BACKTRACE if (mem->backtrace) - libtest_print_backtrace(stderr, "\tat ", 0u, mem->backtrace); + libtest_print_backtrace(stderr, NULL, "\tat ", 0u, mem->backtrace, NULL); #endif fflush(stderr); } diff --git a/libtest/libtest_dump_stack.c b/libtest/libtest_dump_stack.c index ca0c9c7..030da8c 100644 --- a/libtest/libtest_dump_stack.c +++ b/libtest/libtest_dump_stack.c @@ -10,12 +10,13 @@ CONST #endif void -libtest_dump_stack(const char *indent) +libtest_dump_stack(const char *prefix, const char *indent) { #ifndef WITH_BACKTRACE + (void) prefix; (void) indent; #else - libtest_print_backtrace(stderr, indent, 1u, NULL); + libtest_print_backtrace(stderr, prefix, indent, 1u, NULL, NULL); #endif } diff --git a/libtest/libtest_free.c b/libtest/libtest_free.c index 398994b..3dcd41c 100644 --- a/libtest/libtest_free.c +++ b/libtest/libtest_free.c @@ -24,7 +24,7 @@ libtest_free(void *ptr, enum libtest_zero_check zero_checking) if (!inside_free && getenv("PRETRACE_FREE")) { inside_free = 1; fprintf(stderr, "Deallocating: %p\n", ptr); - libtest_print_backtrace(stderr, "\tat ", 0u, NULL); + libtest_print_backtrace(stderr, NULL, "\tat ", 0u, NULL, NULL); fflush(stderr); inside_free = 0; } @@ -66,7 +66,7 @@ libtest_free(void *ptr, enum libtest_zero_check zero_checking) fprintf(stderr, "Memory deallocated: %p\n (alloc-size=%zu, real-size=%zu)", ptr, mem->requested_alloc_size, mem->real_alloc_size); if (getenv("TRACE_FREE") && !getenv("PRETRACE_FREE")) - libtest_print_backtrace(stderr, "\tat ", 0u, NULL); + libtest_print_backtrace(stderr, NULL, "\tat ", 0u, NULL, NULL); fflush(stderr); inside_free = 0; } diff --git a/libtest/libtest_get_alloc_failure_in.c b/libtest/libtest_get_alloc_failure_in.c new file mode 100644 index 0000000..347c973 --- /dev/null +++ b/libtest/libtest_get_alloc_failure_in.c @@ -0,0 +1,31 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + + +size_t +libtest_get_alloc_failure_in(void) +{ + return libtest_malloc_fail_in; +} + + +#else + + +int +main(void) +{ + EXPECT(libtest_malloc_fail_in == 0u); + EXPECT(libtest_get_alloc_failure_in() == 0u); + EXPECT(libtest_get_alloc_failure_in() == 0u); + EXPECT(libtest_malloc_fail_in == 0u); + libtest_malloc_fail_in = 4u; + EXPECT(libtest_get_alloc_failure_in() == 4u); + EXPECT(libtest_get_alloc_failure_in() == 4u); + EXPECT(libtest_malloc_fail_in == 4u); + return 0; +} + + +#endif diff --git a/libtest/libtest_print_backtrace.c b/libtest/libtest_print_backtrace.c index 8fa0fd5..e595131 100644 --- a/libtest/libtest_print_backtrace.c +++ b/libtest/libtest_print_backtrace.c @@ -9,7 +9,8 @@ void -libtest_print_backtrace(FILE *fp, const char *indent, size_t first, const struct backtrace *backtrace) +libtest_print_backtrace(FILE *fp, const char *prefix, const char *indent, size_t first, + const struct backtrace *backtrace, ucontext_t *ucontext) { static _Thread_local int recursion_guard = 0; int saved_errno; @@ -35,7 +36,21 @@ libtest_print_backtrace(FILE *fp, const char *indent, size_t first, const struct recursion_guard = 1; libtest_malloc_internal_usage++; - if (!backtrace) { + if (!prefix) + prefix = indent; + if (!indent) + indent = prefix; + if (!prefix || !indent) + abort(); + + if (backtrace) { + if (ucontext) { + abort(); + } + } else if (ucontext) { + if (unw_init_local2(&cursor, (unw_context_t *)ucontext, UNW_INIT_SIGNAL_FRAME)) + goto out; + } else { if (unw_getcontext(&context)) goto out; if (unw_init_local(&cursor, &context)) @@ -86,14 +101,15 @@ libtest_print_backtrace(FILE *fp, const char *indent, size_t first, const struct #endif #if defined(HAVE_LINE_INFO) - fprintf(fp, "%s0x%016"PRIxPTR": %s", indent, (uintptr_t)ip, funcname ? funcname : "???"); + fprintf(fp, "%s0x%016"PRIxPTR": %s", prefix, (uintptr_t)ip, funcname ? funcname : "???"); if (line) fprintf(fp, " (%s:%i)\n", filename, lineno); else fprintf(fp, "\n"); #else - fprintf(fp, "%s0x%016"PRIxPTR"\n", indent, (uintptr_t)ip); + fprintf(fp, "%s0x%016"PRIxPTR"\n", prefix, (uintptr_t)ip); #endif + prefix = indent; } #if defined(HAVE_LINE_INFO) diff --git a/libtest/libtest_set_alloc_failure_in.c b/libtest/libtest_set_alloc_failure_in.c new file mode 100644 index 0000000..9811456 --- /dev/null +++ b/libtest/libtest_set_alloc_failure_in.c @@ -0,0 +1,32 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + + +void +libtest_set_alloc_failure_in(size_t n) +{ + libtest_malloc_fail_in = n; +} + + +#else + + +int +main(void) +{ + EXPECT(libtest_malloc_fail_in == 0u); + libtest_set_alloc_failure_in(4u); + EXPECT(libtest_malloc_fail_in == 4u); + libtest_set_alloc_failure_in(4u); + EXPECT(libtest_malloc_fail_in == 4u); + libtest_set_alloc_failure_in(0u); + EXPECT(libtest_malloc_fail_in == 0u); + libtest_set_alloc_failure_in(0u); + EXPECT(libtest_malloc_fail_in == 0u); + return 0; +} + + +#endif diff --git a/libtest/libtest_stack_on_signal.c b/libtest/libtest_stack_on_signal.c new file mode 100644 index 0000000..0f92972 --- /dev/null +++ b/libtest/libtest_stack_on_signal.c @@ -0,0 +1,102 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +# ifdef WITH_BACKTRACE + + +static void +stack_dumper(int sig, siginfo_t *info, void *ucontext) +{ + (void) sig; + (void) info; + libtest_print_backtrace(stderr, "crashed at ", " by ", 0u, NULL, ucontext); +} + + +static stack_t ss; +static size_t have_ss = 0u; + + +static void +create_altstack(void) +{ + if (have_ss++) + return; + ss.ss_sp = libtest_real_mmap(NULL, (size_t)SIGSTKSZ, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(ss.ss_sp != MAP_FAILED); + ss.ss_size = (size_t)SIGSTKSZ; + ss.ss_flags = 0; + assert(!sigaltstack(&ss, NULL)); +} + + +static void +destroy_altstack(void) +{ + if (--have_ss) + return; + assert(!libtest_real_munmap(ss.ss_sp, ss.ss_size)); +} + + +void +libtest_stack_on_signal(int signo, struct sigaction *old_out) +{ + struct sigaction sa; + + create_altstack(); + + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = &stack_dumper; + sa.sa_flags = (int)(SA_RESETHAND | SA_SIGINFO); + if (have_ss) + sa.sa_flags |= SA_ONSTACK; + sigfillset(&sa.sa_mask); + + assert(!sigaction(signo, &sa, old_out)); +} + + +void +libtest_stop_stack_on_signal(int signo, const struct sigaction *old) +{ + assert(!sigaction(signo, old, NULL)); + destroy_altstack(); +} + + +#else + + +void +libtest_stack_on_signal(int signo, struct sigaction *old_out) +{ + (void) signo; + (void) old_out; +} + +void +libtest_stop_stack_on_signal(int signo, const struct sigaction *old) +{ + (void) signo; + (void) old; +} + + +# endif + + +#else + + +CONST int +main(void) +{ + /* How would one even test this, and what would be the point? */ + return 0; +} + + +#endif diff --git a/libtest/mmap.c b/libtest/mmap.c new file mode 100644 index 0000000..c12594f --- /dev/null +++ b/libtest/mmap.c @@ -0,0 +1,72 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +#include <sys/syscall.h> + + +void * +libtest_real_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t off) +{ + size_t pagesize = libtest_get_pagesize(); + + if (off < 0 || off % (off_t)pagesize) + goto einval; + off /= (off_t)pagesize; + +#if defined(__x86_64__) && defined(__ILP32__) /* x32 */ + if (off > LLONG_MAX) + goto einval; +#else + if (off > LONG_MAX) + goto einval; +#endif + +#ifdef SYS_mmap2 + assert(pagesize == 4096u); + return (void *)syscall(SYS_mmap2, addr, len, prot, flags, fd, off); +#else + return (void *)syscall(SYS_mmap, addr, len, prot, flags, fd, off); +#endif + +einval: + errno = EINVAL; + return MAP_FAILED; +} + + +int +libtest_real_munmap(void *addr, size_t len) +{ + return syscall(SYS_munmap, addr, len); +} + + +void * +libtest_real_mremap(void *old_addr, size_t old_len, size_t new_len, int flags, ...) +{ + va_list args; + void *new_addr = NULL; + + if (flags & MREMAP_FIXED) { + va_start(args, flags); + new_addr = va_arg(args, void *); + va_end(args); + } + + return (void *)syscall(SYS_mremap, old_addr, old_len, new_len, flags, new_addr); +} + + +#else + + +CONST int +main(void) +{ + /* TODO maybe test */ + return 0; +} + + +#endif |
