smallocx.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. #include "test/jemalloc_test.h"
  2. #include "jemalloc/jemalloc_macros.h"
  3. #define STR_HELPER(x) #x
  4. #define STR(x) STR_HELPER(x)
  5. #ifndef JEMALLOC_VERSION_GID_IDENT
  6. #error "JEMALLOC_VERSION_GID_IDENT not defined"
  7. #endif
  8. #define JOIN(x, y) x ## y
  9. #define JOIN2(x, y) JOIN(x, y)
  10. #define smallocx JOIN2(smallocx_, JEMALLOC_VERSION_GID_IDENT)
  11. typedef struct {
  12. void *ptr;
  13. size_t size;
  14. } smallocx_return_t;
  15. extern smallocx_return_t
  16. smallocx(size_t size, int flags);
  17. static unsigned
  18. get_nsizes_impl(const char *cmd) {
  19. unsigned ret;
  20. size_t z;
  21. z = sizeof(unsigned);
  22. assert_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0,
  23. "Unexpected mallctl(\"%s\", ...) failure", cmd);
  24. return ret;
  25. }
  26. static unsigned
  27. get_nlarge(void) {
  28. return get_nsizes_impl("arenas.nlextents");
  29. }
  30. static size_t
  31. get_size_impl(const char *cmd, size_t ind) {
  32. size_t ret;
  33. size_t z;
  34. size_t mib[4];
  35. size_t miblen = 4;
  36. z = sizeof(size_t);
  37. assert_d_eq(mallctlnametomib(cmd, mib, &miblen),
  38. 0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd);
  39. mib[2] = ind;
  40. z = sizeof(size_t);
  41. assert_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0),
  42. 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind);
  43. return ret;
  44. }
  45. static size_t
  46. get_large_size(size_t ind) {
  47. return get_size_impl("arenas.lextent.0.size", ind);
  48. }
  49. /*
  50. * On systems which can't merge extents, tests that call this function generate
  51. * a lot of dirty memory very quickly. Purging between cycles mitigates
  52. * potential OOM on e.g. 32-bit Windows.
  53. */
  54. static void
  55. purge(void) {
  56. assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
  57. "Unexpected mallctl error");
  58. }
  59. /*
  60. * GCC "-Walloc-size-larger-than" warning detects when one of the memory
  61. * allocation functions is called with a size larger than the maximum size that
  62. * they support. Here we want to explicitly test that the allocation functions
  63. * do indeed fail properly when this is the case, which triggers the warning.
  64. * Therefore we disable the warning for these tests.
  65. */
  66. JEMALLOC_DIAGNOSTIC_PUSH
  67. JEMALLOC_DIAGNOSTIC_IGNORE_ALLOC_SIZE_LARGER_THAN
  68. TEST_BEGIN(test_overflow) {
  69. size_t largemax;
  70. largemax = get_large_size(get_nlarge()-1);
  71. assert_ptr_null(smallocx(largemax+1, 0).ptr,
  72. "Expected OOM for smallocx(size=%#zx, 0)", largemax+1);
  73. assert_ptr_null(smallocx(ZU(PTRDIFF_MAX)+1, 0).ptr,
  74. "Expected OOM for smallocx(size=%#zx, 0)", ZU(PTRDIFF_MAX)+1);
  75. assert_ptr_null(smallocx(SIZE_T_MAX, 0).ptr,
  76. "Expected OOM for smallocx(size=%#zx, 0)", SIZE_T_MAX);
  77. assert_ptr_null(smallocx(1, MALLOCX_ALIGN(ZU(PTRDIFF_MAX)+1)).ptr,
  78. "Expected OOM for smallocx(size=1, MALLOCX_ALIGN(%#zx))",
  79. ZU(PTRDIFF_MAX)+1);
  80. }
  81. TEST_END
  82. static void *
  83. remote_alloc(void *arg) {
  84. unsigned arena;
  85. size_t sz = sizeof(unsigned);
  86. assert_d_eq(mallctl("arenas.create", (void *)&arena, &sz, NULL, 0), 0,
  87. "Unexpected mallctl() failure");
  88. size_t large_sz;
  89. sz = sizeof(size_t);
  90. assert_d_eq(mallctl("arenas.lextent.0.size", (void *)&large_sz, &sz,
  91. NULL, 0), 0, "Unexpected mallctl failure");
  92. smallocx_return_t r
  93. = smallocx(large_sz, MALLOCX_ARENA(arena) | MALLOCX_TCACHE_NONE);
  94. void *ptr = r.ptr;
  95. assert_zu_eq(r.size,
  96. nallocx(large_sz, MALLOCX_ARENA(arena) | MALLOCX_TCACHE_NONE),
  97. "Expected smalloc(size,flags).size == nallocx(size,flags)");
  98. void **ret = (void **)arg;
  99. *ret = ptr;
  100. return NULL;
  101. }
  102. TEST_BEGIN(test_remote_free) {
  103. thd_t thd;
  104. void *ret;
  105. thd_create(&thd, remote_alloc, (void *)&ret);
  106. thd_join(thd, NULL);
  107. assert_ptr_not_null(ret, "Unexpected smallocx failure");
  108. /* Avoid TCACHE_NONE to explicitly test tcache_flush(). */
  109. dallocx(ret, 0);
  110. mallctl("thread.tcache.flush", NULL, NULL, NULL, 0);
  111. }
  112. TEST_END
  113. TEST_BEGIN(test_oom) {
  114. size_t largemax;
  115. bool oom;
  116. void *ptrs[3];
  117. unsigned i;
  118. /*
  119. * It should be impossible to allocate three objects that each consume
  120. * nearly half the virtual address space.
  121. */
  122. largemax = get_large_size(get_nlarge()-1);
  123. oom = false;
  124. for (i = 0; i < sizeof(ptrs) / sizeof(void *); i++) {
  125. ptrs[i] = smallocx(largemax, 0).ptr;
  126. if (ptrs[i] == NULL) {
  127. oom = true;
  128. }
  129. }
  130. assert_true(oom,
  131. "Expected OOM during series of calls to smallocx(size=%zu, 0)",
  132. largemax);
  133. for (i = 0; i < sizeof(ptrs) / sizeof(void *); i++) {
  134. if (ptrs[i] != NULL) {
  135. dallocx(ptrs[i], 0);
  136. }
  137. }
  138. purge();
  139. #if LG_SIZEOF_PTR == 3
  140. assert_ptr_null(smallocx(0x8000000000000000ULL,
  141. MALLOCX_ALIGN(0x8000000000000000ULL)).ptr,
  142. "Expected OOM for smallocx()");
  143. assert_ptr_null(smallocx(0x8000000000000000ULL,
  144. MALLOCX_ALIGN(0x80000000)).ptr,
  145. "Expected OOM for smallocx()");
  146. #else
  147. assert_ptr_null(smallocx(0x80000000UL, MALLOCX_ALIGN(0x80000000UL)).ptr,
  148. "Expected OOM for smallocx()");
  149. #endif
  150. }
  151. TEST_END
  152. /* Re-enable the "-Walloc-size-larger-than=" warning */
  153. JEMALLOC_DIAGNOSTIC_POP
  154. TEST_BEGIN(test_basic) {
  155. #define MAXSZ (((size_t)1) << 23)
  156. size_t sz;
  157. for (sz = 1; sz < MAXSZ; sz = nallocx(sz, 0) + 1) {
  158. smallocx_return_t ret;
  159. size_t nsz, rsz, smz;
  160. void *p;
  161. nsz = nallocx(sz, 0);
  162. assert_zu_ne(nsz, 0, "Unexpected nallocx() error");
  163. ret = smallocx(sz, 0);
  164. p = ret.ptr;
  165. smz = ret.size;
  166. assert_ptr_not_null(p,
  167. "Unexpected smallocx(size=%zx, flags=0) error", sz);
  168. rsz = sallocx(p, 0);
  169. assert_zu_ge(rsz, sz, "Real size smaller than expected");
  170. assert_zu_eq(nsz, rsz, "nallocx()/sallocx() size mismatch");
  171. assert_zu_eq(nsz, smz, "nallocx()/smallocx() size mismatch");
  172. dallocx(p, 0);
  173. ret = smallocx(sz, 0);
  174. p = ret.ptr;
  175. smz = ret.size;
  176. assert_ptr_not_null(p,
  177. "Unexpected smallocx(size=%zx, flags=0) error", sz);
  178. dallocx(p, 0);
  179. nsz = nallocx(sz, MALLOCX_ZERO);
  180. assert_zu_ne(nsz, 0, "Unexpected nallocx() error");
  181. assert_zu_ne(smz, 0, "Unexpected smallocx() error");
  182. ret = smallocx(sz, MALLOCX_ZERO);
  183. p = ret.ptr;
  184. assert_ptr_not_null(p,
  185. "Unexpected smallocx(size=%zx, flags=MALLOCX_ZERO) error",
  186. nsz);
  187. rsz = sallocx(p, 0);
  188. assert_zu_eq(nsz, rsz, "nallocx()/sallocx() rsize mismatch");
  189. assert_zu_eq(nsz, smz, "nallocx()/smallocx() size mismatch");
  190. dallocx(p, 0);
  191. purge();
  192. }
  193. #undef MAXSZ
  194. }
  195. TEST_END
  196. TEST_BEGIN(test_alignment_and_size) {
  197. const char *percpu_arena;
  198. size_t sz = sizeof(percpu_arena);
  199. if(mallctl("opt.percpu_arena", (void *)&percpu_arena, &sz, NULL, 0) ||
  200. strcmp(percpu_arena, "disabled") != 0) {
  201. test_skip("test_alignment_and_size skipped: "
  202. "not working with percpu arena.");
  203. };
  204. #define MAXALIGN (((size_t)1) << 23)
  205. #define NITER 4
  206. size_t nsz, rsz, smz, alignment, total;
  207. unsigned i;
  208. void *ps[NITER];
  209. for (i = 0; i < NITER; i++) {
  210. ps[i] = NULL;
  211. }
  212. for (alignment = 8;
  213. alignment <= MAXALIGN;
  214. alignment <<= 1) {
  215. total = 0;
  216. for (sz = 1;
  217. sz < 3 * alignment && sz < (1U << 31);
  218. sz += (alignment >> (LG_SIZEOF_PTR-1)) - 1) {
  219. for (i = 0; i < NITER; i++) {
  220. nsz = nallocx(sz, MALLOCX_ALIGN(alignment) |
  221. MALLOCX_ZERO);
  222. assert_zu_ne(nsz, 0,
  223. "nallocx() error for alignment=%zu, "
  224. "size=%zu (%#zx)", alignment, sz, sz);
  225. smallocx_return_t ret
  226. = smallocx(sz, MALLOCX_ALIGN(alignment) | MALLOCX_ZERO);
  227. ps[i] = ret.ptr;
  228. assert_ptr_not_null(ps[i],
  229. "smallocx() error for alignment=%zu, "
  230. "size=%zu (%#zx)", alignment, sz, sz);
  231. rsz = sallocx(ps[i], 0);
  232. smz = ret.size;
  233. assert_zu_ge(rsz, sz,
  234. "Real size smaller than expected for "
  235. "alignment=%zu, size=%zu", alignment, sz);
  236. assert_zu_eq(nsz, rsz,
  237. "nallocx()/sallocx() size mismatch for "
  238. "alignment=%zu, size=%zu", alignment, sz);
  239. assert_zu_eq(nsz, smz,
  240. "nallocx()/smallocx() size mismatch for "
  241. "alignment=%zu, size=%zu", alignment, sz);
  242. assert_ptr_null(
  243. (void *)((uintptr_t)ps[i] & (alignment-1)),
  244. "%p inadequately aligned for"
  245. " alignment=%zu, size=%zu", ps[i],
  246. alignment, sz);
  247. total += rsz;
  248. if (total >= (MAXALIGN << 1)) {
  249. break;
  250. }
  251. }
  252. for (i = 0; i < NITER; i++) {
  253. if (ps[i] != NULL) {
  254. dallocx(ps[i], 0);
  255. ps[i] = NULL;
  256. }
  257. }
  258. }
  259. purge();
  260. }
  261. #undef MAXALIGN
  262. #undef NITER
  263. }
  264. TEST_END
  265. int
  266. main(void) {
  267. return test(
  268. test_overflow,
  269. test_oom,
  270. test_remote_free,
  271. test_basic,
  272. test_alignment_and_size);
  273. }