Skip to content

get rid of confusing ACTIVATION_FRAME_COST constant #80

@StackOverflowExcept1on

Description

@StackOverflowExcept1on

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

/// 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 = 2

Backing 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:

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions