Skip to content

Commit

Permalink
Make boundary check behavior configurable
Browse files Browse the repository at this point in the history
Change-Id: Id06b5f9f8b9ef4e29ed0bf70d9b48c5a70ea2853
  • Loading branch information
no1wudi committed Jun 29, 2023
1 parent ab96e01 commit edefb64
Show file tree
Hide file tree
Showing 14 changed files with 223 additions and 30 deletions.
4 changes: 4 additions & 0 deletions build-scripts/config_common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -396,3 +396,7 @@ if (WAMR_DISABLE_WRITE_GS_BASE EQUAL 1)
add_definitions (-DWASM_DISABLE_WRITE_GS_BASE=1)
message (" Write linear memory base addr to x86 GS register disabled")
endif ()
if (WAMR_CONFIGUABLE_BOUNDS_CHECKS EQUAL 1)
add_definitions (-DWASM_CONFIGURABLE_BOUNDS_CHECKS=1)
message (" Configurable bounds checks enabled")
endif ()
6 changes: 6 additions & 0 deletions core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -456,4 +456,10 @@
#define WASM_DISABLE_WRITE_GS_BASE 0
#endif

/* Configurable bounds check */

#ifndef WASM_CONFIGURABLE_BOUNDS_CHECK
#define WASM_CONFIGURABLE_BOUNDS_CHECK 0
#endif

#endif /* end of _CONFIG_H_ */
4 changes: 4 additions & 0 deletions core/iwasm/aot/aot_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ typedef struct AOTFunctionInstance {

typedef struct AOTModuleInstanceExtra {
CApiFuncImport *c_api_func_imports;
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
/* Disable bounds check or not */
bool disable_bounds_checks;
#endif
} AOTModuleInstanceExtra;

#if defined(OS_ENABLE_HW_BOUND_CHECK) && defined(BH_PLATFORM_WINDOWS)
Expand Down
57 changes: 55 additions & 2 deletions core/iwasm/common/wasm_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "wasm_runtime_common.h"
#include "../interpreter/wasm_runtime.h"
#include "../aot/aot_runtime.h"
#include "bh_platform.h"
#include "mem_alloc.h"

Expand Down Expand Up @@ -269,6 +270,10 @@ wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst_comm,
bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
|| module_inst_comm->module_type == Wasm_Module_AoT);

if (!wasm_runtime_is_bounds_checks_enabled(module_inst_comm)) {
return true;
}

memory_inst = wasm_get_default_memory(module_inst);
if (!memory_inst) {
goto fail;
Expand Down Expand Up @@ -299,6 +304,10 @@ wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm,
bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
|| module_inst_comm->module_type == Wasm_Module_AoT);

if (!wasm_runtime_is_bounds_checks_enabled(module_inst_comm)) {
return true;
}

if (!wasm_runtime_get_app_addr_range(module_inst_comm, app_str_offset, NULL,
&app_end_offset))
goto fail;
Expand Down Expand Up @@ -327,6 +336,10 @@ wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst_comm,
bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
|| module_inst_comm->module_type == Wasm_Module_AoT);

if (!wasm_runtime_is_bounds_checks_enabled(module_inst_comm)) {
return true;
}

memory_inst = wasm_get_default_memory(module_inst);
if (!memory_inst) {
goto fail;
Expand Down Expand Up @@ -354,19 +367,32 @@ wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst_comm,
WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
WASMMemoryInstance *memory_inst;
uint8 *addr;
bool bounds_checks;

bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
|| module_inst_comm->module_type == Wasm_Module_AoT);

bounds_checks = wasm_runtime_is_bounds_checks_enabled(module_inst_comm);

memory_inst = wasm_get_default_memory(module_inst);
if (!memory_inst) {
return NULL;
}

addr = memory_inst->memory_data + app_offset;

if (memory_inst->memory_data <= addr && addr < memory_inst->memory_data_end)
if (bounds_checks) {
if (memory_inst->memory_data <= addr
&& addr < memory_inst->memory_data_end) {

return addr;
}
}
/* If bound checks is disabled, and app_offset is not NULL,
return the address directly */
else if (app_offset != 0) {
return addr;
}

return NULL;
}
Expand All @@ -378,17 +404,28 @@ wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst_comm,
WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
WASMMemoryInstance *memory_inst;
uint8 *addr = (uint8 *)native_ptr;
bool bounds_checks;

bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
|| module_inst_comm->module_type == Wasm_Module_AoT);

bounds_checks = wasm_runtime_is_bounds_checks_enabled(module_inst_comm);

memory_inst = wasm_get_default_memory(module_inst);
if (!memory_inst) {
return 0;
}

if (memory_inst->memory_data <= addr && addr < memory_inst->memory_data_end)
if (bounds_checks) {
if (memory_inst->memory_data <= addr
&& addr < memory_inst->memory_data_end)
return (uint32)(addr - memory_inst->memory_data);
}
/* If bound checks is disabled, and addr is not NULL,
return the address directly */
else if (addr != NULL) {
return (uint32)(addr - memory_inst->memory_data);
}

