/memory/jemalloc/src/test/integration/xallocx.c

https://github.com/rillian/firefox · C · 497 lines · 367 code · 95 blank · 35 comment · 10 complexity · aa2a8d6cfde580b454a4e45dfdd9fa46 MD5 · raw file

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