diff options
Diffstat (limited to 'deps/jemalloc/test/unit/junk.c')
-rw-r--r-- | deps/jemalloc/test/unit/junk.c | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/deps/jemalloc/test/unit/junk.c b/deps/jemalloc/test/unit/junk.c new file mode 100644 index 0000000..543092f --- /dev/null +++ b/deps/jemalloc/test/unit/junk.c @@ -0,0 +1,195 @@ +#include "test/jemalloc_test.h" + +#define arraylen(arr) (sizeof(arr)/sizeof(arr[0])) +static size_t ptr_ind; +static void *volatile ptrs[100]; +static void *last_junked_ptr; +static size_t last_junked_usize; + +static void +reset() { + ptr_ind = 0; + last_junked_ptr = NULL; + last_junked_usize = 0; +} + +static void +test_junk(void *ptr, size_t usize) { + last_junked_ptr = ptr; + last_junked_usize = usize; +} + +static void +do_allocs(size_t size, bool zero, size_t lg_align) { +#define JUNK_ALLOC(...) \ + do { \ + assert(ptr_ind + 1 < arraylen(ptrs)); \ + void *ptr = __VA_ARGS__; \ + assert_ptr_not_null(ptr, ""); \ + ptrs[ptr_ind++] = ptr; \ + if (opt_junk_alloc && !zero) { \ + expect_ptr_eq(ptr, last_junked_ptr, ""); \ + expect_zu_eq(last_junked_usize, \ + TEST_MALLOC_SIZE(ptr), ""); \ + } \ + } while (0) + if (!zero && lg_align == 0) { + JUNK_ALLOC(malloc(size)); + } + if (!zero) { + JUNK_ALLOC(aligned_alloc(1 << lg_align, size)); + } +#ifdef JEMALLOC_OVERRIDE_MEMALIGN + if (!zero) { + JUNK_ALLOC(je_memalign(1 << lg_align, size)); + } +#endif +#ifdef JEMALLOC_OVERRIDE_VALLOC + if (!zero && lg_align == LG_PAGE) { + JUNK_ALLOC(je_valloc(size)); + } +#endif + int zero_flag = zero ? MALLOCX_ZERO : 0; + JUNK_ALLOC(mallocx(size, zero_flag | MALLOCX_LG_ALIGN(lg_align))); + JUNK_ALLOC(mallocx(size, zero_flag | MALLOCX_LG_ALIGN(lg_align) + | MALLOCX_TCACHE_NONE)); + if (lg_align >= LG_SIZEOF_PTR) { + void *memalign_result; + int err = posix_memalign(&memalign_result, (1 << lg_align), + size); + assert_d_eq(err, 0, ""); + JUNK_ALLOC(memalign_result); + } +} + +TEST_BEGIN(test_junk_alloc_free) { + bool zerovals[] = {false, true}; + size_t sizevals[] = { + 1, 8, 100, 1000, 100*1000 + /* + * Memory allocation failure is a real possibility in 32-bit mode. + * Rather than try to check in the face of resource exhaustion, we just + * rely more on the 64-bit tests. This is a little bit white-box-y in + * the sense that this is only a good test strategy if we know that the + * junk pathways don't touch interact with the allocation selection + * mechanisms; but this is in fact the case. + */ +#if LG_SIZEOF_PTR == 3 + , 10 * 1000 * 1000 +#endif + }; + size_t lg_alignvals[] = { + 0, 4, 10, 15, 16, LG_PAGE +#if LG_SIZEOF_PTR == 3 + , 20, 24 +#endif + }; + +#define JUNK_FREE(...) \ + do { \ + do_allocs(size, zero, lg_align); \ + for (size_t n = 0; n < ptr_ind; n++) { \ + void *ptr = ptrs[n]; \ + __VA_ARGS__; \ + if (opt_junk_free) { \ + assert_ptr_eq(ptr, last_junked_ptr, \ + ""); \ + assert_zu_eq(usize, last_junked_usize, \ + ""); \ + } \ + reset(); \ + } \ + } while (0) + for (size_t i = 0; i < arraylen(zerovals); i++) { + for (size_t j = 0; j < arraylen(sizevals); j++) { + for (size_t k = 0; k < arraylen(lg_alignvals); k++) { + bool zero = zerovals[i]; + size_t size = sizevals[j]; + size_t lg_align = lg_alignvals[k]; + size_t usize = nallocx(size, + MALLOCX_LG_ALIGN(lg_align)); + + JUNK_FREE(free(ptr)); + JUNK_FREE(dallocx(ptr, 0)); + JUNK_FREE(dallocx(ptr, MALLOCX_TCACHE_NONE)); + JUNK_FREE(dallocx(ptr, MALLOCX_LG_ALIGN( + lg_align))); + JUNK_FREE(sdallocx(ptr, usize, MALLOCX_LG_ALIGN( + lg_align))); + JUNK_FREE(sdallocx(ptr, usize, + MALLOCX_TCACHE_NONE | MALLOCX_LG_ALIGN(lg_align))); + if (opt_zero_realloc_action + == zero_realloc_action_free) { + JUNK_FREE(realloc(ptr, 0)); + } + } + } + } +} +TEST_END + +TEST_BEGIN(test_realloc_expand) { + char *volatile ptr; + char *volatile expanded; + + test_skip_if(!opt_junk_alloc); + + /* Realloc */ + ptr = malloc(SC_SMALL_MAXCLASS); + expanded = realloc(ptr, SC_LARGE_MINCLASS); + expect_ptr_eq(last_junked_ptr, &expanded[SC_SMALL_MAXCLASS], ""); + expect_zu_eq(last_junked_usize, + SC_LARGE_MINCLASS - SC_SMALL_MAXCLASS, ""); + free(expanded); + + /* rallocx(..., 0) */ + ptr = malloc(SC_SMALL_MAXCLASS); + expanded = rallocx(ptr, SC_LARGE_MINCLASS, 0); + expect_ptr_eq(last_junked_ptr, &expanded[SC_SMALL_MAXCLASS], ""); + expect_zu_eq(last_junked_usize, + SC_LARGE_MINCLASS - SC_SMALL_MAXCLASS, ""); + free(expanded); + + /* rallocx(..., nonzero) */ + ptr = malloc(SC_SMALL_MAXCLASS); + expanded = rallocx(ptr, SC_LARGE_MINCLASS, MALLOCX_TCACHE_NONE); + expect_ptr_eq(last_junked_ptr, &expanded[SC_SMALL_MAXCLASS], ""); + expect_zu_eq(last_junked_usize, + SC_LARGE_MINCLASS - SC_SMALL_MAXCLASS, ""); + free(expanded); + + /* rallocx(..., MALLOCX_ZERO) */ + ptr = malloc(SC_SMALL_MAXCLASS); + last_junked_ptr = (void *)-1; + last_junked_usize = (size_t)-1; + expanded = rallocx(ptr, SC_LARGE_MINCLASS, MALLOCX_ZERO); + expect_ptr_eq(last_junked_ptr, (void *)-1, ""); + expect_zu_eq(last_junked_usize, (size_t)-1, ""); + free(expanded); + + /* + * Unfortunately, testing xallocx reliably is difficult to do portably + * (since allocations can be expanded / not expanded differently on + * different platforms. We rely on manual inspection there -- the + * xallocx pathway is easy to inspect, though. + * + * Likewise, we don't test the shrinking pathways. It's difficult to do + * so consistently (because of the risk of split failure or memory + * exhaustion, in which case no junking should happen). This is fine + * -- junking is a best-effort debug mechanism in the first place. + */ +} +TEST_END + +int +main(void) { + junk_alloc_callback = &test_junk; + junk_free_callback = &test_junk; + /* + * We check the last pointer junked. If a reentrant call happens, that + * might be an internal allocation. + */ + return test_no_reentrancy( + test_junk_alloc_free, + test_realloc_expand); +} |