Consider activation frame for stack height metering (#2)

* Charge a base cost for calling a function

* Added regression test for empty functions

* Satisfy clippy
This commit is contained in:
Alexander Theißen
2022-01-18 19:04:17 +02:00
committed by GitHub
parent 4e3e6b598a
commit 57da96fb50
13 changed files with 120 additions and 38 deletions
+14 -8
View File
@@ -5,6 +5,12 @@ use parity_wasm::elements::{self, BlockType, Type};
#[cfg(feature = "sign_ext")] #[cfg(feature = "sign_ext")]
use parity_wasm::elements::SignExtInstruction; use parity_wasm::elements::SignExtInstruction;
// The cost in stack items that should be charged per call of a function. This is
// is a static cost that is added to each function call. This makes sense because even
// if a function does not use any parameters or locals some stack space on the host
// machine might be consumed to hold some context.
const ACTIVATION_FRAME_COST: u32 = 2;
/// Control stack frame. /// Control stack frame.
#[derive(Debug)] #[derive(Debug)]
struct Frame { struct Frame {
@@ -36,7 +42,7 @@ struct Stack {
impl Stack { impl Stack {
fn new() -> Stack { fn new() -> Stack {
Stack { height: 0, control_stack: Vec::new() } Stack { height: ACTIVATION_FRAME_COST, control_stack: Vec::new() }
} }
/// Returns current height of the value stack. /// Returns current height of the value stack.
@@ -431,7 +437,7 @@ mod tests {
); );
let height = compute(0, &module).unwrap(); let height = compute(0, &module).unwrap();
assert_eq!(height, 3); assert_eq!(height, 3 + ACTIVATION_FRAME_COST);
} }
#[test] #[test]
@@ -448,7 +454,7 @@ mod tests {
); );
let height = compute(0, &module).unwrap(); let height = compute(0, &module).unwrap();
assert_eq!(height, 1); assert_eq!(height, 1 + ACTIVATION_FRAME_COST);
} }
#[test] #[test]
@@ -466,7 +472,7 @@ mod tests {
); );
let height = compute(0, &module).unwrap(); let height = compute(0, &module).unwrap();
assert_eq!(height, 0); assert_eq!(height, ACTIVATION_FRAME_COST);
} }
#[test] #[test]
@@ -501,7 +507,7 @@ mod tests {
.expect("Failed to deserialize the module"); .expect("Failed to deserialize the module");
let height = compute(0, &module).unwrap(); let height = compute(0, &module).unwrap();
assert_eq!(height, 2); assert_eq!(height, 2 + ACTIVATION_FRAME_COST);
} }
#[test] #[test]
@@ -525,7 +531,7 @@ mod tests {
); );
let height = compute(0, &module).unwrap(); let height = compute(0, &module).unwrap();
assert_eq!(height, 1); assert_eq!(height, 1 + ACTIVATION_FRAME_COST);
} }
#[test] #[test]
@@ -547,7 +553,7 @@ mod tests {
); );
let height = compute(0, &module).unwrap(); let height = compute(0, &module).unwrap();
assert_eq!(height, 1); assert_eq!(height, 1 + ACTIVATION_FRAME_COST);
} }
#[test] #[test]
@@ -573,6 +579,6 @@ mod tests {
); );
let height = compute(0, &module).unwrap(); let height = compute(0, &module).unwrap();
assert_eq!(height, 3); assert_eq!(height, 3 + ACTIVATION_FRAME_COST);
} }
} }
+1
View File
@@ -92,6 +92,7 @@ mod stack_height {
def_stack_height_test!(global); def_stack_height_test!(global);
def_stack_height_test!(imports); def_stack_height_test!(imports);
def_stack_height_test!(many_locals); def_stack_height_test!(many_locals);
def_stack_height_test!(empty_functions);
} }
mod gas { mod gas {
@@ -0,0 +1,52 @@
(module
(type (;0;) (func))
(func (;0;) (type 0)
global.get 0
i32.const 2
i32.add
global.set 0
global.get 0
i32.const 1024
i32.gt_u
if ;; label = @1
unreachable
end
call 0
global.get 0
i32.const 2
i32.sub
global.set 0)
(func (;1;) (type 0)
global.get 0
i32.const 2
i32.add
global.set 0
global.get 0
i32.const 1024
i32.gt_u
if ;; label = @1
unreachable
end
call 0
global.get 0
i32.const 2
i32.sub
global.set 0)
(func (;2;) (type 0)
global.get 0
i32.const 2
i32.add
global.set 0
global.get 0
i32.const 1024
i32.gt_u
if ;; label = @1
unreachable
end
call 1
global.get 0
i32.const 2
i32.sub
global.set 0)
(global (;0;) (mut i32) (i32.const 0))
(export "main" (func 2)))
+4 -4
View File
@@ -17,7 +17,7 @@
local.get 1 local.get 1
local.get 0 local.get 0
global.get 1 global.get 1
i32.const 2 i32.const 4
i32.add i32.add
global.set 1 global.set 1
global.get 1 global.get 1
@@ -28,7 +28,7 @@
end end
call 1 call 1
global.get 1 global.get 1
i32.const 2 i32.const 4
i32.sub i32.sub
global.set 1 global.set 1
drop) drop)
@@ -36,7 +36,7 @@
local.get 0 local.get 0
local.get 1 local.get 1
global.get 1 global.get 1
i32.const 2 i32.const 4
i32.add i32.add
global.set 1 global.set 1
global.get 1 global.get 1
@@ -47,7 +47,7 @@
end end
call 1 call 1
global.get 1 global.get 1
i32.const 2 i32.const 4
i32.sub i32.sub
global.set 1) global.set 1)
(global (;0;) (mut i32) (i32.const 1)) (global (;0;) (mut i32) (i32.const 1))
+2 -2
View File
@@ -13,7 +13,7 @@
local.get 0 local.get 0
local.get 1 local.get 1
global.get 0 global.get 0
i32.const 2 i32.const 4
i32.add i32.add
global.set 0 global.set 0
global.get 0 global.get 0
@@ -24,7 +24,7 @@
end end
call 2 call 2
global.get 0 global.get 0
i32.const 2 i32.const 4
i32.sub i32.sub
global.set 0) global.set 0)
(global (;0;) (mut i32) (i32.const 0)) (global (;0;) (mut i32) (i32.const 0))
@@ -4,7 +4,7 @@
(local i64 i64 i32)) (local i64 i64 i32))
(func (;1;) (type 0) (func (;1;) (type 0)
global.get 0 global.get 0
i32.const 3 i32.const 5
i32.add i32.add
global.set 0 global.set 0
global.get 0 global.get 0
@@ -15,7 +15,7 @@
end end
call 0 call 0
global.get 0 global.get 0
i32.const 3 i32.const 5
i32.sub i32.sub
global.set 0) global.set 0)
(global (;0;) (mut i32) (i32.const 0))) (global (;0;) (mut i32) (i32.const 0)))
+2 -2
View File
@@ -5,7 +5,7 @@
drop) drop)
(func (;1;) (type 0) (func (;1;) (type 0)
global.get 0 global.get 0
i32.const 1 i32.const 3
i32.add i32.add
global.set 0 global.set 0
global.get 0 global.get 0
@@ -16,7 +16,7 @@
end end
call 0 call 0
global.get 0 global.get 0
i32.const 1 i32.const 3
i32.sub i32.sub
global.set 0) global.set 0)
(global (;0;) (mut i32) (i32.const 0)) (global (;0;) (mut i32) (i32.const 0))
+19 -4
View File
@@ -8,7 +8,7 @@
(func (;2;) (type 1)) (func (;2;) (type 1))
(func (;3;) (type 1) (func (;3;) (type 1)
global.get 0 global.get 0
i32.const 1 i32.const 3
i32.add i32.add
global.set 0 global.set 0
global.get 0 global.get 0
@@ -19,10 +19,25 @@
end end
call 1 call 1
global.get 0 global.get 0
i32.const 1 i32.const 3
i32.sub
global.set 0)
(func (;4;) (type 1)
global.get 0
i32.const 2
i32.add
global.set 0
global.get 0
i32.const 1024
i32.gt_u
if ;; label = @1
unreachable
end
call 2
global.get 0
i32.const 2
i32.sub i32.sub
global.set 0) global.set 0)
(global (;0;) (mut i32) (i32.const 0)) (global (;0;) (mut i32) (i32.const 0))
(export "exported_start" (func 3)) (export "call" (func 4))
(export "call" (func 2))
(start 3)) (start 3))
+6 -6
View File
@@ -7,7 +7,7 @@
local.get 0 local.get 0
i32.const 0 i32.const 0
global.get 0 global.get 0
i32.const 2 i32.const 4
i32.add i32.add
global.set 0 global.set 0
global.get 0 global.get 0
@@ -18,7 +18,7 @@
end end
call 2 call 2
global.get 0 global.get 0
i32.const 2 i32.const 4
i32.sub i32.sub
global.set 0 global.set 0
drop) drop)
@@ -29,7 +29,7 @@
(func (;3;) (type 1) (param i32) (func (;3;) (type 1) (param i32)
local.get 0 local.get 0
global.get 0 global.get 0
i32.const 2 i32.const 4
i32.add i32.add
global.set 0 global.set 0
global.get 0 global.get 0
@@ -40,14 +40,14 @@
end end
call 1 call 1
global.get 0 global.get 0
i32.const 2 i32.const 4
i32.sub i32.sub
global.set 0) global.set 0)
(func (;4;) (type 2) (param i32 i32) (result i32) (func (;4;) (type 2) (param i32 i32) (result i32)
local.get 0 local.get 0
local.get 1 local.get 1
global.get 0 global.get 0
i32.const 2 i32.const 4
i32.add i32.add
global.set 0 global.set 0
global.get 0 global.get 0
@@ -58,7 +58,7 @@
end end
call 2 call 2
global.get 0 global.get 0
i32.const 2 i32.const 4
i32.sub i32.sub
global.set 0) global.set 0)
(table (;0;) 10 funcref) (table (;0;) 10 funcref)
+8
View File
@@ -0,0 +1,8 @@
(module
(func (;0;)
call 0
)
(func (;1;) (export "main")
call 0
)
)
+3 -3
View File
@@ -6,8 +6,8 @@
(func $i32.add (export "i32.add") (param i32 i32) (result i32) (func $i32.add (export "i32.add") (param i32 i32) (result i32)
get_local 0 get_local 0
get_local 1 get_local 1
i32.add i32.add
) )
(func (param $arg i32) (func (param $arg i32)
(local $tmp i32) (local $tmp i32)
@@ -15,7 +15,7 @@
global.get 0 global.get 0
i32.const 1 i32.const 1
i32.add i32.add
tee_local $tmp tee_local $tmp
global.set $counter global.set $counter
get_local $tmp get_local $tmp
+1 -1
View File
@@ -3,7 +3,7 @@
(import "env" "memory" (memory 1 1)) (import "env" "memory" (memory 1 1))
(start $start) (start $start)
(func $start (export "exported_start") (func $start
(local i32) (local i32)
) )
(func (export "call") (func (export "call")
+6 -6
View File
@@ -1,15 +1,15 @@
(module (module
(import "env" "foo" (func $foo)) (import "env" "foo" (func $foo))
(func (param i32) (func (param i32)
get_local 0 get_local 0
i32.const 0 i32.const 0
call $i32.add call $i32.add
drop drop
) )
(func $i32.add (export "i32.add") (param i32 i32) (result i32) (func $i32.add (export "i32.add") (param i32 i32) (result i32)
get_local 0 get_local 0
get_local 1 get_local 1
i32.add i32.add
) )
(table 10 anyfunc) (table 10 anyfunc)