123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- #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);
- }
|