Home | History | Annotate | Download | only in unit
      1 #include "test/jemalloc_test.h"
      2 
      3 #ifdef JEMALLOC_FILL
      4 const char *malloc_conf =
      5     "abort:false,junk:true,zero:false,redzone:true,quarantine:0";
      6 #endif
      7 
      8 static arena_dalloc_junk_small_t *arena_dalloc_junk_small_orig;
      9 static arena_dalloc_junk_large_t *arena_dalloc_junk_large_orig;
     10 static huge_dalloc_junk_t *huge_dalloc_junk_orig;
     11 static void *most_recently_junked;
     12 
     13 static void
     14 arena_dalloc_junk_small_intercept(void *ptr, arena_bin_info_t *bin_info)
     15 {
     16 	size_t i;
     17 
     18 	arena_dalloc_junk_small_orig(ptr, bin_info);
     19 	for (i = 0; i < bin_info->reg_size; i++) {
     20 		assert_c_eq(((char *)ptr)[i], 0x5a,
     21 		    "Missing junk fill for byte %zu/%zu of deallocated region",
     22 		    i, bin_info->reg_size);
     23 	}
     24 	most_recently_junked = ptr;
     25 }
     26 
     27 static void
     28 arena_dalloc_junk_large_intercept(void *ptr, size_t usize)
     29 {
     30 	size_t i;
     31 
     32 	arena_dalloc_junk_large_orig(ptr, usize);
     33 	for (i = 0; i < usize; i++) {
     34 		assert_c_eq(((char *)ptr)[i], 0x5a,
     35 		    "Missing junk fill for byte %zu/%zu of deallocated region",
     36 		    i, usize);
     37 	}
     38 	most_recently_junked = ptr;
     39 }
     40 
     41 static void
     42 huge_dalloc_junk_intercept(void *ptr, size_t usize)
     43 {
     44 
     45 	huge_dalloc_junk_orig(ptr, usize);
     46 	/*
     47 	 * The conditions under which junk filling actually occurs are nuanced
     48 	 * enough that it doesn't make sense to duplicate the decision logic in
     49 	 * test code, so don't actually check that the region is junk-filled.
     50 	 */
     51 	most_recently_junked = ptr;
     52 }
     53 
     54 static void
     55 test_junk(size_t sz_min, size_t sz_max)
     56 {
     57 	char *s;
     58 	size_t sz_prev, sz, i;
     59 
     60 	arena_dalloc_junk_small_orig = arena_dalloc_junk_small;
     61 	arena_dalloc_junk_small = arena_dalloc_junk_small_intercept;
     62 	arena_dalloc_junk_large_orig = arena_dalloc_junk_large;
     63 	arena_dalloc_junk_large = arena_dalloc_junk_large_intercept;
     64 	huge_dalloc_junk_orig = huge_dalloc_junk;
     65 	huge_dalloc_junk = huge_dalloc_junk_intercept;
     66 
     67 	sz_prev = 0;
     68 	s = (char *)mallocx(sz_min, 0);
     69 	assert_ptr_not_null((void *)s, "Unexpected mallocx() failure");
     70 
     71 	for (sz = sallocx(s, 0); sz <= sz_max;
     72 	    sz_prev = sz, sz = sallocx(s, 0)) {
     73 		if (sz_prev > 0) {
     74 			assert_c_eq(s[0], 'a',
     75 			    "Previously allocated byte %zu/%zu is corrupted",
     76 			    ZU(0), sz_prev);
     77 			assert_c_eq(s[sz_prev-1], 'a',
     78 			    "Previously allocated byte %zu/%zu is corrupted",
     79 			    sz_prev-1, sz_prev);
     80 		}
     81 
     82 		for (i = sz_prev; i < sz; i++) {
     83 			assert_c_eq(s[i], 0xa5,
     84 			    "Newly allocated byte %zu/%zu isn't junk-filled",
     85 			    i, sz);
     86 			s[i] = 'a';
     87 		}
     88 
     89 		if (xallocx(s, sz+1, 0, 0) == sz) {
     90 			void *junked = (void *)s;
     91 
     92 			s = (char *)rallocx(s, sz+1, 0);
     93 			assert_ptr_not_null((void *)s,
     94 			    "Unexpected rallocx() failure");
     95 			assert_ptr_eq(most_recently_junked, junked,
     96 			    "Expected region of size %zu to be junk-filled",
     97 			    sz);
     98 		}
     99 	}
    100 
    101 	dallocx(s, 0);
    102 	assert_ptr_eq(most_recently_junked, (void *)s,
    103 	    "Expected region of size %zu to be junk-filled", sz);
    104 
    105 	arena_dalloc_junk_small = arena_dalloc_junk_small_orig;
    106 	arena_dalloc_junk_large = arena_dalloc_junk_large_orig;
    107 	huge_dalloc_junk = huge_dalloc_junk_orig;
    108 }
    109 
    110 TEST_BEGIN(test_junk_small)
    111 {
    112 
    113 	test_skip_if(!config_fill);
    114 	test_junk(1, SMALL_MAXCLASS-1);
    115 }
    116 TEST_END
    117 
    118 TEST_BEGIN(test_junk_large)
    119 {
    120 
    121 	test_skip_if(!config_fill);
    122 	test_junk(SMALL_MAXCLASS+1, arena_maxclass);
    123 }
    124 TEST_END
    125 
    126 TEST_BEGIN(test_junk_huge)
    127 {
    128 
    129 	test_skip_if(!config_fill);
    130 	test_junk(arena_maxclass+1, chunksize*2);
    131 }
    132 TEST_END
    133 
    134 arena_ralloc_junk_large_t *arena_ralloc_junk_large_orig;
    135 static void *most_recently_trimmed;
    136 
    137 static void
    138 arena_ralloc_junk_large_intercept(void *ptr, size_t old_usize, size_t usize)
    139 {
    140 
    141 	arena_ralloc_junk_large_orig(ptr, old_usize, usize);
    142 	assert_zu_eq(old_usize, arena_maxclass, "Unexpected old_usize");
    143 	assert_zu_eq(usize, arena_maxclass-PAGE, "Unexpected usize");
    144 	most_recently_trimmed = ptr;
    145 }
    146 
    147 TEST_BEGIN(test_junk_large_ralloc_shrink)
    148 {
    149 	void *p1, *p2;
    150 
    151 	p1 = mallocx(arena_maxclass, 0);
    152 	assert_ptr_not_null(p1, "Unexpected mallocx() failure");
    153 
    154 	arena_ralloc_junk_large_orig = arena_ralloc_junk_large;
    155 	arena_ralloc_junk_large = arena_ralloc_junk_large_intercept;
    156 
    157 	p2 = rallocx(p1, arena_maxclass-PAGE, 0);
    158 	assert_ptr_eq(p1, p2, "Unexpected move during shrink");
    159 
    160 	arena_ralloc_junk_large = arena_ralloc_junk_large_orig;
    161 
    162 	assert_ptr_eq(most_recently_trimmed, p1,
    163 	    "Expected trimmed portion of region to be junk-filled");
    164 }
    165 TEST_END
    166 
    167 static bool detected_redzone_corruption;
    168 
    169 static void
    170 arena_redzone_corruption_replacement(void *ptr, size_t usize, bool after,
    171     size_t offset, uint8_t byte)
    172 {
    173 
    174 	detected_redzone_corruption = true;
    175 }
    176 
    177 TEST_BEGIN(test_junk_redzone)
    178 {
    179 	char *s;
    180 	arena_redzone_corruption_t *arena_redzone_corruption_orig;
    181 
    182 	test_skip_if(!config_fill);
    183 
    184 	arena_redzone_corruption_orig = arena_redzone_corruption;
    185 	arena_redzone_corruption = arena_redzone_corruption_replacement;
    186 
    187 	/* Test underflow. */
    188 	detected_redzone_corruption = false;
    189 	s = (char *)mallocx(1, 0);
    190 	assert_ptr_not_null((void *)s, "Unexpected mallocx() failure");
    191 	s[-1] = 0xbb;
    192 	dallocx(s, 0);
    193 	assert_true(detected_redzone_corruption,
    194 	    "Did not detect redzone corruption");
    195 
    196 	/* Test overflow. */
    197 	detected_redzone_corruption = false;
    198 	s = (char *)mallocx(1, 0);
    199 	assert_ptr_not_null((void *)s, "Unexpected mallocx() failure");
    200 	s[sallocx(s, 0)] = 0xbb;
    201 	dallocx(s, 0);
    202 	assert_true(detected_redzone_corruption,
    203 	    "Did not detect redzone corruption");
    204 
    205 	arena_redzone_corruption = arena_redzone_corruption_orig;
    206 }
    207 TEST_END
    208 
    209 int
    210 main(void)
    211 {
    212 
    213 	return (test(
    214 	    test_junk_small,
    215 	    test_junk_large,
    216 	    test_junk_huge,
    217 	    test_junk_large_ralloc_shrink,
    218 	    test_junk_redzone));
    219 }
    220