2
0

xallocx.c 9.8 KB

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