Skip to content

Commit c018b8a

Browse files
authored
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
1 parent 6659a31 commit c018b8a

File tree

10 files changed

+104
-3
lines changed

10 files changed

+104
-3
lines changed

build-scripts/config_common.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,10 @@ if (WAMR_BUILD_AOT_VALIDATOR EQUAL 1)
671671
message (" AOT validator enabled")
672672
add_definitions (-DWASM_ENABLE_AOT_VALIDATOR=1)
673673
endif ()
674+
if (WAMR_BUILD_INSTRUCTION_METERING EQUAL 1)
675+
message (" Instruction metering enabled")
676+
add_definitions (-DWASM_ENABLE_INSTRUCTION_METERING=1)
677+
endif ()
674678

675679
########################################
676680
# Show Phase4 Wasm proposals status.

core/config.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,4 +716,8 @@ unless used elsewhere */
716716
#define WASM_ENABLE_AOT_VALIDATOR 0
717717
#endif
718718

719+
#ifndef WASM_ENABLE_INSTRUCTION_METERING
720+
#define WASM_ENABLE_INSTRUCTION_METERING 0
721+
#endif
722+
719723
#endif /* end of _CONFIG_H_ */

core/iwasm/common/wasm_exec_env.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
8585
wasm_runtime_dump_exec_env_mem_consumption(exec_env);
8686
#endif
8787

88+
#if WASM_ENABLE_INSTRUCTION_METERING != 0
89+
exec_env->instructions_to_execute = -1;
90+
#endif
91+
8892
return exec_env;
8993

9094
#ifdef OS_ENABLE_HW_BOUND_CHECK

core/iwasm/common/wasm_exec_env.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ typedef struct WASMExecEnv {
8787
uint8 *bottom;
8888
} wasm_stack;
8989

90+
#if WASM_ENABLE_INSTRUCTION_METERING != 0
91+
/* instructions to execute */
92+
int instructions_to_execute;
93+
#endif
94+
9095
#if WASM_ENABLE_FAST_JIT != 0
9196
/**
9297
* Cache for

core/iwasm/common/wasm_runtime_common.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2285,6 +2285,15 @@ wasm_runtime_access_exce_check_guard_page()
22852285
}
22862286
#endif
22872287

2288+
#if WASM_ENABLE_INSTRUCTION_METERING != 0
2289+
void
2290+
wasm_runtime_set_instruction_count_limit(WASMExecEnv *exec_env,
2291+
int instructions_to_execute)
2292+
{
2293+
exec_env->instructions_to_execute = instructions_to_execute;
2294+
}
2295+
#endif
2296+
22882297
WASMFuncType *
22892298
wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function,
22902299
uint32 module_type)

core/iwasm/common/wasm_runtime_common.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -791,9 +791,17 @@ WASM_RUNTIME_API_EXTERN void
791791
wasm_runtime_set_native_stack_boundary(WASMExecEnv *exec_env,
792792
uint8 *native_stack_boundary);
793793

794-
#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
794+
#if WASM_ENABLE_INSTRUCTION_METERING != 0
795795
/* See wasm_export.h for description */
796796
WASM_RUNTIME_API_EXTERN void
797+
wasm_runtime_set_instruction_count_limit(WASMExecEnv *exec_env,
798+
int instructions_to_execute);
799+
#endif
800+
801+
#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0
802+
/* See wasm_export.h for description */
803+
WASM_RUNTIME_API_EXTERN
804+
void
797805
wasm_runtime_set_bounds_checks(WASMModuleInstanceCommon *module_inst,
798806
bool enable);
799807

core/iwasm/include/wasm_export.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1821,6 +1821,20 @@ WASM_RUNTIME_API_EXTERN void
18211821
wasm_runtime_set_native_stack_boundary(wasm_exec_env_t exec_env,
18221822
uint8_t *native_stack_boundary);
18231823

