mem_alloc_test.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include <stdint.h>
  6. #include <string.h>
  7. #include <cmocka.h>
  8. #if WAMR_BUILD_TEST != 1
  9. #error "WAMR_BUILD_TEST must be defined as 1"
  10. #endif
  11. #include "mem_alloc.h"
  12. #include "ems_gc_internal.h"
  13. #include "wasm_export.h"
  14. /* Test helper: Check if pointer is aligned */
  15. static inline bool
  16. is_aligned(void *ptr, size_t alignment)
  17. {
  18. return ((uintptr_t)ptr % alignment) == 0;
  19. }
  20. /* Test helper: Check if allocation is aligned (has magic value) */
  21. static inline bool
  22. is_aligned_allocation(gc_object_t obj)
  23. {
  24. uint32_t *magic_ptr = (uint32_t *)((char *)obj - 4);
  25. return ((*magic_ptr & ALIGNED_ALLOC_MAGIC_MASK)
  26. == ALIGNED_ALLOC_MAGIC_VALUE);
  27. }
  28. /* Test: Normal allocation still works (regression) */
  29. static void
  30. test_normal_alloc_basic(void **state)
  31. {
  32. mem_allocator_t allocator;
  33. char heap_buf[64 * 1024];
  34. void *ptr;
  35. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  36. assert_non_null(allocator);
  37. /* Normal allocation should still work */
  38. ptr = mem_allocator_malloc(allocator, 128);
  39. assert_non_null(ptr);
  40. /* Should be 8-byte aligned */
  41. assert_true(is_aligned(ptr, 8));
  42. /* Should NOT be marked as aligned allocation */
  43. assert_false(is_aligned_allocation(ptr));
  44. /* Free should work */
  45. mem_allocator_free(allocator, ptr);
  46. mem_allocator_destroy(allocator);
  47. }
  48. /* Test: Valid alignment powers of 2 */
  49. static void
  50. test_aligned_alloc_valid_alignments(void **state)
  51. {
  52. mem_allocator_t allocator;
  53. char heap_buf[128 * 1024];
  54. void *ptr;
  55. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  56. assert_non_null(allocator);
  57. /* Test each valid alignment */
  58. int alignments[] = { 8, 16, 32, 64, 128, 256, 512, 1024 };
  59. int num_alignments = sizeof(alignments) / sizeof(alignments[0]);
  60. for (int i = 0; i < num_alignments; i++) {
  61. int align = alignments[i];
  62. /* Allocate with size = multiple of alignment */
  63. ptr = mem_allocator_malloc_aligned(allocator, align * 2, align);
  64. assert_non_null(ptr);
  65. /* Verify alignment */
  66. assert_true(is_aligned(ptr, align));
  67. /* Verify marked as aligned */
  68. assert_true(is_aligned_allocation(ptr));
  69. /* Free */
  70. mem_allocator_free(allocator, ptr);
  71. }
  72. mem_allocator_destroy(allocator);
  73. }
  74. /* Test: Realloc rejects aligned allocations */
  75. static void
  76. test_realloc_rejects_aligned(void **state)
  77. {
  78. mem_allocator_t allocator;
  79. char heap_buf[64 * 1024];
  80. void *ptr, *new_ptr;
  81. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  82. assert_non_null(allocator);
  83. /* Allocate aligned */
  84. ptr = mem_allocator_malloc_aligned(allocator, 128, 64);
  85. assert_non_null(ptr);
  86. assert_true(is_aligned_allocation(ptr));
  87. /* Realloc should reject aligned allocation */
  88. new_ptr = mem_allocator_realloc(allocator, ptr, 256);
  89. assert_null(new_ptr);
  90. /* Original pointer should still be valid - free it */
  91. mem_allocator_free(allocator, ptr);
  92. mem_allocator_destroy(allocator);
  93. }
  94. /* Test: Realloc still works for normal allocations */
  95. static void
  96. test_normal_realloc_works(void **state)
  97. {
  98. mem_allocator_t allocator;
  99. char heap_buf[64 * 1024];
  100. void *ptr, *new_ptr;
  101. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  102. assert_non_null(allocator);
  103. /* Allocate normal */
  104. ptr = mem_allocator_malloc(allocator, 128);
  105. assert_non_null(ptr);
  106. /* Write some data */
  107. memset(ptr, 0xAB, 128);
  108. /* Realloc should work */
  109. new_ptr = mem_allocator_realloc(allocator, ptr, 256);
  110. assert_non_null(new_ptr);
  111. /* Data should be preserved */
  112. for (int i = 0; i < 128; i++) {
  113. assert_int_equal(((unsigned char *)new_ptr)[i], 0xAB);
  114. }
  115. mem_allocator_free(allocator, new_ptr);
  116. mem_allocator_destroy(allocator);
  117. }
  118. /* Test: Invalid alignments (not power of 2 or zero) */
  119. static void
  120. test_aligned_alloc_invalid_not_power_of_2(void **state)
  121. {
  122. mem_allocator_t allocator;
  123. char heap_buf[64 * 1024];
  124. void *ptr;
  125. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  126. assert_non_null(allocator);
  127. /* These should all fail (zero or not power of 2) */
  128. int invalid_alignments[] = { 0, 3, 5, 7, 9, 15, 17, 100 };
  129. int num_invalid =
  130. sizeof(invalid_alignments) / sizeof(invalid_alignments[0]);
  131. for (int i = 0; i < num_invalid; i++) {
  132. ptr =
  133. mem_allocator_malloc_aligned(allocator, 128, invalid_alignments[i]);
  134. assert_null(ptr);
  135. }
  136. /* Small powers of 2 should succeed (adjusted to GC_MIN_ALIGNMENT) */
  137. ptr = mem_allocator_malloc_aligned(allocator, 8, 1);
  138. assert_non_null(ptr);
  139. mem_allocator_free(allocator, ptr);
  140. ptr = mem_allocator_malloc_aligned(allocator, 8, 2);
  141. assert_non_null(ptr);
  142. mem_allocator_free(allocator, ptr);
  143. ptr = mem_allocator_malloc_aligned(allocator, 8, 4);
  144. assert_non_null(ptr);
  145. mem_allocator_free(allocator, ptr);
  146. mem_allocator_destroy(allocator);
  147. }
  148. /* Test: Size must be multiple of alignment */
  149. static void
  150. test_aligned_alloc_size_not_multiple(void **state)
  151. {
  152. mem_allocator_t allocator;
  153. char heap_buf[64 * 1024];
  154. void *ptr;
  155. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  156. assert_non_null(allocator);
  157. /* Size not multiple of alignment - should fail */
  158. ptr = mem_allocator_malloc_aligned(allocator, 100, 64);
  159. assert_null(ptr);
  160. ptr = mem_allocator_malloc_aligned(allocator, 65, 64);
  161. assert_null(ptr);
  162. /* Size is multiple - should succeed */
  163. ptr = mem_allocator_malloc_aligned(allocator, 128, 64);
  164. assert_non_null(ptr);
  165. mem_allocator_free(allocator, ptr);
  166. mem_allocator_destroy(allocator);
  167. }
  168. /* Test: Mixed normal and aligned allocations */
  169. static void
  170. test_mixed_alloc_interleaved(void **state)
  171. {
  172. mem_allocator_t allocator;
  173. char heap_buf[128 * 1024];
  174. void *normal1, *aligned1, *normal2, *aligned2;
  175. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  176. assert_non_null(allocator);
  177. /* Allocate: normal -> aligned -> normal -> aligned */
  178. normal1 = mem_allocator_malloc(allocator, 64);
  179. assert_non_null(normal1);
  180. assert_false(is_aligned_allocation(normal1));
  181. aligned1 = mem_allocator_malloc_aligned(allocator, 128, 64);
  182. assert_non_null(aligned1);
  183. assert_true(is_aligned_allocation(aligned1));
  184. assert_true(is_aligned(aligned1, 64));
  185. normal2 = mem_allocator_malloc(allocator, 96);
  186. assert_non_null(normal2);
  187. assert_false(is_aligned_allocation(normal2));
  188. aligned2 = mem_allocator_malloc_aligned(allocator, 256, 128);
  189. assert_non_null(aligned2);
  190. assert_true(is_aligned_allocation(aligned2));
  191. assert_true(is_aligned(aligned2, 128));
  192. /* Free in mixed order */
  193. mem_allocator_free(allocator, normal1);
  194. mem_allocator_free(allocator, aligned2);
  195. mem_allocator_free(allocator, normal2);
  196. mem_allocator_free(allocator, aligned1);
  197. mem_allocator_destroy(allocator);
  198. }
  199. /* Test: obj_to_hmu works correctly for both types */
  200. static void
  201. test_mixed_obj_to_hmu(void **state)
  202. {
  203. mem_allocator_t allocator;
  204. char heap_buf[64 * 1024];
  205. void *normal, *aligned;
  206. hmu_t *hmu_normal, *hmu_aligned;
  207. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  208. assert_non_null(allocator);
  209. /* Allocate both types */
  210. normal = mem_allocator_malloc(allocator, 128);
  211. assert_non_null(normal);
  212. aligned = mem_allocator_malloc_aligned(allocator, 128, 64);
  213. assert_non_null(aligned);
  214. /* Get HMU pointers */
  215. hmu_normal = obj_to_hmu(normal);
  216. hmu_aligned = obj_to_hmu(aligned);
  217. assert_non_null(hmu_normal);
  218. assert_non_null(hmu_aligned);
  219. /* Both should have HMU_VO type */
  220. assert_int_equal(hmu_get_ut(hmu_normal), HMU_VO);
  221. assert_int_equal(hmu_get_ut(hmu_aligned), HMU_VO);
  222. /* Sizes should be reasonable */
  223. assert_true(hmu_get_size(hmu_normal) >= 128);
  224. assert_true(hmu_get_size(hmu_aligned) >= 128);
  225. /* Free both */
  226. mem_allocator_free(allocator, normal);
  227. mem_allocator_free(allocator, aligned);
  228. mem_allocator_destroy(allocator);
  229. }
  230. /* Test: Many aligned allocations */
  231. static void
  232. test_aligned_alloc_many(void **state)
  233. {
  234. mem_allocator_t allocator;
  235. char heap_buf[512 * 1024];
  236. void *ptrs[100];
  237. int count = 0;
  238. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  239. assert_non_null(allocator);
  240. /* Allocate as many as possible */
  241. for (int i = 0; i < 100; i++) {
  242. int align = (i % 4 == 0) ? 64 : 32;
  243. ptrs[i] = mem_allocator_malloc_aligned(allocator, align * 2, align);
  244. if (ptrs[i]) {
  245. assert_true(is_aligned(ptrs[i], align));
  246. count++;
  247. }
  248. else {
  249. break;
  250. }
  251. }
  252. assert_true(count > 10); /* At least some should succeed */
  253. /* Free all */
  254. for (int i = 0; i < count; i++) {
  255. mem_allocator_free(allocator, ptrs[i]);
  256. }
  257. mem_allocator_destroy(allocator);
  258. }
  259. /* Test: Many mixed allocations */
  260. static void
  261. test_mixed_alloc_many(void **state)
  262. {
  263. mem_allocator_t allocator;
  264. char heap_buf[512 * 1024];
  265. void *ptrs[200];
  266. int count = 0;
  267. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  268. assert_non_null(allocator);
  269. /* Alternate normal and aligned */
  270. for (int i = 0; i < 200; i++) {
  271. if (i % 2 == 0) {
  272. /* Normal allocation */
  273. ptrs[i] = mem_allocator_malloc(allocator, 64);
  274. }
  275. else {
  276. /* Aligned allocation */
  277. ptrs[i] = mem_allocator_malloc_aligned(allocator, 64, 32);
  278. }
  279. if (ptrs[i]) {
  280. count++;
  281. }
  282. else {
  283. break;
  284. }
  285. }
  286. assert_true(count > 20);
  287. /* Free in reverse order */
  288. for (int i = count - 1; i >= 0; i--) {
  289. mem_allocator_free(allocator, ptrs[i]);
  290. }
  291. mem_allocator_destroy(allocator);
  292. }
  293. /* Test: free a .ro data */
  294. static void
  295. test_free_ro_data(void **state)
  296. {
  297. mem_allocator_t allocator;
  298. char heap_buf[64 * 1024];
  299. void *ptr;
  300. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  301. assert_non_null(allocator);
  302. /* Freeing a .ro data pointer should not crash */
  303. const char *ro_str = "This is a read-only string.";
  304. // FIXME: This case should trigger an exception because the pointer is not
  305. // allocated by the allocator, but currently it just does nothing. We should
  306. // add a check in mem_allocator_free to detect this case and return an
  307. // error. mem_allocator_free(allocator, (void *)ro_str);
  308. mem_allocator_destroy(allocator);
  309. }
  310. /* Test: free a freed pointer */
  311. static void
  312. test_free_freed_pointer(void **state)
  313. {
  314. mem_allocator_t allocator;
  315. char heap_buf[64 * 1024];
  316. void *ptr;
  317. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  318. assert_non_null(allocator);
  319. ptr = mem_allocator_malloc(allocator, 64);
  320. assert_non_null(ptr);
  321. mem_allocator_free(allocator, ptr);
  322. /* Freeing the same pointer again should not crash */
  323. mem_allocator_free(allocator, ptr);
  324. mem_allocator_free(allocator, ptr);
  325. mem_allocator_destroy(allocator);
  326. }
  327. /* Test: free a freed pointer from aligned-alloc */
  328. static void
  329. test_free_freed_pointer_aligned(void **state)
  330. {
  331. mem_allocator_t allocator;
  332. char heap_buf[64 * 1024];
  333. void *ptr;
  334. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  335. assert_non_null(allocator);
  336. ptr = mem_allocator_malloc_aligned(allocator, 128, 64);
  337. assert_non_null(ptr);
  338. mem_allocator_free(allocator, ptr);
  339. /* Freeing the same pointer again should not crash */
  340. mem_allocator_free(allocator, ptr);
  341. mem_allocator_free(allocator, ptr);
  342. mem_allocator_free(allocator, ptr);
  343. mem_allocator_destroy(allocator);
  344. }
  345. /* Test: wasm_runtime_aligned_alloc with valid inputs in POOL mode */
  346. static void
  347. test_wasm_runtime_aligned_alloc_valid(void **state)
  348. {
  349. RuntimeInitArgs init_args;
  350. void *ptr;
  351. memset(&init_args, 0, sizeof(RuntimeInitArgs));
  352. init_args.mem_alloc_type = Alloc_With_Pool;
  353. init_args.mem_alloc_option.pool.heap_buf = malloc(256 * 1024);
  354. init_args.mem_alloc_option.pool.heap_size = 256 * 1024;
  355. assert_true(wasm_runtime_full_init(&init_args));
  356. /* Test valid aligned allocation */
  357. ptr = wasm_runtime_aligned_alloc(128, 64);
  358. assert_non_null(ptr);
  359. assert_true(is_aligned(ptr, 64));
  360. /* Free should work */
  361. wasm_runtime_free(ptr);
  362. wasm_runtime_destroy();
  363. free(init_args.mem_alloc_option.pool.heap_buf);
  364. }
  365. /* Test: wasm_runtime_aligned_alloc with zero size */
  366. static void
  367. test_wasm_runtime_aligned_alloc_zero_size(void **state)
  368. {
  369. RuntimeInitArgs init_args;
  370. void *ptr;
  371. memset(&init_args, 0, sizeof(RuntimeInitArgs));
  372. init_args.mem_alloc_type = Alloc_With_Pool;
  373. init_args.mem_alloc_option.pool.heap_buf = malloc(256 * 1024);
  374. init_args.mem_alloc_option.pool.heap_size = 256 * 1024;
  375. assert_true(wasm_runtime_full_init(&init_args));
  376. /* Zero size should allocate alignment bytes (like malloc(0) behavior) */
  377. ptr = wasm_runtime_aligned_alloc(0, 64);
  378. assert_non_null(ptr);
  379. assert_true(is_aligned(ptr, 64));
  380. wasm_runtime_free(ptr);
  381. wasm_runtime_destroy();
  382. free(init_args.mem_alloc_option.pool.heap_buf);
  383. }
  384. /* Test: wasm_runtime_aligned_alloc with zero alignment */
  385. static void
  386. test_wasm_runtime_aligned_alloc_zero_alignment(void **state)
  387. {
  388. RuntimeInitArgs init_args;
  389. void *ptr;
  390. memset(&init_args, 0, sizeof(RuntimeInitArgs));
  391. init_args.mem_alloc_type = Alloc_With_Pool;
  392. init_args.mem_alloc_option.pool.heap_buf = malloc(256 * 1024);
  393. init_args.mem_alloc_option.pool.heap_size = 256 * 1024;
  394. assert_true(wasm_runtime_full_init(&init_args));
  395. /* Zero alignment should return NULL */
  396. ptr = wasm_runtime_aligned_alloc(128, 0);
  397. assert_null(ptr);
  398. wasm_runtime_destroy();
  399. free(init_args.mem_alloc_option.pool.heap_buf);
  400. }
  401. /* Test: wasm_runtime_aligned_alloc in SYSTEM_ALLOCATOR mode returns NULL */
  402. static void
  403. test_wasm_runtime_aligned_alloc_system_mode(void **state)
  404. {
  405. RuntimeInitArgs init_args;
  406. void *ptr;
  407. memset(&init_args, 0, sizeof(RuntimeInitArgs));
  408. init_args.mem_alloc_type = Alloc_With_System_Allocator;
  409. assert_true(wasm_runtime_full_init(&init_args));
  410. /* Should return NULL in non-POOL mode */
  411. ptr = wasm_runtime_aligned_alloc(128, 64);
  412. assert_null(ptr);
  413. wasm_runtime_destroy();
  414. }
  415. /* Test: wasm_runtime_realloc rejects aligned allocations */
  416. static void
  417. test_wasm_runtime_realloc_rejects_aligned(void **state)
  418. {
  419. RuntimeInitArgs init_args;
  420. void *ptr, *new_ptr;
  421. memset(&init_args, 0, sizeof(RuntimeInitArgs));
  422. init_args.mem_alloc_type = Alloc_With_Pool;
  423. init_args.mem_alloc_option.pool.heap_buf = malloc(256 * 1024);
  424. init_args.mem_alloc_option.pool.heap_size = 256 * 1024;
  425. assert_true(wasm_runtime_full_init(&init_args));
  426. /* Allocate with alignment */
  427. ptr = wasm_runtime_aligned_alloc(128, 64);
  428. assert_non_null(ptr);
  429. /* Realloc should return NULL */
  430. new_ptr = wasm_runtime_realloc(ptr, 256);
  431. assert_null(new_ptr);
  432. /* Original pointer still valid */
  433. wasm_runtime_free(ptr);
  434. wasm_runtime_destroy();
  435. free(init_args.mem_alloc_option.pool.heap_buf);
  436. }
  437. /* Test: wasm_runtime_aligned_alloc with various alignments */
  438. static void
  439. test_wasm_runtime_aligned_alloc_multiple_alignments(void **state)
  440. {
  441. RuntimeInitArgs init_args;
  442. int alignments[] = { 8, 16, 32, 64, 128, 256 };
  443. int num_alignments = sizeof(alignments) / sizeof(alignments[0]);
  444. memset(&init_args, 0, sizeof(RuntimeInitArgs));
  445. init_args.mem_alloc_type = Alloc_With_Pool;
  446. init_args.mem_alloc_option.pool.heap_buf = malloc(512 * 1024);
  447. init_args.mem_alloc_option.pool.heap_size = 512 * 1024;
  448. assert_true(wasm_runtime_full_init(&init_args));
  449. for (int i = 0; i < num_alignments; i++) {
  450. int align = alignments[i];
  451. void *ptr = wasm_runtime_aligned_alloc(align * 2, align);
  452. assert_non_null(ptr);
  453. assert_true(is_aligned(ptr, align));
  454. wasm_runtime_free(ptr);
  455. }
  456. wasm_runtime_destroy();
  457. free(init_args.mem_alloc_option.pool.heap_buf);
  458. }
  459. /* Test: Normal allocation with huge size (near upper limit) */
  460. static void
  461. test_normal_alloc_huge_size(void **state)
  462. {
  463. mem_allocator_t allocator;
  464. char heap_buf[1024 * 1024]; /* 1MB heap */
  465. void *ptr;
  466. size_t huge_size;
  467. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  468. assert_non_null(allocator);
  469. /* Try to allocate most of the heap */
  470. huge_size = sizeof(heap_buf) - 4096; /* Leave some overhead */
  471. ptr = mem_allocator_malloc(allocator, huge_size);
  472. /* May succeed or fail depending on internal fragmentation */
  473. if (ptr) {
  474. /* If it succeeds, verify it's properly allocated */
  475. assert_true(is_aligned(ptr, 8));
  476. mem_allocator_free(allocator, ptr);
  477. }
  478. /* Try allocation at exact upper limit - should handle gracefully */
  479. huge_size = SIZE_MAX - 1024;
  480. ptr = mem_allocator_malloc(allocator, huge_size);
  481. assert_null(ptr); /* Should fail gracefully, not crash */
  482. mem_allocator_destroy(allocator);
  483. }
  484. /* Test: Aligned allocation with huge size (near upper limit) */
  485. static void
  486. test_aligned_alloc_huge_size(void **state)
  487. {
  488. mem_allocator_t allocator;
  489. char heap_buf[1024 * 1024]; /* 1MB heap */
  490. void *ptr;
  491. size_t huge_size;
  492. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  493. assert_non_null(allocator);
  494. /* Try to allocate most of the heap with alignment */
  495. huge_size = 512 * 1024; /* Size must be multiple of alignment */
  496. ptr = mem_allocator_malloc_aligned(allocator, huge_size, 512);
  497. /* May succeed or fail depending on alignment overhead */
  498. if (ptr) {
  499. assert_true(is_aligned(ptr, 512));
  500. mem_allocator_free(allocator, ptr);
  501. }
  502. /* Try allocation at extreme size - should fail gracefully */
  503. huge_size = (SIZE_MAX / 2) & ~(size_t)4095; /* Aligned to 4096 */
  504. ptr = mem_allocator_malloc_aligned(allocator, huge_size, 4096);
  505. assert_null(ptr); /* Should fail gracefully, not crash */
  506. mem_allocator_destroy(allocator);
  507. }
  508. /* Test: Normal allocations until OOM */
  509. static void
  510. test_normal_alloc_until_oom(void **state)
  511. {
  512. mem_allocator_t allocator;
  513. char heap_buf[256 * 1024];
  514. void *ptrs[1000];
  515. int count = 0;
  516. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  517. assert_non_null(allocator);
  518. /* Allocate until we run out of memory */
  519. for (int i = 0; i < 1000; i++) {
  520. ptrs[i] = mem_allocator_malloc(allocator, 1024);
  521. if (ptrs[i]) {
  522. count++;
  523. }
  524. else {
  525. /* OOM reached - this is expected */
  526. break;
  527. }
  528. }
  529. /* Should have allocated at least some blocks */
  530. assert_true(count > 10);
  531. assert_true(count < 1000); /* Should not have allocated all */
  532. /* Should still be able to free what we allocated */
  533. for (int i = 0; i < count; i++) {
  534. mem_allocator_free(allocator, ptrs[i]);
  535. }
  536. /* After freeing, should be able to allocate again */
  537. void *ptr = mem_allocator_malloc(allocator, 1024);
  538. assert_non_null(ptr);
  539. mem_allocator_free(allocator, ptr);
  540. mem_allocator_destroy(allocator);
  541. }
  542. /* Test: Aligned allocations until OOM */
  543. static void
  544. test_aligned_alloc_until_oom(void **state)
  545. {
  546. mem_allocator_t allocator;
  547. char heap_buf[512 * 1024];
  548. void *ptrs[500];
  549. int count = 0;
  550. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  551. assert_non_null(allocator);
  552. /* Allocate with alignment until we run out of memory */
  553. for (int i = 0; i < 500; i++) {
  554. /* Alternate between different alignments */
  555. int align = (i % 2 == 0) ? 64 : 128;
  556. ptrs[i] = mem_allocator_malloc_aligned(allocator, align * 20, align);
  557. if (ptrs[i]) {
  558. assert_true(is_aligned(ptrs[i], align));
  559. count++;
  560. }
  561. else {
  562. /* OOM reached - this is expected */
  563. break;
  564. }
  565. }
  566. /* Should have allocated at least some blocks */
  567. assert_true(count > 5);
  568. assert_true(count < 500); /* Should not have allocated all */
  569. /* Free all allocated blocks */
  570. for (int i = 0; i < count; i++) {
  571. mem_allocator_free(allocator, ptrs[i]);
  572. }
  573. /* After freeing, should be able to allocate again */
  574. void *ptr = mem_allocator_malloc_aligned(allocator, 256, 64);
  575. assert_non_null(ptr);
  576. mem_allocator_free(allocator, ptr);
  577. mem_allocator_destroy(allocator);
  578. }
  579. /* Test: Mixed normal and aligned allocations until OOM */
  580. static void
  581. test_mixed_alloc_until_oom(void **state)
  582. {
  583. mem_allocator_t allocator;
  584. char heap_buf[128 * 1024];
  585. void *ptrs[1000];
  586. bool is_aligned_alloc[1000];
  587. int count = 0;
  588. allocator = mem_allocator_create(heap_buf, sizeof(heap_buf));
  589. assert_non_null(allocator);
  590. /* Alternate between normal and aligned allocations until OOM */
  591. for (int i = 0; i < 1000; i++) {
  592. if (i % 3 == 0) {
  593. /* Aligned allocation */
  594. ptrs[i] = mem_allocator_malloc_aligned(allocator, 128, 64);
  595. is_aligned_alloc[i] = true;
  596. }
  597. else {
  598. /* Normal allocation */
  599. ptrs[i] = mem_allocator_malloc(allocator, 512);
  600. is_aligned_alloc[i] = false;
  601. }
  602. if (ptrs[i]) {
  603. if (is_aligned_alloc[i]) {
  604. assert_true(is_aligned(ptrs[i], 64));
  605. }
  606. count++;
  607. }
  608. else {
  609. /* OOM reached */
  610. break;
  611. }
  612. }
  613. /* Should have allocated a reasonable number of blocks */
  614. assert_true(count > 20);
  615. assert_true(count < 1000); /* Should not have allocated all */
  616. /* Free in random order (every other block first) */
  617. for (int i = 0; i < count; i += 2) {
  618. mem_allocator_free(allocator, ptrs[i]);
  619. }
  620. for (int i = 1; i < count; i += 2) {
  621. mem_allocator_free(allocator, ptrs[i]);
  622. }
  623. /* Verify allocator still works after OOM and free */
  624. void *ptr1 = mem_allocator_malloc(allocator, 1024);
  625. void *ptr2 = mem_allocator_malloc_aligned(allocator, 128, 64);
  626. assert_non_null(ptr1);
  627. assert_non_null(ptr2);
  628. mem_allocator_free(allocator, ptr1);
  629. mem_allocator_free(allocator, ptr2);
  630. mem_allocator_destroy(allocator);
  631. }