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