Skip to content

Commit dc8e9e8

Browse files
committed
wasm2c: Mmap+guard on big-endian won't move memory (fix #2599)
1 parent 975539c commit dc8e9e8

File tree

12 files changed

+95
-67
lines changed

12 files changed

+95
-67
lines changed

src/prebuilt/wasm2c_source_declarations.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ R"w2c_template(// A pointer for an object of size n.
3131
)w2c_template"
3232
R"w2c_template(#if WABT_BIG_ENDIAN
3333
)w2c_template"
34-
R"w2c_template(#define MEM_ADDR(mem, addr, n) &(mem)->data[(mem)->size - (addr) - (n)]
34+
R"w2c_template(#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n))
3535
)w2c_template"
3636
R"w2c_template(#else
3737
)w2c_template"
38-
R"w2c_template(#define MEM_ADDR(mem, addr, n) &(mem)->data[addr]
38+
R"w2c_template(#define MEM_ADDR(mem, addr, n) &((mem)->data[addr])
3939
)w2c_template"
4040
R"w2c_template(#endif
4141
)w2c_template"
@@ -194,7 +194,7 @@ R"w2c_template( if (UNLIKELY(add_overflow(offset, len, &res))) \
194194
)w2c_template"
195195
R"w2c_template( TRAP(OOB); \
196196
)w2c_template"
197-
R"w2c_template( if (UNLIKELY(res > mem->size)) \
197+
R"w2c_template( if (UNLIKELY(res > (mem)->size)) \
198198
)w2c_template"
199199
R"w2c_template( TRAP(OOB); \
200200
)w2c_template"

src/template/wasm2c.declarations.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
// Result:
1616
// A pointer for an object of size n.
1717
#if WABT_BIG_ENDIAN
18-
#define MEM_ADDR(mem, addr, n) &(mem)->data[(mem)->size - (addr) - (n)]
18+
#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n))
1919
#else
20-
#define MEM_ADDR(mem, addr, n) &(mem)->data[addr]
20+
#define MEM_ADDR(mem, addr, n) &((mem)->data[addr])
2121
#endif
2222

2323
// We can only use Segue for this module if it uses a single unshared imported
@@ -104,7 +104,7 @@ static inline bool add_overflow(uint64_t a, uint64_t b, uint64_t* resptr) {
104104
uint64_t res; \
105105
if (UNLIKELY(add_overflow(offset, len, &res))) \
106106
TRAP(OOB); \
107-
if (UNLIKELY(res > mem->size)) \
107+
if (UNLIKELY(res > (mem)->size)) \
108108
TRAP(OOB); \
109109
} while (0);
110110

test/wasm2c/add.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ u32 w2c_test_add(w2c_test*, u32, u32);
8282
// Result:
8383
// A pointer for an object of size n.
8484
#if WABT_BIG_ENDIAN
85-
#define MEM_ADDR(mem, addr, n) &(mem)->data[(mem)->size - (addr) - (n)]
85+
#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n))
8686
#else
87-
#define MEM_ADDR(mem, addr, n) &(mem)->data[addr]
87+
#define MEM_ADDR(mem, addr, n) &((mem)->data[addr])
8888
#endif
8989

9090
// We can only use Segue for this module if it uses a single unshared imported
@@ -171,7 +171,7 @@ static inline bool add_overflow(uint64_t a, uint64_t b, uint64_t* resptr) {
171171
uint64_t res; \
172172
if (UNLIKELY(add_overflow(offset, len, &res))) \
173173
TRAP(OOB); \
174-
if (UNLIKELY(res > mem->size)) \
174+
if (UNLIKELY(res > (mem)->size)) \
175175
TRAP(OOB); \
176176
} while (0);
177177