1824+
/**
1825+
* Set the instruction count limit to the execution environment.
1826+
* By default the instruction count limit is -1, which means no limit.
1827+
* However, if the instruction count limit is set to a positive value,
1828+
* the execution will be terminated when the instruction count reaches
1829+
* the limit.
1830+
*
1831+
* @param exec_env the execution environment
1832+
* @param instruction_count the instruction count limit
1833+
*/
1834+
WASM_RUNTIME_API_EXTERN void
1835+
wasm_runtime_set_instruction_count_limit(wasm_exec_env_t exec_env,
1836+
int instruction_count);
1837+
18241838
/**
18251839
* Dump runtime memory consumption, including:
18261840
* Exec env memory consumption

core/iwasm/interpreter/wasm_interp_classic.c

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,10 +1516,13 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
15161516
} \
15171517
os_mutex_unlock(&exec_env->wait_lock); \
15181518
} \
1519+
CHECK_INSTRUCTION_LIMIT(); \
15191520
goto *handle_table[*frame_ip++]; \
15201521
} while (0)
15211522
#else
1522-
#define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH()
1523+
#define HANDLE_OP_END() \
1524+
CHECK_INSTRUCTION_LIMIT(); \
1525+
FETCH_OPCODE_AND_DISPATCH()
15231526
#endif
15241527

15251528
#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
@@ -1542,9 +1545,12 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
15421545
} \
15431546
os_mutex_unlock(&exec_env->wait_lock); \
15441547
} \
1548+
CHECK_INSTRUCTION_LIMIT(); \
15451549
continue;
15461550
#else
1547-
#define HANDLE_OP_END() continue
1551+
#define HANDLE_OP_END() \
1552+
CHECK_INSTRUCTION_LIMIT(); \
1553+
continue;
15481554
#endif
15491555

15501556
#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
@@ -1562,6 +1568,18 @@ get_global_addr(uint8 *global_data, WASMGlobalInstance *global)
15621568
#endif
15631569
}
15641570

1571+
#if WASM_ENABLE_INSTRUCTION_METERING != 0
1572+
#define CHECK_INSTRUCTION_LIMIT() \
1573+
if (instructions_left == 0) { \
1574+
wasm_set_exception(module, "instruction limit exceeded"); \
1575+
goto got_exception; \
1576+
} \
1577+
else if (instructions_left > 0) \
1578+
instructions_left--;
1579+
#else
1580+
#define CHECK_INSTRUCTION_LIMIT() (void)0
1581+
#endif
1582+
15651583
static void
15661584
wasm_interp_call_func_bytecode(WASMModuleInstance *module,
15671585
WASMExecEnv *exec_env,
@@ -1605,6 +1623,14 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
16051623
uint32 local_idx, local_offset, global_idx;
16061624
uint8 local_type, *global_addr;
16071625
uint32 cache_index, type_index, param_cell_num, cell_num;
1626+
1627+
#if WASM_ENABLE_INSTRUCTION_METERING != 0
1628+
int instructions_left = -1;
1629+
if (exec_env) {
1630+
instructions_left = exec_env->instructions_to_execute;
1631+
}
1632+
#endif
1633+
16081634
#if WASM_ENABLE_EXCE_HANDLING != 0
16091635
int32_t exception_tag_index;
16101636
#endif

core/iwasm/interpreter/wasm_interp_fast.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,19 @@ typedef float64 CellType_F64;
105105
goto unaligned_atomic; \
106106
} while (0)
107107

108+
#if WASM_ENABLE_INSTRUCTION_METERING != 0
109+
#define CHECK_INSTRUCTION_LIMIT() \
110+
if (instructions_left == 0) { \
111+
wasm_set_exception(module, "instruction limit exceeded"); \
112+
goto got_exception; \
113+
} \
114+
else if (instructions_left > 0) \
115+
instructions_left--;
116+
117+
#else
118+
#define CHECK_INSTRUCTION_LIMIT() (void)0
119+
#endif
120+
108121
static inline uint32
109122
rotl32(uint32 n, uint32 c)
110123
{
@@ -1441,6 +1454,7 @@ wasm_interp_dump_op_count()
14411454
do { \
14421455
const void *p_label_addr = *(void **)frame_ip; \
14431456
frame_ip += sizeof(void *); \
1457+
CHECK_INSTRUCTION_LIMIT(); \
14441458
goto *p_label_addr; \
14451459
} while (0)
14461460
#else
@@ -1452,6 +1466,7 @@ wasm_interp_dump_op_count()
14521466
/* int32 relative offset was emitted in 64-bit target */ \
14531467
p_label_addr = label_base + (int32)LOAD_U32_WITH_2U16S(frame_ip); \
14541468
frame_ip += sizeof(int32); \
1469+
CHECK_INSTRUCTION_LIMIT(); \
14551470
goto *p_label_addr; \
14561471
} while (0)
14571472
#else
@@ -1462,6 +1477,7 @@ wasm_interp_dump_op_count()
14621477
/* uint32 label address was emitted in 32-bit target */ \
14631478
p_label_addr = (void *)(uintptr_t)LOAD_U32_WITH_2U16S(frame_ip); \
14641479
frame_ip += sizeof(int32); \
1480+
CHECK_INSTRUCTION_LIMIT(); \
14651481
goto *p_label_addr; \
14661482
} while (0)
14671483
#endif
@@ -1538,6 +1554,13 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
15381554
uint8 *maddr = NULL;
15391555
uint32 local_idx, local_offset, global_idx;
15401556
uint8 opcode = 0, local_type, *global_addr;
1557+
1558+
#if WASM_ENABLE_INSTRUCTION_METERING != 0
1559+
int instructions_left = -1;
1560+
if (exec_env) {
1561+
instructions_left = exec_env->instructions_to_execute;
1562+
}
1563+
#endif
15411564
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
15421565
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
15431566
#if WASM_CONFIGURABLE_BOUNDS_CHECKS != 0

doc/build_wamr.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,10 @@ And the wasm app can calls below APIs to allocate/free memory from/to the shared
327327
- **WAMR_BUILD_SHRUNK_MEMORY**=1/0, default to enable if not set
328328
> Note: When enabled, this feature will reduce memory usage by decreasing the size of the linear memory, particularly when the `memory.grow` opcode is not used and memory usage is somewhat predictable.
329329
330+
## **Instruction metering**
331+
- **WAMR_BUILD_INSTRUCTION_METERING**=1/0, default to disable if not set
332+
> Note: Enabling this feature allows limiting the number of instructions a wasm module instance can execute. Use the `wasm_runtime_set_instruction_count_limit(...)` API before calling `wasm_runtime_call_*(...)` APIs to enforce this limit.
333+
330334
## **Combination of configurations:**
331335
332336
We can combine the configurations. For example, if we want to disable interpreter, enable AOT and WASI, we can run command:

0 commit comments

Comments
 (0)