Skip to content

Commit

Permalink
Implement MAP_ANONYMOUS on top of malloc in STANDALONE_WASM mode
Browse files Browse the repository at this point in the history
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
  • Loading branch information
sbc100 committed Feb 15, 2022
1 parent aa147e7 commit d86afde
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 7 deletions.
70 changes: 66 additions & 4 deletions system/lib/standalone/standalone.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <malloc.h>
#include <time.h>
#include <unistd.h>

Expand All @@ -17,6 +19,8 @@
#include <wasi/api.h>
#include <wasi/wasi-helpers.h>

#include "lock.h"

/*
* WASI support code. These are compiled with the program, and call out
* using wasi APIs, which can be provided either by a wasi VM or by our
Expand Down Expand Up @@ -59,15 +63,73 @@ int clock_getres(clockid_t clk_id, struct timespec *tp) {
// mmap support is nonexistent. TODO: emulate simple mmaps using
// stdio + malloc, which is slow but may help some things?

long __map_file(int x, int y) {
return -ENOSYS;
const unsigned char * __map_file(const char *pathname, size_t *size) {
errno = ENOSYS;
return NULL;
}

long __syscall_munmap(int x, int y) {
return -ENOSYS;
struct map {
void* addr;
long length;
struct map* next;
} __attribute__((aligned (1)));

static volatile int lock[1];
static struct map* mappings;

long __syscall_munmap(long addr, long length) {
LOCK(lock);
struct map* map = mappings;
struct map* prev = NULL;
while (map) {
if (map->addr == (void*)addr) {
// We don't support partial munmapping.
if (map->length != length) {
map = NULL;
break;
}
if (prev) {
prev->next = map->next;
} else {
mappings = map->next;
}
break;
}
prev = map;
map = map->next;
}
UNLOCK(lock);

if (map) {
// Release the memory.
free(map->addr);
// Success!
return 0;
}

errno = EINVAL;
return -1;
}

long __syscall_mmap2(long addr, long len, long prot, long flags, long fd, long off) {
// MAP_ANONYMOUS (aka MAP_ANON) isn't actually defined by POSIX spec,
// but it is widely used way to allocate memory pages on Linux, BSD and Mac.
// In this case fd argument is ignored.
if (flags & MAP_ANONYMOUS) {
void* ptr = memalign(WASM_PAGE_SIZE, len + sizeof(struct map));
if (!ptr) {
return -ENOMEM;
}
memset(ptr, 0, len);
struct map* new_map = (struct map*)((char*)ptr + len);
new_map->addr = ptr;
new_map->length = len;
LOCK(lock);
new_map->next = mappings;
mappings = new_map;
UNLOCK(lock);
return (long)ptr;
}
return -ENOSYS;
}

Expand Down
2 changes: 1 addition & 1 deletion tests/core/test_mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ int main(int argc, char* argv[]) {

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

printf("hello,world");
printf("hello,world\n");
return 0;
}
3 changes: 1 addition & 2 deletions tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -6058,13 +6058,12 @@ def test_static_variable(self):
def test_fakestat(self):
self.do_core_test('test_fakestat.c')

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

# needs to flush stdio streams
self.set_setting('EXIT_RUNTIME')
self.do_core_test('test_mmap.c')

def test_mmap_file(self):
Expand Down

0 comments on commit d86afde

Please sign in to comment.