return 0;
}
Expand Down Expand Up @@ -460,13 +497,29 @@ wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
{
WASMMemoryInstance *memory_inst = wasm_get_default_memory(module_inst);
uint8 *native_addr;
bool bounds_checks;

if (!memory_inst) {
goto fail;
}

bounds_checks =
wasm_runtime_is_bounds_checks_enabled((wasm_module_inst_t)module_inst);

native_addr = memory_inst->memory_data + app_buf_addr;

if (!bounds_checks) {
/* If bound checks is disabled, and app_buf_addr is not NULL,
return the address directly */
if (app_buf_addr != 0) {
*p_native_addr = (void *)native_addr;
}
else {
*p_native_addr = NULL;
}
return true;
}

/* No need to check the app_offset and buf_size if memory access
boundary check with hardware trap is enabled */
#ifndef OS_ENABLE_HW_BOUND_CHECK
Expand Down
44 changes: 44 additions & 0 deletions core/iwasm/common/wasm_runtime_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -2482,6 +2482,50 @@ wasm_runtime_get_custom_data(WASMModuleInstanceCommon *module_inst_comm)
return module_inst->custom_data;
}

#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
void
wasm_runtime_set_bounds_checks(WASMModuleInstanceCommon *module_inst,
bool enable)
{
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) {
((WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)->e)
->disable_bounds_checks = enable ? false : true;
}
#endif

#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT) {
((AOTModuleInstanceExtra *)((AOTModuleInstance *)module_inst)->e)
->disable_bounds_checks = enable ? false : true;
}
#endif
}
#endif

bool
wasm_runtime_is_bounds_checks_enabled(WASMModuleInstanceCommon *module_inst)
{
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) {
return !((WASMModuleInstanceExtra *)((WASMModuleInstance *)module_inst)
->e)
->disable_bounds_checks;
}
#endif

#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT) {
return !((AOTModuleInstanceExtra *)((WASMModuleInstance *)module_inst)
->e)
->disable_bounds_checks;
}
#endif
#endif
return true;
}

