diff options
author | Shravan Narayan <shravanrn@gmail.com> | 2023-04-10 19:55:37 -0400 |
---|---|---|
committer | Shravan Narayan <shravanrn@gmail.com> | 2023-04-12 00:54:37 -0400 |
commit | c83f9b02f67adbc20499fc4821941cdf5011dc8a (patch) | |
tree | 89ebe2f4928ac0ab5d597d1e84c3748454dc0de5 /wasm2c | |
parent | 8b8428b5c49aa89a3512452984818a273224143f (diff) | |
download | wabt-c83f9b02f67adbc20499fc4821941cdf5011dc8a.tar.gz wabt-c83f9b02f67adbc20499fc4821941cdf5011dc8a.tar.bz2 wabt-c83f9b02f67adbc20499fc4821941cdf5011dc8a.zip |
wasm2c: Separate the macros for allocation and bounds checks strategies
Diffstat (limited to 'wasm2c')
-rw-r--r-- | wasm2c/examples/fac/fac.c | 2 | ||||
-rw-r--r-- | wasm2c/wasm-rt-impl.c | 67 | ||||
-rw-r--r-- | wasm2c/wasm-rt-impl.h | 2 | ||||
-rw-r--r-- | wasm2c/wasm-rt.h | 120 |
4 files changed, 138 insertions, 53 deletions
diff --git a/wasm2c/examples/fac/fac.c b/wasm2c/examples/fac/fac.c index 2102f751..970abbe1 100644 --- a/wasm2c/examples/fac/fac.c +++ b/wasm2c/examples/fac/fac.c @@ -56,7 +56,7 @@ static inline bool func_types_eq(const wasm_rt_func_type_t a, TRAP(OOB); #endif -#if WASM_RT_MEMCHECK_SIGNAL_HANDLER +#if WASM_RT_MEMCHECK_GUARD_PAGES #define MEMCHECK(mem, a, t) #else #define MEMCHECK(mem, a, t) RANGE_CHECK(mem, a, sizeof(t)) diff --git a/wasm2c/wasm-rt-impl.c b/wasm2c/wasm-rt-impl.c index 357e5b14..8e4823f0 100644 --- a/wasm2c/wasm-rt-impl.c +++ b/wasm2c/wasm-rt-impl.c @@ -25,8 +25,7 @@ #include <stdlib.h> #include <string.h> -#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !WASM_RT_SKIP_SIGNAL_RECOVERY && \ - !defined(_WIN32) +#if WASM_RT_INSTALL_SIGNAL_HANDLER && !defined(_WIN32) #include <signal.h> #include <unistd.h> #endif @@ -45,7 +44,7 @@ #define PAGE_SIZE 65536 #define MAX_EXCEPTION_SIZE PAGE_SIZE -#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !WASM_RT_SKIP_SIGNAL_RECOVERY +#if WASM_RT_INSTALL_SIGNAL_HANDLER static bool g_signal_handler_installed = false; #ifdef _WIN32 static void* g_sig_handler_handle = 0; @@ -167,7 +166,7 @@ static void os_print_last_error(const char* msg) { } } -#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !WASM_RT_SKIP_SIGNAL_RECOVERY +#if WASM_RT_INSTALL_SIGNAL_HANDLER static LONG os_signal_handler(PEXCEPTION_POINTERS info) { if (info->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { @@ -211,7 +210,7 @@ static void os_print_last_error(const char* msg) { perror(msg); } -#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !WASM_RT_SKIP_SIGNAL_RECOVERY +#if WASM_RT_INSTALL_SIGNAL_HANDLER static void os_signal_handler(int sig, siginfo_t* si, void* unused) { if (si->si_code == SEGV_ACCERR) { wasm_rt_trap(WASM_RT_TRAP_OOB); @@ -238,7 +237,7 @@ static void os_install_signal_handler(void) { } struct sigaction sa; - memset(&sa , '\0', sizeof(sa)); + memset(&sa, '\0', sizeof(sa)); sa.sa_flags = SA_SIGINFO | SA_ONSTACK; sigemptyset(&sa.sa_mask); sa.sa_sigaction = os_signal_handler; @@ -253,7 +252,7 @@ static void os_install_signal_handler(void) { static void os_cleanup_signal_handler(void) { /* Undo what was done in os_install_signal_handler */ struct sigaction sa; - memset(&sa , '\0', sizeof(sa)); + memset(&sa, '\0', sizeof(sa)); sa.sa_handler = SIG_DFL; if (sigaction(SIGSEGV, &sa, NULL) != 0 || sigaction(SIGBUS, &sa, NULL)) { perror("sigaction failed"); @@ -272,7 +271,7 @@ static void os_cleanup_signal_handler(void) { #endif void wasm_rt_init(void) { -#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !WASM_RT_SKIP_SIGNAL_RECOVERY +#if WASM_RT_INSTALL_SIGNAL_HANDLER if (!g_signal_handler_installed) { g_signal_handler_installed = true; os_install_signal_handler(); @@ -281,7 +280,7 @@ void wasm_rt_init(void) { } bool wasm_rt_is_initialized(void) { -#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !WASM_RT_SKIP_SIGNAL_RECOVERY +#if WASM_RT_INSTALL_SIGNAL_HANDLER return g_signal_handler_installed; #else return true; @@ -289,23 +288,48 @@ bool wasm_rt_is_initialized(void) { } void wasm_rt_free(void) { -#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !WASM_RT_SKIP_SIGNAL_RECOVERY +#if WASM_RT_INSTALL_SIGNAL_HANDLER os_cleanup_signal_handler(); #endif } +#if WASM_RT_USE_MMAP + +static uint64_t get_allocation_size_for_mmap(wasm_rt_memory_t* memory) { + /* Reserve 8GiB. */ + assert(!memory->is64 && + "memory64 is not yet compatible with WASM_RT_USE_MMAP"); +#if WASM_RT_MEMCHECK_GUARD_PAGES + /* Reserve 8GiB. */ + const uint64_t max_size = 0x200000000ul; + return max_size; +#else + if (memory->max_pages != 0) { + const uint64_t max_size = memory->max_pages * PAGE_SIZE; + return max_size; + } + + /* Reserve 4GiB. */ + const uint64_t max_size = 0x100000000ul; + return max_size; +#endif +} + +#endif + void wasm_rt_allocate_memory(wasm_rt_memory_t* memory, uint64_t initial_pages, uint64_t max_pages, bool is64) { uint64_t byte_length = initial_pages * PAGE_SIZE; -#if WASM_RT_MEMCHECK_SIGNAL_HANDLER - /* Reserve 8GiB. */ - assert( - !is64 && - "memory64 is not yet compatible with WASM_RT_MEMCHECK_SIGNAL_HANDLER"); - void* addr = os_mmap(0x200000000ul); + memory->size = byte_length; + memory->pages = initial_pages; + memory->max_pages = max_pages; + memory->is64 = is64; +#if WASM_RT_USE_MMAP + const uint64_t mmap_size = get_allocation_size_for_mmap(memory); + void* addr = os_mmap(mmap_size); if (!addr) { os_print_last_error("os_mmap failed."); abort(); @@ -319,10 +343,6 @@ void wasm_rt_allocate_memory(wasm_rt_memory_t* memory, #else memory->data = calloc(byte_length, 1); #endif - memory->size = byte_length; - memory->pages = initial_pages; - memory->max_pages = max_pages; - memory->is64 = is64; } uint64_t wasm_rt_grow_memory(wasm_rt_memory_t* memory, uint64_t delta) { @@ -337,7 +357,7 @@ uint64_t wasm_rt_grow_memory(wasm_rt_memory_t* memory, uint64_t delta) { uint64_t old_size = old_pages * PAGE_SIZE; uint64_t new_size = new_pages * PAGE_SIZE; uint64_t delta_size = delta * PAGE_SIZE; -#if WASM_RT_MEMCHECK_SIGNAL_HANDLER +#if WASM_RT_USE_MMAP uint8_t* new_data = memory->data; int ret = os_mprotect(new_data + old_size, delta_size); if (ret != 0) { @@ -363,8 +383,9 @@ uint64_t wasm_rt_grow_memory(wasm_rt_memory_t* memory, uint64_t delta) { } void wasm_rt_free_memory(wasm_rt_memory_t* memory) { -#if WASM_RT_MEMCHECK_SIGNAL_HANDLER - os_munmap(memory->data, memory->size); // ignore error? +#if WASM_RT_USE_MMAP + const uint64_t mmap_size = get_allocation_size_for_mmap(memory); + os_munmap(memory->data, mmap_size); // ignore error? #else free(memory->data); #endif diff --git a/wasm2c/wasm-rt-impl.h b/wasm2c/wasm-rt-impl.h index a05a9f8c..088619f4 100644 --- a/wasm2c/wasm-rt-impl.h +++ b/wasm2c/wasm-rt-impl.h @@ -30,7 +30,7 @@ extern "C" { /** A setjmp buffer used for handling traps. */ extern WASM_RT_THREAD_LOCAL wasm_rt_jmp_buf g_wasm_rt_jmp_buf; -#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !defined(_WIN32) +#if WASM_RT_INSTALL_SIGNAL_HANDLER && !defined(_WIN32) #define WASM_RT_LONGJMP_UNCHECKED(buf, val) siglongjmp(buf, val) #else #define WASM_RT_LONGJMP_UNCHECKED(buf, val) longjmp(buf, val) diff --git a/wasm2c/wasm-rt.h b/wasm2c/wasm-rt.h index abdd0d0d..03f78834 100644 --- a/wasm2c/wasm-rt.h +++ b/wasm2c/wasm-rt.h @@ -60,52 +60,116 @@ extern "C" { #endif /** - * Enable memory checking via a signal handler via the following definition: - * - * #define WASM_RT_MEMCHECK_SIGNAL_HANDLER 1 - * - * This is usually 10%-25% faster, but requires OS-specific support. + * Backward compatibility: Convert the previously exposed + * WASM_RT_MEMCHECK_SIGNAL_HANDLER macro to the ALLOCATION and CHECK macros that + * are now used. */ +#if defined(WASM_RT_MEMCHECK_SIGNAL_HANDLER) -#ifndef WASM_RT_SKIP_SIGNAL_RECOVERY -#define WASM_RT_SKIP_SIGNAL_RECOVERY 0 +#if WASM_RT_MEMCHECK_SIGNAL_HANDLER +#define WASM_RT_USE_MMAP 1 +#define WASM_RT_MEMCHECK_GUARD_PAGES 1 +#else +#define WASM_RT_USE_MMAP 0 +#define WASM_RT_MEMCHECK_BOUNDS_CHECK 1 #endif -/** Signal handler not supported on 32-bit platforms. */ -#if UINTPTR_MAX > 0xffffffff - -#define WASM_RT_SIGNAL_RECOVERY_SUPPORTED 1 +#warning \ + "WASM_RT_MEMCHECK_SIGNAL_HANDLER has been deprecated in favor of WASM_RT_USE_MMAP and WASM_RT_MEMORY_CHECK_* macros" +#endif -/* Signal handler is supported. Use it by default. */ -#ifndef WASM_RT_MEMCHECK_SIGNAL_HANDLER -#ifdef SUPPORT_MEMORY64 -#define WASM_RT_MEMCHECK_SIGNAL_HANDLER 0 +/** + * Specify if we use OR mmap/mprotect (+ Windows equivalents) OR malloc/realloc + * for the Wasm memory allocation and growth. mmap/mprotect guarantees memory + * will grow without being moved, while malloc ensures the virtual memory is + * consumed only as needed, but may relocate the memory to handle memory + * fragmentation. + * + * This defaults to malloc on 32-bit platforms or if memory64 support is needed. + * It defaults to mmap on 64-bit platforms assuming memory64 support is not + * needed (so we can use the guard based range checks below). + */ +#ifndef WASM_RT_USE_MMAP +#if UINTPTR_MAX > 0xffffffff && !SUPPORT_MEMORY64 +#define WASM_RT_USE_MMAP 1 #else -#define WASM_RT_MEMCHECK_SIGNAL_HANDLER 1 +#define WASM_RT_USE_MMAP 0 #endif #endif +/** + * Set the range checking strategy for Wasm memories. + * + * GUARD_PAGES: memory accesses rely on unmapped pages/guard pages to trap + * out-of-bound accesses. + * + * BOUNDS_CHECK: memory accesses are checked with explicit bounds checks. + * + * This defaults to GUARD_PAGES as this is the fasest option, iff the + * requirements of GUARD_PAGES --- 64-bit platforms, MMAP allocation strategy, + * no 64-bit memories --- are met. This falls back to BOUNDS otherwise. + */ + +// Check if Guard checks are supported +#if UINTPTR_MAX > 0xffffffff && WASM_RT_USE_MMAP && !SUPPORT_MEMORY64 +#define WASM_RT_GUARD_PAGES_SUPPORTED 1 +#else +#define WASM_RT_GUARD_PAGES_SUPPORTED 0 +#endif + +// Specify defaults for memory checks if unspecified +#if !defined(WASM_RT_MEMCHECK_GUARD_PAGES) && \ + !defined(WASM_RT_MEMCHECK_BOUNDS_CHECK) +#if WASM_RT_GUARD_PAGES_SUPPORTED +#define WASM_RT_MEMCHECK_GUARD_PAGES 1 #else -#define WASM_RT_SIGNAL_RECOVERY_SUPPORTED 0 +#define WASM_RT_MEMCHECK_BOUNDS_CHECK 1 +#endif +#endif + +// Ensure the macros are defined +#ifndef WASM_RT_MEMCHECK_GUARD_PAGES +#define WASM_RT_MEMCHECK_GUARD_PAGES 0 +#endif +#ifndef WASM_RT_MEMCHECK_BOUNDS_CHECK +#define WASM_RT_MEMCHECK_BOUNDS_CHECK 0 +#endif -/* Signal handler is not supported. */ -#ifndef WASM_RT_MEMCHECK_SIGNAL_HANDLER -#define WASM_RT_MEMCHECK_SIGNAL_HANDLER 0 +// Sanity check the use of guard pages +#if WASM_RT_MEMCHECK_GUARD_PAGES && !WASM_RT_GUARD_PAGES_SUPPORTED +#error \ + "WASM_RT_MEMCHECK_GUARD_PAGES not supported on this platform/configuration" #endif +#if WASM_RT_MEMCHECK_GUARD_PAGES && WASM_RT_MEMCHECK_BOUNDS_CHECK +#error \ + "Cannot use both WASM_RT_MEMCHECK_GUARD_PAGES and WASM_RT_MEMCHECK_BOUNDS_CHECK" + +#elif !WASM_RT_MEMCHECK_GUARD_PAGES && !WASM_RT_MEMCHECK_BOUNDS_CHECK +#error \ + "Must choose at least one from WASM_RT_MEMCHECK_GUARD_PAGES and WASM_RT_MEMCHECK_BOUNDS_CHECK" +#endif + +/** + * Some configurations above require the Wasm runtime to install a signal + * handler. However, this can be explicitly disallowed by the host using + * WASM_RT_SKIP_SIGNAL_RECOVERY. In this case, when the wasm code encounters an + * OOB access, it may either trap or abort. + */ +#ifndef WASM_RT_SKIP_SIGNAL_RECOVERY +#define WASM_RT_SKIP_SIGNAL_RECOVERY 0 #endif -#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && \ - (!WASM_RT_SKIP_SIGNAL_RECOVERY && !WASM_RT_SIGNAL_RECOVERY_SUPPORTED) -/* The signal handler is not supported, error out if the user was trying to - * enable it. */ -#error "Signal handler is not supported for this OS/Architecture!" +#if WASM_RT_MEMCHECK_GUARD_PAGES && !WASM_RT_SKIP_SIGNAL_RECOVERY +#define WASM_RT_INSTALL_SIGNAL_HANDLER 1 +#else +#define WASM_RT_INSTALL_SIGNAL_HANDLER 0 #endif #ifndef WASM_RT_USE_STACK_DEPTH_COUNT /* The signal handler on POSIX can detect call stack overflows. On windows, or * platforms without a signal handler, we use stack depth counting. */ -#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !defined(_WIN32) +#if WASM_RT_INSTALL_SIGNAL_HANDLER && !defined(_WIN32) #define WASM_RT_USE_STACK_DEPTH_COUNT 0 #else #define WASM_RT_USE_STACK_DEPTH_COUNT 1 @@ -138,7 +202,7 @@ extern WASM_RT_THREAD_LOCAL uint32_t wasm_rt_call_stack_depth; #define WASM_RT_NO_RETURN __attribute__((noreturn)) #endif -#if defined(__APPLE__) && WASM_RT_MEMCHECK_SIGNAL_HANDLER +#if defined(__APPLE__) && WASM_RT_INSTALL_SIGNAL_HANDLER #define WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 1 #else #define WASM_RT_MERGED_OOB_AND_EXHAUSTION_TRAPS 0 @@ -323,7 +387,7 @@ uint32_t wasm_rt_exception_size(void); */ void* wasm_rt_exception(void); -#if WASM_RT_MEMCHECK_SIGNAL_HANDLER && !defined(_WIN32) +#if WASM_RT_INSTALL_SIGNAL_HANDLER && !defined(_WIN32) #define WASM_RT_SETJMP_SETBUF(buf) sigsetjmp(buf, 1) #else #define WASM_RT_SETJMP_SETBUF(buf) setjmp(buf) |