feat: Add instruction metering for interpreter (#4122)

- add instruction metering support with execution limit
- initialize instruction execution limit in exec_env
- docs: add instruction metering section to build_wamr documentation
This commit is contained in:
Alix ANNERAUD
2025-05-26 10:16:42 +02:00
committed by GitHub
parent 6659a312cf
commit c018b8ab98
10 changed files with 104 additions and 3 deletions

View File

@ -1516,10 +1516,13 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
} \
os_mutex_unlock(&exec_env->wait_lock); \
} \
CHECK_INSTRUCTION_LIMIT(); \
goto *handle_table[*frame_ip++]; \
} while (0)
#else
#define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH()
#define HANDLE_OP_END() \
CHECK_INSTRUCTION_LIMIT(); \
FETCH_OPCODE_AND_DISPATCH()
#endif
#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
@ -1542,9 +1545,12 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
} \
os_mutex_unlock(&exec_env->wait_lock); \
} \
CHECK_INSTRUCTION_LIMIT(); \
continue;
#else
#define HANDLE_OP_END() continue
#define HANDLE_OP_END() \
CHECK_INSTRUCTION_LIMIT(); \
continue;
#endif
#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
@ -1562,6 +1568,18 @@ get_global_addr(uint8 *global_data, WASMGlobalInstance *global)
#endif
}
#if WASM_ENABLE_INSTRUCTION_METERING != 0
#define CHECK_INSTRUCTION_LIMIT() \
if (instructions_left == 0) { \
wasm_set_exception(module, "instruction limit exceeded"); \
goto got_exception; \
} \
else if (instructions_left > 0) \
instructions_left--;
#else
#define CHECK_INSTRUCTION_LIMIT() (void)0
#endif
static void
wasm_interp_call_func_bytecode(WASMModuleInstance *module,
WASMExecEnv *exec_env,
@ -1605,6 +1623,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint32 local_idx, local_offset, global_idx;
uint8 local_type, *global_addr;
uint32 cache_index, type_index, param_cell_num, cell_num;
#if WASM_ENABLE_INSTRUCTION_METERING != 0
int instructions_left = -1;
if (exec_env) {
instructions_left = exec_env->instructions_to_execute;
}
#endif
#if WASM_ENABLE_EXCE_HANDLING != 0
int32_t exception_tag_index;
#endif

View File

@ -105,6 +105,19 @@ typedef float64 CellType_F64;
goto unaligned_atomic; \
} while (0)
#if WASM_ENABLE_INSTRUCTION_METERING != 0
#define CHECK_INSTRUCTION_LIMIT() \
if (instructions_left == 0) { \
wasm_set_exception(module, "instruction limit exceeded"); \
goto got_exception; \
} \
else if (instructions_left > 0) \
instructions_left--;
#else
#define CHECK_INSTRUCTION_LIMIT() (void)0
#endif
static inline uint32
rotl32(uint32 n, uint32 c)
{
@ -1441,6 +1454,7 @@ wasm_interp_dump_op_count()
do { \
const void *p_label_addr = *(void **)frame_ip; \
frame_ip += sizeof(void *); \
CHECK_INSTRUCTION_LIMIT(); \
goto *p_label_addr; \
} while (0)
#else
@ -1452,6 +1466,7 @@ wasm_interp_dump_op_count()
/* int32 relative offset was emitted in 64-bit target */ \
p_label_addr = label_base + (int32)LOAD_U32_WITH_2U16S(frame_ip); \
frame_ip += sizeof(int32); \
CHECK_INSTRUCTION_LIMIT(); \
goto *p_label_addr; \
} while (0)
#else
@ -1462,6 +1477,7 @@ wasm_interp_dump_op_count()
/* uint32 label address was emitted in 32-bit target */ \
p_label_addr = (void *)(uintptr_t)LOAD_U32_WITH_2U16S(frame_ip); \
frame_ip += sizeof(int32); \
CHECK_INSTRUCTION_LIMIT(); \
goto *p_label_addr; \
} while (0)
#endif
@ -1538,6 +1554,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
uint8 *maddr = NULL;
uint32 local_idx, local_offset, global_idx;
uint8 opcode = 0, local_type, *global_addr;
#if WASM_ENABLE_INSTRUCTION_METERING != 0
int instructions_left = -1;
if (exec_env) {
instructions_left = exec_env->instructions_to_execute;
}
#endif
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0