test/wasm2c/check-imports.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ extern const u32 wasm2c_test_pagesize_env_0x5F_linear_memory;
107107
// Result:
108108
// A pointer for an object of size n.
109109
#if WABT_BIG_ENDIAN
110-
#define MEM_ADDR(mem, addr, n) &(mem)->data[(mem)->size - (addr) - (n)]
110+
#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n))
111111
#else
112-
#define MEM_ADDR(mem, addr, n) &(mem)->data[addr]
112+
#define MEM_ADDR(mem, addr, n) &((mem)->data[addr])
113113
#endif
114114

115115
// We can only use Segue for this module if it uses a single unshared imported
@@ -196,7 +196,7 @@ static inline bool add_overflow(uint64_t a, uint64_t b, uint64_t* resptr) {
196196
uint64_t res; \
197197
if (UNLIKELY(add_overflow(offset, len, &res))) \
198198
TRAP(OOB); \
199-
if (UNLIKELY(res > mem->size)) \
199+
if (UNLIKELY(res > (mem)->size)) \
200200
TRAP(OOB); \
201201
} while (0);
202202

test/wasm2c/export-names.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ void w2c_test_0xE20x9D0xA40xEF0xB80x8F(w2c_test*);
107107
// Result:
108108
// A pointer for an object of size n.
109109
#if WABT_BIG_ENDIAN
110-
#define MEM_ADDR(mem, addr, n) &(mem)->data[(mem)->size - (addr) - (n)]
110+
#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n))
111111
#else
112-
#define MEM_ADDR(mem, addr, n) &(mem)->data[addr]
112+
#define MEM_ADDR(mem, addr, n) &((mem)->data[addr])
113113
#endif
114114

115115
// We can only use Segue for this module if it uses a single unshared imported
@@ -196,7 +196,7 @@ static inline bool add_overflow(uint64_t a, uint64_t b, uint64_t* resptr) {
196196
uint64_t res; \
197197
if (UNLIKELY(add_overflow(offset, len, &res))) \
198198
TRAP(OOB); \
199-
if (UNLIKELY(res > mem->size)) \
199+
if (UNLIKELY(res > (mem)->size)) \
200200
TRAP(OOB); \
201201
} while (0);
202202

test/wasm2c/hello.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,9 @@ void w2c_test_0x5Fstart(w2c_test*);
114114
// Result:
115115
// A pointer for an object of size n.
116116
#if WABT_BIG_ENDIAN
117-
#define MEM_ADDR(mem, addr, n) &(mem)->data[(mem)->size - (addr) - (n)]
117+
#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n))
118118
#else
119-
#define MEM_ADDR(mem, addr, n) &(mem)->data[addr]
119+
#define MEM_ADDR(mem, addr, n) &((mem)->data[addr])
120120
#endif
121121

122122
// We can only use Segue for this module if it uses a single unshared imported
@@ -203,7 +203,7 @@ static inline bool add_overflow(uint64_t a, uint64_t b, uint64_t* resptr) {
203203
uint64_t res; \
204204
if (UNLIKELY(add_overflow(offset, len, &res))) \
205205
TRAP(OOB); \
206-
if (UNLIKELY(res > mem->size)) \
206+
if (UNLIKELY(res > (mem)->size)) \
207207
TRAP(OOB); \
208208
} while (0);
209209

