Skip to content

Commit a02ad8b

Browse files
lum1n0usclaude
andcommitted
refactor(mem-alloc): improve aligned allocation design and documentation
This commit addresses several design improvements for aligned allocation: 1. **Size=0 behavior consistency**: - wasm_runtime_aligned_alloc(0, N) now allocates N bytes (smallest valid size) - Matches wasm_runtime_malloc(0) behavior which allocates 1 byte - Ensures size is always a multiple of alignment 2. **Helper function for alignment detection**: - Add gc_is_aligned_allocation() inline helper in ems_gc_internal.h - Encapsulates magic marker check logic (DRY principle) - Used in obj_to_hmu() and gc_realloc_vo_internal() - Single source of truth for alignment detection 3. **Global API visibility macro**: - Add WASM_RUNTIME_API_INTERN to bh_platform.h - Centralizes internal API visibility control - MEM_ALLOC_API_INTER now uses WASM_RUNTIME_API_INTERN - Consistent with WASM_RUNTIME_API_EXTERN pattern 4. **Comprehensive documentation**: - Replace brief comment with 90+ line documentation block - Explain POSIX aligned_alloc() specification (C11 §7.22.3.1) - Describe WAMR implementation strategy in detail: * Validation, over-allocation, alignment adjustment * Magic marker storage (0xA11C0000 | offset) * Realloc prevention mechanism - Include memory layout diagram with ASCII art - Document constraints, limitations, and usage examples - Helps future maintainers understand design decisions Files changed: - core/iwasm/common/wasm_memory.c: Fix size=0 behavior - core/shared/utils/bh_platform.h: Add WASM_RUNTIME_API_INTERN - core/shared/mem-alloc/ems/ems_gc_internal.h: Add helper + docs - core/shared/mem-alloc/ems/ems_alloc.c: Use helper function - tests/unit/mem-alloc/mem_alloc_test.c: Update test expectations Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 95157c2 commit a02ad8b

File tree

5 files changed

+142
-31
lines changed

5 files changed

+142
-31
lines changed

