Skip to content

Commit f4115eb

Browse files
authored
Implement MAP_ANONYMOUS on top of malloc in STANDALONE_WASM mode (#16289)
This hack already exists in the JS implementation of mmap. We could try to unify the two but I'm not sure its worth it. Fixes: #16280, #13312
1 parent 2a4e295 commit f4115eb

File tree

3 files changed

+74
-8
lines changed

3 files changed

+74
-8
lines changed

system/lib/standalone/standalone.c

+66-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include <errno.h>
1010
#include <stdlib.h>
1111
#include <string.h>
12+
#include <sys/mman.h>
13+
#include <malloc.h>
1214
#include <time.h>
1315
#include <unistd.h>
1416

@@ -17,6 +19,8 @@
1719
#include <wasi/api.h>
1820
#include <wasi/wasi-helpers.h>
1921

22+
#include "lock.h"
23+
2024
/*
2125
* WASI support code. These are compiled with the program, and call out
2226
* using wasi APIs, which can be provided either by a wasi VM or by our
@@ -59,15 +63,73 @@ int clock_getres(clockid_t clk_id, struct timespec *tp) {
5963
// mmap support is nonexistent. TODO: emulate simple mmaps using
6064
// stdio + malloc, which is slow but may help some things?
6165

62-
long __map_file(int x, int y) {
63-
return -ENOSYS;
66+
const unsigned char * __map_file(const char *pathname, size_t *size) {
67+
errno = ENOSYS;
68+
return NULL;
6469
}
6570

66-
long __syscall_munmap(int x, int y) {
67-
return -ENOSYS;
71+
struct map {
72+
void* addr;
73+
long length;
74+
struct map* next;
75+
} __attribute__((aligned (1)));
76+
77+
static volatile int lock[1];
78+
static struct map* mappings;
79+
80+
long __syscall_munmap(long addr, long length) {
81+
LOCK(lock);
82+
struct map* map = mappings;
83+
struct map* prev = NULL;
84+
while (map) {
85+
if (map->addr == (void*)addr) {
86+
// We don't support partial munmapping.
87+
if (map->length != length) {
88+
map = NULL;
89+
break;
90+
}
91+
if (prev) {
92+
prev->next = map->next;
93+
} else {
94+
mappings = map->next;
95+
}
96+
break;
97+
}
98+
prev = map;
99+
map = map->next;
100+
}
101+
UNLOCK(lock);
102+
103+
if (map) {
104+
// Release the memory.
105+
free(map->addr);
106+
// Success!
107+
return 0;
108+
}
109+
110+
errno = EINVAL;
111+
return -1;
68112
}
69113

70114
long __syscall_mmap2(long addr, long len, long prot, long flags, long fd, long off) {
115+
// MAP_ANONYMOUS (aka MAP_ANON) isn't actually defined by POSIX spec,
116+
// but it is widely used way to allocate memory pages on Linux, BSD and Mac.
117+
// In this case fd argument is ignored.
118+
if (flags & MAP_ANONYMOUS) {
119+
void* ptr = memalign(WASM_PAGE_SIZE, len + sizeof(struct map));
120+
if (!ptr) {
121+
return -ENOMEM;
122+
}
123+
memset(ptr, 0, len);
124+
struct map* new_map = (struct map*)((char*)ptr + len);
125+
new_map->addr = ptr;
126+
new_map->length = len;
127+
LOCK(lock);
128+
new_map->next = mappings;
129+
mappings = new_map;
130+
UNLOCK(lock);
131+
return (long)ptr;
132+
}
71133
return -ENOSYS;
72134
}
73135

tests/core/test_mmap.c

+7-2
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,17 @@ int main(int argc, char* argv[]) {
1717
assert(getpagesize() == 65536);
1818
assert(sysconf(_SC_PAGESIZE) == 65536);
1919

20+
int* maps[10];
2021
for (int i = 0; i < 10; i++) {
2122
int* map = (int*)mmap(0, 5000, PROT_READ | PROT_WRITE,
2223
MAP_SHARED | MAP_ANON, -1, 0);
2324
assert(map != MAP_FAILED);
2425
assert(((long)map) % 65536 == 0); // aligned
25-
assert(munmap(map, 5000) == 0);
26+
maps[i] = map;
27+
}
28+
29+
for (int i = 0; i < 10; i++) {
30+
assert(munmap(maps[i], 5000) == 0);
2631
}
2732

2833
const int NUM_BYTES = 8 * 1024 * 1024;
@@ -44,6 +49,6 @@ int main(int argc, char* argv[]) {
4449

4550
assert(munmap(map, NUM_BYTES) == 0);
4651

47-
printf("hello,world");
52+
printf("hello,world\n");
4853
return 0;
4954
}

tests/test_core.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -6061,13 +6061,12 @@ def test_static_variable(self):
60616061
def test_fakestat(self):
60626062
self.do_core_test('test_fakestat.c')
60636063

6064+
@also_with_standalone_wasm()
60646065
def test_mmap(self):
60656066
# ASan needs more memory, but that is set up separately
60666067
if '-fsanitize=address' not in self.emcc_args:
60676068
self.set_setting('INITIAL_MEMORY', '128mb')
60686069

6069-
# needs to flush stdio streams
6070-
self.set_setting('EXIT_RUNTIME')
60716070
self.do_core_test('test_mmap.c')
60726071

60736072
def test_mmap_file(self):

0 commit comments

Comments
 (0)