-
Notifications
You must be signed in to change notification settings - Fork 22
get rid of confusing ACTIVATION_FRAME_COST constant #80
Description
Hi, I'm working on adding a custom stack limiter for our protocol. It will provide API like that: (e.g. you can inject something instead of unreachable instruction)
wasm_instrument::inject_custom_stack_limiter(module, 20_000, |signature| vec![
Instruction::Foo,
Instruction::Bar,
...,
])And I think I understood what the real problem was at #1
wasm-instrument/src/stack_limiter/mod.rs
Lines 10 to 19 in 6307588
| /// Macro to generate preamble and postamble. | |
| macro_rules! instrument_call { | |
| ($callee_idx: expr, $callee_stack_cost: expr, $stack_height_global_idx: expr, $stack_limit: expr) => {{ | |
| use $crate::parity_wasm::elements::Instruction::*; | |
| [ | |
| // stack_height += stack_cost(F) | |
| GetGlobal($stack_height_global_idx), | |
| I32Const($callee_stack_cost), | |
| I32Add, | |
| SetGlobal($stack_height_global_idx), |
So we have an instrumented_call! with a maximum stack height of 2, the same as the ACTIVATION_FRAME_COST constant.
// stack_height += stack_cost(F)
GetGlobal($stack_height_global_idx), // push #1
I32Const($callee_stack_cost), // push #2
// max_height = 2Backing to problem #1: the function with index 0 has no arguments and no return value, so its max_height=0
(module
(type (;0;) (func))
(func (;0;) (type 0)
call 0)
(func (;1;) (type 0)
call 0)
(export "main" (func 1)))We also have a main export that will call function 0 and it will not be instrumented due to the condition:
wasm-instrument/src/stack_limiter/thunk.rs
Lines 44 to 48 in 6307588
| let callee_stack_cost = ctx.stack_cost(func_idx).ok_or("function index isn't found")?; | |
| // Don't generate a thunk if stack_cost of a callee is zero. | |
| if callee_stack_cost != 0 { | |
| replacement_map.insert( |
What is the best way to solve this problem? When the Call(idx) opcode is found, we need to check that idx is not an import and simply do:
let import_count = module.import_count(elements::ImportCountType::Function);
let mut max_height: u32 = 0;
let mut overhead_of_instrumented_call = 0;
...
match opcode {
Call(idx) => {
if idx >= import_count {
overhead_of_instrumented_call = 2;
}
}
}
Ok(max_height + overhead_of_instrumented_call)or we can start passing instrument_call! instructions instead of Call(idx) to match opcode