core/iwasm/common/wasm_memory.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,16 +1073,20 @@ wasm_runtime_malloc(unsigned int size)
10731073
void *
10741074
wasm_runtime_aligned_alloc(unsigned int size, unsigned int alignment)
10751075
{
1076-
if (size == 0) {
1077-
LOG_WARNING("warning: wasm_runtime_aligned_alloc with size zero\n");
1078-
return NULL;
1079-
}
1080-
10811076
if (alignment == 0) {
10821077
LOG_WARNING("warning: wasm_runtime_aligned_alloc with zero alignment\n");
10831078
return NULL;
10841079
}
10851080

1081+
if (size == 0) {
1082+
LOG_WARNING("warning: wasm_runtime_aligned_alloc with size zero\n");
1083+
/* Allocate at least alignment bytes (smallest multiple of alignment) */
1084+
size = alignment;
1085+
#if BH_ENABLE_GC_VERIFY != 0
1086+
exit(-1);
1087+
#endif
1088+
}
1089+
10861090
#if WASM_ENABLE_FUZZ_TEST != 0
10871091
if (size >= WASM_MEM_ALLOC_MAX_SIZE) {
10881092
LOG_WARNING("warning: wasm_runtime_aligned_alloc with too large size\n");

core/shared/mem-alloc/ems/ems_alloc.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -556,10 +556,8 @@ alloc_hmu_ex(gc_heap_t *heap, gc_size_t size)
556556
MEM_ALLOC_API_INTER hmu_t *
557557
obj_to_hmu(gc_object_t obj)
558558
{
559-
uint32_t *magic_ptr = (uint32_t *)((char *)obj - 4);
560-
561559
/* Check for aligned allocation magic signature */
562-
if ((*magic_ptr & ALIGNED_ALLOC_MAGIC_MASK) == ALIGNED_ALLOC_MAGIC_VALUE) {
560+
if (gc_is_aligned_allocation(obj)) {
563561
/* This is an aligned allocation, read offset */
564562
uint32_t *offset_ptr = (uint32_t *)((char *)obj - 8);
565563
return (hmu_t *)((char *)obj - *offset_ptr);
@@ -779,13 +777,10 @@ gc_realloc_vo_internal(void *vheap, void *ptr, gc_size_t size, const char *file,
779777
#endif
780778

781779
/* Check if this is an aligned allocation - not supported */
782-
if (obj_old) {
783-
uint32_t *magic_ptr = (uint32_t *)((char *)obj_old - 4);
784-
if ((*magic_ptr & ALIGNED_ALLOC_MAGIC_MASK) == ALIGNED_ALLOC_MAGIC_VALUE) {
785-
LOG_ERROR("[GC_ERROR]gc_realloc_vo does not support aligned "
786-
"allocations\n");
787-
return NULL;
788-
}
780+
if (gc_is_aligned_allocation(obj_old)) {
781+
LOG_ERROR("[GC_ERROR]gc_realloc_vo does not support aligned "
782+
"allocations\n");
783+
return NULL;
789784
}
790785

791786
if (obj_old) {

core/shared/mem-alloc/ems/ems_gc_internal.h

Lines changed: 107 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,7 @@ extern "C" {
1515

1616
/* Test visibility macro for internal functions */
1717
#ifndef MEM_ALLOC_API_INTER
18-
#ifdef WAMR_BUILD_TEST
19-
#define MEM_ALLOC_API_INTER
20-
#else
21-
#define MEM_ALLOC_API_INTER static
22-
#endif
18+
#define MEM_ALLOC_API_INTER WASM_RUNTIME_API_INTERN
2319
#endif
2420

2521
/* HMU (heap memory unit) basic block type */
@@ -102,22 +98,119 @@ hmu_verify(void *vheap, hmu_t *hmu);
10298
+ (((x) > 8) ? (x) : 8))
10399

104100
/*
105-
* Aligned allocation uses metadata in the header to store the offset
101+
* ============================================================================
102+
* Aligned Memory Allocation
103+
* ============================================================================
106104
*
107-
* ### Memory Layout
105+
* This module implements aligned memory allocation similar to C11 aligned_alloc()
106+
* and POSIX posix_memalign() for WAMR's garbage collector.
108107
*
109-
* Aligned allocations use over-allocation with metadata storage:
108+
* POSIX aligned_alloc() Specification:
109+
* ------------------------------------
110+
* From C11 §7.22.3.1 and POSIX.1-2017:
111+
* void *aligned_alloc(size_t alignment, size_t size);
110112
*
111-
* ```
112-
* [HMU][PREFIX][...padding...][METADATA][ALIGNED_OBJ][SUFFIX]
113-
* ^8 bytes ^returned pointer (aligned)
114-
* ```
113+
* Requirements:
114+
* - alignment: Must be a valid alignment supported by the implementation,
115+
* typically a power of 2
116+
* - size: Must be an integral multiple of alignment
117+
* - Returns: Pointer aligned to the specified alignment boundary, or NULL
118+
* - Memory must be freed with free() (not realloc'd)
119+
* - Behavior: If size is 0, may return NULL or unique pointer (impl-defined)
120+
*
121+
* IMPORTANT: POSIX does not require realloc() to preserve alignment.
122+
* Calling realloc() on aligned_alloc() memory has undefined behavior.
123+
*
124+
* WAMR Implementation Strategy:
125+
* -----------------------------
126+
* We implement alignment through over-allocation with metadata tracking:
127+
*
128+
* 1. **Validation Phase**:
129+
* - Check alignment is power-of-2, >= 8 bytes, <= system page size
130+
* - Check size is multiple of alignment
131+
* - Return NULL if validation fails
132+
*
133+
* 2. **Over-Allocation**:
134+
* - Allocate (size + alignment + metadata_overhead) bytes
135+
* - Extra space allows us to find an aligned boundary within the block
136+
* - Calculate log2(alignment) for efficient offset storage
137+
*
138+
* 3. **Alignment Adjustment**:
139+
* - Find next aligned address within allocated block
140+
* - Calculate offset from original allocation to aligned address
141+
* - Store offset in metadata for later free() operation
142+
*
143+
* 4. **Magic Marker Storage**:
144+
* - Store magic marker (0xA11C0000 | offset) in 4 bytes before user pointer
145+
* - Upper 16 bits: 0xA11C identifies aligned allocation
146+
* - Lower 16 bits: offset from HMU to aligned pointer (max 65535 bytes)
147+
* - This marker prevents unsafe realloc() operations
148+
*
149+
* 5. **Realloc Prevention**:
150+
* - gc_realloc_vo_internal() checks for magic marker
151+
* - Returns NULL if realloc attempted on aligned allocation
152+
* - User must manually allocate new memory and copy data
153+
*
154+
* Memory Layout Diagram:
155+
* ----------------------
156+
*
157+
* Low Address High Address
158+
* ┌─────────────┬──────────┬────────────────┬──────────────┬─────────────┐
159+
* │ HMU Header │ Padding │ Magic + Offset │ Aligned Data │ Padding │
160+
* │ (meta) │ (0-align)│ (4 bytes) │ (size) │ (overhead) │
161+
* └─────────────┴──────────┴────────────────┴──────────────┴─────────────┘
162+
* ▲ ▲
163+
* │ │
164+
* magic_ptr user_ptr (returned, aligned)
115165
*
116-
* Magic value for aligned allocation detection
166+
* Constraints and Limitations:
167+
* ----------------------------
168+
* - Minimum alignment: 8 bytes (GC_MIN_ALIGNMENT)
169+
* - Maximum alignment: System page size (os_getpagesize(), typically 4KB)
170+
* - Maximum offset: 65535 bytes (16-bit storage limit)
171+
* - Realloc support: None - returns NULL (prevents alignment loss)
172+
* - Free support: Full - use mem_allocator_free() / wasm_runtime_free()
173+
* - Thread safety: Protected by LOCK_HEAP/UNLOCK_HEAP
174+
*
175+
* Usage Example:
176+
* --------------
177+
* // Allocate 256 bytes aligned to 64-byte boundary (e.g., for SIMD)
178+
* void *ptr = wasm_runtime_aligned_alloc(256, 64);
179+
* assert((uintptr_t)ptr % 64 == 0); // Guaranteed aligned
180+
*
181+
* // Use the memory...
182+
*
183+
* // Free normally (alignment metadata handled automatically)
184+
* wasm_runtime_free(ptr);
185+
*
186+
* // INVALID: Cannot realloc aligned memory
187+
* void *new_ptr = wasm_runtime_realloc(ptr, 512); // Returns NULL!
117188
*/
118-
#define ALIGNED_ALLOC_MAGIC_MASK 0xFFFF0000
189+
190+
/* Aligned allocation magic markers */
191+
#define ALIGNED_ALLOC_MAGIC_MASK 0xFFFF0000
119192
#define ALIGNED_ALLOC_MAGIC_VALUE 0xA11C0000
120193

194+
/**
195+
* Check if a gc_object was allocated with alignment requirements.
196+
*
197+
* Aligned allocations store a magic marker (0xA11C0000) in the 4 bytes
198+
* immediately before the object pointer. This marker is used to identify
199+
* aligned allocations to prevent unsafe realloc operations.
200+
*
201+
* @param obj the gc_object to check (user-visible pointer)
202+
* @return true if obj is an aligned allocation, false otherwise
203+
*/
204+
static inline bool
205+
gc_is_aligned_allocation(gc_object_t obj)
206+
{
207+
if (!obj)
208+
return false;
209+
210+
uint32_t *magic_ptr = (uint32_t *)((char *)obj - 4);
211+
return ((*magic_ptr & ALIGNED_ALLOC_MAGIC_MASK) == ALIGNED_ALLOC_MAGIC_VALUE);
212+
}
213+
121214
/**
122215
* hmu bit operation
123216
*/

core/shared/utils/bh_platform.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,23 @@
1818
#include "bh_vector.h"
1919
#include "runtime_timer.h"
2020

21+
/**
22+
* API visibility macros for WAMR internal functions
23+
*
24+
* WASM_RUNTIME_API_EXTERN - Public exported APIs (defined in wasm_export.h)
25+
* WASM_RUNTIME_API_INTERN - Internal APIs visible across WAMR components
26+
*
27+
* In test builds (WAMR_BUILD_TEST=1), internal APIs are exposed for unit testing.
28+
* In production builds, internal APIs are static (file-scoped) for encapsulation.
29+
*/
30+
#ifndef WASM_RUNTIME_API_INTERN
31+
#ifdef WAMR_BUILD_TEST
32+
#define WASM_RUNTIME_API_INTERN
33+
#else
34+
#define WASM_RUNTIME_API_INTERN static
35+
#endif
36+
#endif
37+
2138
/**
2239
* WA_MALLOC/WA_FREE need to be redefined for both
2340
* runtime native and WASM app respectively.

tests/unit/mem-alloc/mem_alloc_test.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,10 +406,12 @@ test_wasm_runtime_aligned_alloc_zero_size(void **state)
406406

407407
assert_true(wasm_runtime_full_init(&init_args));
408408

409-
/* Zero size should return NULL */
409+
/* Zero size should allocate alignment bytes (like malloc(0) behavior) */
410410
ptr = wasm_runtime_aligned_alloc(0, 64);
411-
assert_null(ptr);
411+
assert_non_null(ptr);
412+
assert_true(is_aligned(ptr, 64));
412413

414+
wasm_runtime_free(ptr);
413415
wasm_runtime_destroy();
414416
free(init_args.mem_alloc_option.pool.heap_buf);
415417
}

0 commit comments

Comments
 (0)