uint32
wasm_runtime_module_malloc_internal(WASMModuleInstanceCommon *module_inst,
WASMExecEnv *exec_env, uint32 size,
Expand Down
10 changes: 10 additions & 0 deletions core/iwasm/common/wasm_runtime_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,16 @@ wasm_runtime_set_user_data(WASMExecEnv *exec_env, void *user_data);
WASM_RUNTIME_API_EXTERN void *
wasm_runtime_get_user_data(WASMExecEnv *exec_env);

#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN void
wasm_runtime_set_bounds_checks(WASMModuleInstanceCommon *module_inst,
bool enable);
#endif
/* See wasm_export.h for description */
WASM_RUNTIME_API_EXTERN bool
wasm_runtime_is_bounds_checks_enabled(WASMModuleInstanceCommon *module_inst);

#ifdef OS_ENABLE_HW_BOUND_CHECK
/* Access exception check guard page to trigger the signal handler */
void
Expand Down
19 changes: 19 additions & 0 deletions core/iwasm/include/wasm_export.h
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,25 @@ wasm_runtime_set_custom_data(wasm_module_inst_t module_inst,
WASM_RUNTIME_API_EXTERN void *
wasm_runtime_get_custom_data(wasm_module_inst_t module_inst);

/**
* Set the memory bounds check flag of a WASM module instance.
*
* @param module_inst the WASM module instance
* @param enable the flag to enable/disable the memory bounds check
*/
WASM_RUNTIME_API_EXTERN void
wasm_runtime_set_bounds_checks(wasm_module_inst_t module_inst,
bool enable);
/**
* Check if the memory bounds check flag is enabled for a WASM module instance.
*
* @param module_inst the WASM module instance
*
* @return true if the memory bounds check flag is enabled, false otherwise
*/
WASM_RUNTIME_API_EXTERN bool
wasm_runtime_is_bounds_checks_enabled(
wasm_module_inst_t module_inst);
/**
* Allocate memory from the heap of WASM module instance
*
Expand Down
43 changes: 25 additions & 18 deletions core/iwasm/interpreter/wasm_interp_classic.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,26 +41,28 @@ typedef float64 CellType_F64;

#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
#define CHECK_MEMORY_OVERFLOW(bytes) \
do { \
uint64 offset1 = (uint64)offset + (uint64)addr; \
if (offset1 + bytes <= (uint64)get_linear_mem_size()) \
/* If offset1 is in valid range, maddr must also \
be in valid range, no need to check it again. */ \
maddr = memory->memory_data + offset1; \
else \
goto out_of_bounds; \
#define CHECK_MEMORY_OVERFLOW(bytes) \
do { \
uint64 offset1 = (uint64)offset + (uint64)addr; \
if (disable_bounds_checks \
|| offset1 + bytes <= (uint64)get_linear_mem_size()) \
/* If offset1 is in valid range, maddr must also \
be in valid range, no need to check it again. */ \
maddr = memory->memory_data + offset1; \
else \
goto out_of_bounds; \
} while (0)

#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
do { \
uint64 offset1 = (uint32)(start); \
if (offset1 + bytes <= (uint64)get_linear_mem_size()) \
/* App heap space is not valid space for \
bulk memory operation */ \
maddr = memory->memory_data + offset1; \
else \
goto out_of_bounds; \
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
do { \
uint64 offset1 = (uint32)(start); \
if (disable_bounds_checks \
|| offset1 + bytes <= (uint64)get_linear_mem_size()) \
/* App heap space is not valid space for \
bulk memory operation */ \
maddr = memory->memory_data + offset1; \
else \
goto out_of_bounds; \
} while (0)
#else
#define CHECK_MEMORY_OVERFLOW(bytes) \
Expand Down Expand Up @@ -1174,6 +1176,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint8 local_type, *global_addr;
uint32 cache_index, type_index, param_cell_num, cell_num;
uint8 value_type;
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
bool disable_bounds_checks = module->e->disable_bounds_checks;
#else
bool disable_bounds_checks = false;
#endif

#if WASM_ENABLE_DEBUG_INTERP != 0
uint8 *frame_ip_orig = NULL;
Expand Down
26 changes: 16 additions & 10 deletions core/iwasm/interpreter/wasm_interp_fast.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,24 @@ typedef float64 CellType_F64;
#define CHECK_MEMORY_OVERFLOW(bytes) \
do { \
uint64 offset1 = (uint64)offset + (uint64)addr; \
if (offset1 + bytes <= (uint64)get_linear_mem_size()) \
if (disable_bounds_checks \
|| offset1 + bytes <= (uint64)get_linear_mem_size()) \
/* If offset1 is in valid range, maddr must also \
be in valid range, no need to check it again. */ \
maddr = memory->memory_data + offset1; \
else \
goto out_of_bounds; \
} while (0)

#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
do { \
uint64 offset1 = (uint32)(start); \
if (offset1 + bytes <= get_linear_mem_size()) \
/* App heap space is not valid space for \
bulk memory operation */ \
maddr = memory->memory_data + offset1; \
else \
goto out_of_bounds; \
#define CHECK_BULK_MEMORY_OVERFLOW(start, bytes, maddr) \
do { \
uint64 offset1 = (uint32)(start); \
if (disable_bounds_checks || offset1 + bytes <= get_linear_mem_size()) \
/* App heap space is not valid space for \
bulk memory operation */ \
maddr = memory->memory_data + offset1; \
else \
goto out_of_bounds; \
} while (0)
#else
#define CHECK_MEMORY_OVERFLOW(bytes) \
Expand Down Expand Up @@ -1199,6 +1200,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint8 *maddr = NULL;
uint32 local_idx, local_offset, global_idx;
uint8 opcode, local_type, *global_addr;
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
bool disable_bounds_checks = module->e->disable_bounds_checks;
#else
bool disable_bounds_checks = false;
#endif

#if WASM_ENABLE_LABELS_AS_VALUES != 0
#define HANDLE_OPCODE(op) &&HANDLE_##op
Expand Down
4 changes: 4 additions & 0 deletions core/iwasm/interpreter/wasm_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ typedef struct WASMModuleInstanceExtra {
&& WASM_ENABLE_LAZY_JIT != 0)
WASMModuleInstance *next;
#endif
#if WASM_CONFIGUABLE_BOUNDS_CHECKS != 0
/* Disable bounds check or not */
bool disable_bounds_checks;
#endif
} WASMModuleInstanceExtra;

struct AOTFuncPerfProfInfo;
Expand Down
12 changes: 12 additions & 0 deletions doc/perf_tune.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,15 @@ wasm_runtime_dump_pgo_prof_data_to_buf(wasm_module_inst_t module_inst, char *buf
6. Run the optimized aot_file: `iwasm <aot_file>`.
Developer can refer to the `test_pgo.sh` files under each benchmark folder for more details, e.g. [test_pgo.sh](../tests/benchmarks/coremark/test_pgo.sh) of CoreMark benchmark.
## 6. Disable the memory boundary check
Please notice that this method is not a general solution since it may lead to security issues. And only boost the performance for some platforms in AOT mode and don't support hardware trap for memory boundary check.
1. Build WAMR with `-DWAMR_CONFIGUABLE_BOUNDS_CHECKS=1` option.
2. Compile AOT module by wamrc with `--bounds-check=0` option.
3. Run the AOT module by iwasm with `--disable-bounds-checks` option.
> Note: The size of AOT file will be much smaller than the default, and some tricks are possible such as let the wasm application access the memory of host os directly.
Loading

0 comments on commit edefb64

Please sign in to comment.