test/wasm2c/minimal.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ wasm_rt_func_type_t wasm2c_test_get_func_type(uint32_t param_count, uint32_t res
7676
// Result:
7777
// A pointer for an object of size n.
7878
#if WABT_BIG_ENDIAN
79-
#define MEM_ADDR(mem, addr, n) &(mem)->data[(mem)->size - (addr) - (n)]
79+
#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n))
8080
#else
81-
#define MEM_ADDR(mem, addr, n) &(mem)->data[addr]
81+
#define MEM_ADDR(mem, addr, n) &((mem)->data[addr])
8282
#endif
8383

8484
// We can only use Segue for this module if it uses a single unshared imported
@@ -165,7 +165,7 @@ static inline bool add_overflow(uint64_t a, uint64_t b, uint64_t* resptr) {
165165
uint64_t res; \
166166
if (UNLIKELY(add_overflow(offset, len, &res))) \
167167
TRAP(OOB); \
168-
if (UNLIKELY(res > mem->size)) \
168+
if (UNLIKELY(res > (mem)->size)) \
169169
TRAP(OOB); \
170170
} while (0);
171171

test/wasm2c/tail-calls.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ void wasm_tailcall_w2c_test_tailcaller(void **instance_ptr, void *tail_call_stac
106106
// Result:
107107
// A pointer for an object of size n.
108108
#if WABT_BIG_ENDIAN
109-
#define MEM_ADDR(mem, addr, n) &(mem)->data[(mem)->size - (addr) - (n)]
109+
#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n))
110110
#else
111-
#define MEM_ADDR(mem, addr, n) &(mem)->data[addr]
111+
#define MEM_ADDR(mem, addr, n) &((mem)->data[addr])
112112
#endif
113113

114114
// We can only use Segue for this module if it uses a single unshared imported
@@ -195,7 +195,7 @@ static inline bool add_overflow(uint64_t a, uint64_t b, uint64_t* resptr) {
195195
uint64_t res; \
196196
if (UNLIKELY(add_overflow(offset, len, &res))) \
197197
TRAP(OOB); \
198-
if (UNLIKELY(res > mem->size)) \
198+
if (UNLIKELY(res > (mem)->size)) \
199199
TRAP(OOB); \
200200
} while (0);
201201

wasm2c/benchmarks/dhrystone/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ typedef uint32_t u32;
1818
typedef uint64_t u64;
1919

2020
#if WABT_BIG_ENDIAN
21-
#define MEM_ADDR(mem, addr, n) &(mem)->data[(mem)->size - (addr) - (n)]
21+
#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n))
2222
#else
23-
#define MEM_ADDR(mem, addr, n) &(mem)->data[addr]
23+
#define MEM_ADDR(mem, addr, n) &((mem)->data[addr])
2424
#endif
2525

2626
#define MEM_ADDR_MEMOP(mem, addr, n) MEM_ADDR(mem, addr, n)

wasm2c/examples/fac/fac.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@
3434
// Result:
3535
// A pointer for an object of size n.
3636
#if WABT_BIG_ENDIAN
37-
#define MEM_ADDR(mem, addr, n) &(mem)->data[(mem)->size - (addr) - (n)]
37+
#define MEM_ADDR(mem, addr, n) ((mem)->data_end - (addr) - (n))
3838
#else
39-
#define MEM_ADDR(mem, addr, n) &(mem)->data[addr]
39+
#define MEM_ADDR(mem, addr, n) &((mem)->data[addr])
4040
#endif
4141

4242
// We can only use Segue for this module if it uses a single unshared imported
@@ -123,7 +123,7 @@ static inline bool add_overflow(uint64_t a, uint64_t b, uint64_t* resptr) {
123123
uint64_t res; \
124124
if (UNLIKELY(add_overflow(offset, len, &res))) \
125125
TRAP(OOB); \
126-
if (UNLIKELY(res > mem->size)) \
126+
if (UNLIKELY(res > (mem)->size)) \
127127
TRAP(OOB); \
128128
} while (0);
129129

wasm2c/wasm-rt-mem-impl-helper.inc

Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -76,26 +76,65 @@ void MEMORY_API_NAME(wasm_rt_allocate_memory)(MEMORY_TYPE* memory,
7676
memory->page_size = page_size;
7777
MEMORY_LOCK_VAR_INIT(memory->mem_lock);
7878

79-
if (WASM_RT_USE_MMAP &&
80-
MEMORY_API_NAME(wasm_rt_memory_is_default32)(memory)) {
81-
#if WASM_RT_USE_MMAP // mmap-related functions don't exist unless this is set
79+
#if WASM_RT_USE_MMAP
80+
if (MEMORY_API_NAME(wasm_rt_memory_is_default32)(memory)) {
8281
const uint64_t mmap_size =
8382
get_alloc_size_for_mmap_default32(memory->max_pages);
84-
void* addr = os_mmap(mmap_size);
83+
uint8_t* addr = os_mmap(mmap_size);
8584
if (!addr) {
8685
os_print_last_error("os_mmap failed.");
8786
abort();
8887
}
88+
uint8_t* data_end = addr + mmap_size;
89+
#if !WABT_BIG_ENDIAN
8990
int ret = os_mprotect(addr, byte_length);
91+
#else
92+
int ret = os_mprotect(data_end - byte_length, byte_length);
93+
#endif
9094
if (ret != 0) {
9195
os_print_last_error("os_mprotect failed.");
9296
abort();
9397
}
94-
memory->data = addr;
98+
memory->data = (MEMORY_CELL_TYPE)addr;
99+
memory->data_end = (MEMORY_CELL_TYPE)data_end;
100+
return;
101+
}
102+
#endif
103+
104+
memory->data = (MEMORY_CELL_TYPE)calloc(byte_length, 1);
105+
memory->data_end = memory->data + byte_length;
106+
}
107+
108+
// Returns 0 on success
109+
static int MEMORY_API_NAME(expand_data_allocation)(MEMORY_TYPE* memory,
110+
uint64_t old_size,
111+
uint64_t new_size,
112+
uint64_t delta_size) {
113+
#if WASM_RT_USE_MMAP
114+
if (MEMORY_API_NAME(wasm_rt_memory_is_default32)(memory)) {
115+
#if !WABT_BIG_ENDIAN
116+
return os_mprotect((void*)(memory->data + old_size), delta_size);
117+
#else
118+
return os_mprotect((void*)(memory->data_end - old_size - delta_size),
119+
delta_size);
95120
#endif
96-
} else {
97-
memory->data = calloc(byte_length, 1);
98121
}
122+
#endif
123+
124+
uint8_t* new_data = realloc((void*)memory->data, new_size);
125+
if (new_data == NULL) {
126+
return -1;
127+
}
128+
#if !WABT_BIG_ENDIAN
129+
memset((void*)(new_data + old_size), 0, delta_size);
130+
#else
131+
memmove((void*)(new_data + new_size - old_size), (void*)new_data, old_size);
132+
memset((void*)new_data, 0, delta_size);
133+
#endif
134+
135+
memory->data = (MEMORY_CELL_TYPE)new_data;
136+
memory->data_end = memory->data + new_size;
137+
return 0;
99138
}
100139

101140
static uint64_t MEMORY_API_NAME(grow_memory_impl)(MEMORY_TYPE* memory,
@@ -111,32 +150,15 @@ static uint64_t MEMORY_API_NAME(grow_memory_impl)(MEMORY_TYPE* memory,
111150
uint64_t old_size = old_pages * memory->page_size;
112151
uint64_t new_size = new_pages * memory->page_size;
113152
uint64_t delta_size = delta * memory->page_size;
114-
MEMORY_CELL_TYPE new_data;
115-
if (WASM_RT_USE_MMAP &&
116-
MEMORY_API_NAME(wasm_rt_memory_is_default32)(memory)) {
117-
#if WASM_RT_USE_MMAP
118-
new_data = memory->data;
119-
int ret = os_mprotect((void*)(new_data + old_size), delta_size);
120-
if (ret != 0) {
121-
return (uint64_t)-1;
122-
}
123-
#endif
124-
} else {
125-
new_data = realloc((void*)memory->data, new_size);
126-
if (new_data == NULL) {
127-
return (uint64_t)-1;
128-
}
129-
#if !WABT_BIG_ENDIAN
130-
memset((void*)(new_data + old_size), 0, delta_size);
131-
#endif
153+
154+
int err = MEMORY_API_NAME(expand_data_allocation)(memory, old_size, new_size,
155+
delta_size);
156+
if (err != 0) {
157+
return (uint64_t)-1;
132158
}
133-
#if WABT_BIG_ENDIAN
134-
memmove((void*)(new_data + new_size - old_size), (void*)new_data, old_size);
135-
memset((void*)new_data, 0, delta_size);
136-
#endif
159+
137160
memory->pages = new_pages;
138161
memory->size = new_size;
139-
memory->data = new_data;
140162
return old_pages;
141163
}
142164

@@ -154,16 +176,15 @@ uint64_t MEMORY_API_NAME(wasm_rt_grow_memory)(MEMORY_TYPE* memory,
154176
}
155177

156178
void MEMORY_API_NAME(wasm_rt_free_memory)(MEMORY_TYPE* memory) {
157-
if (WASM_RT_USE_MMAP &&
158-
MEMORY_API_NAME(wasm_rt_memory_is_default32)(memory)) {
159179
#if WASM_RT_USE_MMAP
180+
if (MEMORY_API_NAME(wasm_rt_memory_is_default32)(memory)) {
160181
const uint64_t mmap_size =
161182
get_alloc_size_for_mmap_default32(memory->max_pages);
162183
os_munmap((void*)memory->data, mmap_size); // ignore error
163-
#endif
164-
} else {
165-
free((void*)memory->data);
184+
return;
166185
}
186+
#endif
187+
free((void*)memory->data);
167188
}
168189

169190
#undef MEMORY_LOCK_RELEASE

wasm2c/wasm-rt.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ extern "C" {
140140
*
141141
* BOUNDS_CHECK: memory accesses are checked with explicit bounds checks.
142142
*
143-
* This defaults to GUARD_PAGES as this is the fasest option, iff the
143+
* This defaults to GUARD_PAGES as this is the fastest option, iff the
144144
* requirements of GUARD_PAGES --- 64-bit platforms, MMAP allocation strategy,
145145
* no 64-bit memories, no big-endian --- are met. This falls back to BOUNDS
146146
* otherwise.
@@ -266,13 +266,15 @@ extern "C" {
266266
/**
267267
* We need to detect and trap stack overflows. If we use a signal handler on
268268
* POSIX systems, this can detect call stack overflows. On windows, or platforms
269-
* without a signal handler, we use stack depth counting.
269+
* without a signal handler, we use stack depth counting. The s390x big endian
270+
* platform additionally seems to have issues with stack guard pages, so we play
271+
* it safe and use stack counting on big endian platforms.
270272
*/
271273
#if !defined(WASM_RT_STACK_DEPTH_COUNT) && \
272274
!defined(WASM_RT_STACK_EXHAUSTION_HANDLER) && \
273275
!WASM_RT_NONCONFORMING_UNCHECKED_STACK_EXHAUSTION
274276

275-
#if WASM_RT_INSTALL_SIGNAL_HANDLER && !defined(_WIN32)
277+
#if WASM_RT_INSTALL_SIGNAL_HANDLER && !defined(_WIN32) && !WABT_BIG_ENDIAN
276278
#define WASM_RT_STACK_EXHAUSTION_HANDLER 1
277279
#else
278280
#define WASM_RT_STACK_DEPTH_COUNT 1
@@ -465,6 +467,8 @@ typedef void* wasm_rt_externref_t;
465467
typedef struct {
466468
/** The linear memory data, with a byte length of `size`. */
467469
uint8_t* data;
470+
/** The location after the the reserved space for the linear memory data. */
471+
uint8_t* data_end;
468472
/** The page size for this Memory object
469473
(always 64 KiB without the custom-page-sizes feature) */
470474
uint32_t page_size;
@@ -493,6 +497,9 @@ typedef struct {
493497
* volatile.
494498
*/
495499
_Atomic volatile uint8_t* data;
500+
/** The location one byte after the reserved space for the linear memory data.
501+
* This includes any reserved pages that are not yet allocated. */
502+
_Atomic volatile uint8_t* data_end;
496503
/** The page size for this Memory object
497504
(always 64 KiB without the custom-page-sizes feature) */
498505
uint32_t page_size;

0 commit comments

Comments
 (0)