1 #include "test/jemalloc_test.h" 2 3 TEST_BEGIN(test_same_size) 4 { 5 void *p; 6 size_t sz, tsz; 7 8 p = mallocx(42, 0); 9 assert_ptr_not_null(p, "Unexpected mallocx() error"); 10 sz = sallocx(p, 0); 11 12 tsz = xallocx(p, sz, 0, 0); 13 assert_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz); 14 15 dallocx(p, 0); 16 } 17 TEST_END 18 19 TEST_BEGIN(test_extra_no_move) 20 { 21 void *p; 22 size_t sz, tsz; 23 24 p = mallocx(42, 0); 25 assert_ptr_not_null(p, "Unexpected mallocx() error"); 26 sz = sallocx(p, 0); 27 28 tsz = xallocx(p, sz, sz-42, 0); 29 assert_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz); 30 31 dallocx(p, 0); 32 } 33 TEST_END 34 35 TEST_BEGIN(test_no_move_fail) 36 { 37 void *p; 38 size_t sz, tsz; 39 40 p = mallocx(42, 0); 41 assert_ptr_not_null(p, "Unexpected mallocx() error"); 42 sz = sallocx(p, 0); 43 44 tsz = xallocx(p, sz + 5, 0, 0); 45 assert_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz); 46 47 dallocx(p, 0); 48 } 49 TEST_END 50 51 static unsigned 52 get_nsizes_impl(const char *cmd) 53 { 54 unsigned ret; 55 size_t z; 56 57 z = sizeof(unsigned); 58 assert_d_eq(mallctl(cmd, &ret, &z, NULL, 0), 0, 59 "Unexpected mallctl(\"%s\", ...) failure", cmd); 60 61 return (ret); 62 } 63 64 static unsigned 65 get_nsmall(void) 66 { 67 68 return (get_nsizes_impl("arenas.nbins")); 69 } 70 71 static unsigned 72 get_nlarge(void) 73 { 74 75 return (get_nsizes_impl("arenas.nlruns")); 76 } 77 78 static unsigned 79 get_nhuge(void) 80 { 81 82 return (get_nsizes_impl("arenas.nhchunks")); 83 } 84 85 static size_t 86 get_size_impl(const char *cmd, size_t ind) 87 { 88 size_t ret; 89 size_t z; 90 size_t mib[4]; 91 size_t miblen = 4; 92 93 z = sizeof(size_t); 94 assert_d_eq(mallctlnametomib(cmd, mib, &miblen), 95 0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd); 96 mib[2] = ind; 97 z = sizeof(size_t); 98 assert_d_eq(mallctlbymib(mib, miblen, &ret, &z, NULL, 0), 99 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind); 100 101 return (ret); 102 } 103 104 static size_t 105 get_small_size(size_t ind) 106 { 107 108 return (get_size_impl("arenas.bin.0.size", ind)); 109 } 110 111 static size_t 112 get_large_size(size_t ind) 113 { 114 115 return (get_size_impl("arenas.lrun.0.size", ind)); 116 } 117 118 static size_t 119 get_huge_size(size_t ind) 120 { 121 122 return (get_size_impl("arenas.hchunk.0.size", ind)); 123 } 124 125 TEST_BEGIN(test_size) 126 { 127 size_t small0, hugemax; 128 void *p; 129 130 /* Get size classes. */ 131 small0 = get_small_size(0); 132 hugemax = get_huge_size(get_nhuge()-1); 133 134 p = mallocx(small0, 0); 135 assert_ptr_not_null(p, "Unexpected mallocx() error"); 136 137 /* Test smallest supported size. */ 138 assert_zu_eq(xallocx(p, 1, 0, 0), small0, 139 "Unexpected xallocx() behavior"); 140 141 /* Test largest supported size. */ 142 assert_zu_le(xallocx(p, hugemax, 0, 0), hugemax, 143 "Unexpected xallocx() behavior"); 144 145 /* Test size overflow. */ 146 assert_zu_le(xallocx(p, hugemax+1, 0, 0), hugemax, 147 "Unexpected xallocx() behavior"); 148 assert_zu_le(xallocx(p, SIZE_T_MAX, 0, 0), hugemax, 149 "Unexpected xallocx() behavior"); 150 151 dallocx(p, 0); 152 } 153 TEST_END 154 155 TEST_BEGIN(test_size_extra_overflow) 156 { 157 size_t small0, hugemax; 158 void *p; 159 160 /* Get size classes. */ 161 small0 = get_small_size(0); 162 hugemax = get_huge_size(get_nhuge()-1); 163 164 p = mallocx(small0, 0); 165 assert_ptr_not_null(p, "Unexpected mallocx() error"); 166 167 /* Test overflows that can be resolved by clamping extra. */ 168 assert_zu_le(xallocx(p, hugemax-1, 2, 0), hugemax, 169 "Unexpected xallocx() behavior"); 170 assert_zu_le(xallocx(p, hugemax, 1, 0), hugemax, 171 "Unexpected xallocx() behavior"); 172 173 /* Test overflow such that hugemax-size underflows. */ 174 assert_zu_le(xallocx(p, hugemax+1, 2, 0), hugemax, 175 "Unexpected xallocx() behavior"); 176 assert_zu_le(xallocx(p, hugemax+2, 3, 0), hugemax, 177 "Unexpected xallocx() behavior"); 178 assert_zu_le(xallocx(p, SIZE_T_MAX-2, 2, 0), hugemax, 179 "Unexpected xallocx() behavior"); 180 assert_zu_le(xallocx(p, SIZE_T_MAX-1, 1, 0), hugemax, 181 "Unexpected xallocx() behavior"); 182 183 dallocx(p, 0); 184 } 185 TEST_END 186 187 TEST_BEGIN(test_extra_small) 188 { 189 size_t small0, small1, hugemax; 190 void *p; 191 192 /* Get size classes. */ 193 small0 = get_small_size(0); 194 small1 = get_small_size(1); 195 hugemax = get_huge_size(get_nhuge()-1); 196 197 p = mallocx(small0, 0); 198 assert_ptr_not_null(p, "Unexpected mallocx() error"); 199 200 assert_zu_eq(xallocx(p, small1, 0, 0), small0, 201 "Unexpected xallocx() behavior"); 202 203 assert_zu_eq(xallocx(p, small1, 0, 0), small0, 204 "Unexpected xallocx() behavior"); 205 206 assert_zu_eq(xallocx(p, small0, small1 - small0, 0), small0, 207 "Unexpected xallocx() behavior"); 208 209 /* Test size+extra overflow. */ 210 assert_zu_eq(xallocx(p, small0, hugemax - small0 + 1, 0), small0, 211 "Unexpected xallocx() behavior"); 212 assert_zu_eq(xallocx(p, small0, SIZE_T_MAX - small0, 0), small0, 213 "Unexpected xallocx() behavior"); 214 215 dallocx(p, 0); 216 } 217 TEST_END 218 219 TEST_BEGIN(test_extra_large) 220 { 221 size_t smallmax, large0, large1, large2, huge0, hugemax; 222 void *p; 223 224 /* Get size classes. */ 225 smallmax = get_small_size(get_nsmall()-1); 226 large0 = get_large_size(0); 227 large1 = get_large_size(1); 228 large2 = get_large_size(2); 229 huge0 = get_huge_size(0); 230 hugemax = get_huge_size(get_nhuge()-1); 231 232 p = mallocx(large2, 0); 233 assert_ptr_not_null(p, "Unexpected mallocx() error"); 234 235 assert_zu_eq(xallocx(p, large2, 0, 0), large2, 236 "Unexpected xallocx() behavior"); 237 /* Test size decrease with zero extra. */ 238 assert_zu_eq(xallocx(p, large0, 0, 0), large0, 239 "Unexpected xallocx() behavior"); 240 assert_zu_eq(xallocx(p, smallmax, 0, 0), large0, 241 "Unexpected xallocx() behavior"); 242 243 assert_zu_eq(xallocx(p, large2, 0, 0), large2, 244 "Unexpected xallocx() behavior"); 245 /* Test size decrease with non-zero extra. */ 246 assert_zu_eq(xallocx(p, large0, large2 - large0, 0), large2, 247 "Unexpected xallocx() behavior"); 248 assert_zu_eq(xallocx(p, large1, large2 - large1, 0), large2, 249 "Unexpected xallocx() behavior"); 250 assert_zu_eq(xallocx(p, large0, large1 - large0, 0), large1, 251 "Unexpected xallocx() behavior"); 252 assert_zu_eq(xallocx(p, smallmax, large0 - smallmax, 0), large0, 253 "Unexpected xallocx() behavior"); 254 255 assert_zu_eq(xallocx(p, large0, 0, 0), large0, 256 "Unexpected xallocx() behavior"); 257 /* Test size increase with zero extra. */ 258 assert_zu_eq(xallocx(p, large2, 0, 0), large2, 259 "Unexpected xallocx() behavior"); 260 assert_zu_eq(xallocx(p, huge0, 0, 0), large2, 261 "Unexpected xallocx() behavior"); 262 263 assert_zu_eq(xallocx(p, large0, 0, 0), large0, 264 "Unexpected xallocx() behavior"); 265 /* Test size increase with non-zero extra. */ 266 assert_zu_lt(xallocx(p, large0, huge0 - large0, 0), huge0, 267 "Unexpected xallocx() behavior"); 268 269 assert_zu_eq(xallocx(p, large0, 0, 0), large0, 270 "Unexpected xallocx() behavior"); 271 /* Test size increase with non-zero extra. */ 272 assert_zu_eq(xallocx(p, large0, large2 - large0, 0), large2, 273 "Unexpected xallocx() behavior"); 274 275 assert_zu_eq(xallocx(p, large2, 0, 0), large2, 276 "Unexpected xallocx() behavior"); 277 /* Test size+extra overflow. */ 278 assert_zu_lt(xallocx(p, large2, hugemax - large2 + 1, 0), huge0, 279 "Unexpected xallocx() behavior"); 280 281 dallocx(p, 0); 282 } 283 TEST_END 284 285 TEST_BEGIN(test_extra_huge) 286 { 287 size_t largemax, huge0, huge1, huge2, hugemax; 288 void *p; 289 290 /* Get size classes. */ 291 largemax = get_large_size(get_nlarge()-1); 292 huge0 = get_huge_size(0); 293 huge1 = get_huge_size(1); 294 huge2 = get_huge_size(2); 295 hugemax = get_huge_size(get_nhuge()-1); 296 297 p = mallocx(huge2, 0); 298 assert_ptr_not_null(p, "Unexpected mallocx() error"); 299 300 assert_zu_eq(xallocx(p, huge2, 0, 0), huge2, 301 "Unexpected xallocx() behavior"); 302 /* Test size decrease with zero extra. */ 303 assert_zu_ge(xallocx(p, huge0, 0, 0), huge0, 304 "Unexpected xallocx() behavior"); 305 assert_zu_ge(xallocx(p, largemax, 0, 0), huge0, 306 "Unexpected xallocx() behavior"); 307 308 assert_zu_eq(xallocx(p, huge2, 0, 0), huge2, 309 "Unexpected xallocx() behavior"); 310 /* Test size decrease with non-zero extra. */ 311 assert_zu_eq(xallocx(p, huge0, huge2 - huge0, 0), huge2, 312 "Unexpected xallocx() behavior"); 313 assert_zu_eq(xallocx(p, huge1, huge2 - huge1, 0), huge2, 314 "Unexpected xallocx() behavior"); 315 assert_zu_eq(xallocx(p, huge0, huge1 - huge0, 0), huge1, 316 "Unexpected xallocx() behavior"); 317 assert_zu_ge(xallocx(p, largemax, huge0 - largemax, 0), huge0, 318 "Unexpected xallocx() behavior"); 319 320 assert_zu_ge(xallocx(p, huge0, 0, 0), huge0, 321 "Unexpected xallocx() behavior"); 322 /* Test size increase with zero extra. */ 323 assert_zu_le(xallocx(p, huge2, 0, 0), huge2, 324 "Unexpected xallocx() behavior"); 325 assert_zu_le(xallocx(p, hugemax+1, 0, 0), huge2, 326 "Unexpected xallocx() behavior"); 327 328 assert_zu_ge(xallocx(p, huge0, 0, 0), huge0, 329 "Unexpected xallocx() behavior"); 330 /* Test size increase with non-zero extra. */ 331 assert_zu_le(xallocx(p, huge0, SIZE_T_MAX - huge0, 0), hugemax, 332 "Unexpected xallocx() behavior"); 333 334 assert_zu_ge(xallocx(p, huge0, 0, 0), huge0, 335 "Unexpected xallocx() behavior"); 336 /* Test size increase with non-zero extra. */ 337 assert_zu_le(xallocx(p, huge0, huge2 - huge0, 0), huge2, 338 "Unexpected xallocx() behavior"); 339 340 assert_zu_eq(xallocx(p, huge2, 0, 0), huge2, 341 "Unexpected xallocx() behavior"); 342 /* Test size+extra overflow. */ 343 assert_zu_le(xallocx(p, huge2, hugemax - huge2 + 1, 0), hugemax, 344 "Unexpected xallocx() behavior"); 345 346 dallocx(p, 0); 347 } 348 TEST_END 349 350 static void 351 print_filled_extents(const void *p, uint8_t c, size_t len) 352 { 353 const uint8_t *pc = (const uint8_t *)p; 354 size_t i, range0; 355 uint8_t c0; 356 357 malloc_printf(" p=%p, c=%#x, len=%zu:", p, c, len); 358 range0 = 0; 359 c0 = pc[0]; 360 for (i = 0; i < len; i++) { 361 if (pc[i] != c0) { 362 malloc_printf(" %#x[%zu..%zu)", c0, range0, i); 363 range0 = i; 364 c0 = pc[i]; 365 } 366 } 367 malloc_printf(" %#x[%zu..%zu)\n", c0, range0, i); 368 } 369 370 static bool 371 validate_fill(const void *p, uint8_t c, size_t offset, size_t len) 372 { 373 const uint8_t *pc = (const uint8_t *)p; 374 bool err; 375 size_t i; 376 377 for (i = offset, err = false; i < offset+len; i++) { 378 if (pc[i] != c) 379 err = true; 380 } 381 382 if (err) 383 print_filled_extents(p, c, offset + len); 384 385 return (err); 386 } 387 388 static void 389 test_zero(size_t szmin, size_t szmax) 390 { 391 size_t sz, nsz; 392 void *p; 393 #define FILL_BYTE 0x7aU 394 395 sz = szmax; 396 p = mallocx(sz, MALLOCX_ZERO); 397 assert_ptr_not_null(p, "Unexpected mallocx() error"); 398 assert_false(validate_fill(p, 0x00, 0, sz), "Memory not filled: sz=%zu", 399 sz); 400 401 /* 402 * Fill with non-zero so that non-debug builds are more likely to detect 403 * errors. 404 */ 405 memset(p, FILL_BYTE, sz); 406 assert_false(validate_fill(p, FILL_BYTE, 0, sz), 407 "Memory not filled: sz=%zu", sz); 408 409 /* Shrink in place so that we can expect growing in place to succeed. */ 410 sz = szmin; 411 assert_zu_eq(xallocx(p, sz, 0, MALLOCX_ZERO), sz, 412 "Unexpected xallocx() error"); 413 assert_false(validate_fill(p, FILL_BYTE, 0, sz), 414 "Memory not filled: sz=%zu", sz); 415 416 for (sz = szmin; sz < szmax; sz = nsz) { 417 nsz = nallocx(sz+1, MALLOCX_ZERO); 418 assert_zu_eq(xallocx(p, sz+1, 0, MALLOCX_ZERO), nsz, 419 "Unexpected xallocx() failure"); 420 assert_false(validate_fill(p, FILL_BYTE, 0, sz), 421 "Memory not filled: sz=%zu", sz); 422 assert_false(validate_fill(p, 0x00, sz, nsz-sz), 423 "Memory not filled: sz=%zu, nsz-sz=%zu", sz, nsz-sz); 424 memset((void *)((uintptr_t)p + sz), FILL_BYTE, nsz-sz); 425 assert_false(validate_fill(p, FILL_BYTE, 0, nsz), 426 "Memory not filled: nsz=%zu", nsz); 427 } 428 429 dallocx(p, 0); 430 } 431 432 TEST_BEGIN(test_zero_large) 433 { 434 size_t large0, largemax; 435 436 /* Get size classes. */ 437 large0 = get_large_size(0); 438 largemax = get_large_size(get_nlarge()-1); 439 440 test_zero(large0, largemax); 441 } 442 TEST_END 443 444 TEST_BEGIN(test_zero_huge) 445 { 446 size_t huge0, huge1; 447 448 /* Get size classes. */ 449 huge0 = get_huge_size(0); 450 huge1 = get_huge_size(1); 451 452 test_zero(huge1, huge0 * 2); 453 } 454 TEST_END 455 456 int 457 main(void) 458 { 459 460 return (test( 461 test_same_size, 462 test_extra_no_move, 463 test_no_move_fail, 464 test_size, 465 test_size_extra_overflow, 466 test_extra_small, 467 test_extra_large, 468 test_extra_huge, 469 test_zero_large, 470 test_zero_huge)); 471 } 472