Skip to content

Commit 4b4330d

Browse files
committed
Improve loop metering tests
1 parent 20526d0 commit 4b4330d

File tree

1 file changed

+92
-4
lines changed

1 file changed

+92
-4
lines changed

lib/middlewares/src/metering.rs

+92-4
Original file line numberDiff line numberDiff line change
@@ -368,15 +368,39 @@ mod tests {
368368

369369
fn bytecode() -> Vec<u8> {
370370
wat2wasm(
371-
br#"
372-
(module
371+
br#"(module
373372
(type $add_t (func (param i32) (result i32)))
374373
(func $add_one_f (type $add_t) (param $value i32) (result i32)
375374
local.get $value
376375
i32.const 1
377376
i32.add)
378-
(export "add_one" (func $add_one_f)))
379-
"#,
377+
(func $short_loop_f
378+
(local $x f64) (local $j i32)
379+
(local.set $x (f64.const 5.5))
380+
381+
(loop $named_loop
382+
;; $j++
383+
local.get $j
384+
i32.const 1
385+
i32.add
386+
local.set $j
387+
388+
;; if $j < 5, one more time
389+
local.get $j
390+
i32.const 5
391+
i32.lt_s
392+
br_if $named_loop
393+
)
394+
)
395+
(func $infi_loop_f
396+
(loop $infi_loop_start
397+
br $infi_loop_start
398+
)
399+
)
400+
(export "add_one" (func $add_one_f))
401+
(export "short_loop" (func $short_loop_f))
402+
(export "infi_loop" (func $infi_loop_f))
403+
)"#,
380404
)
381405
.unwrap()
382406
.into()
@@ -486,4 +510,68 @@ mod tests {
486510
MeteringPoints::Remaining(4)
487511
);
488512
}
513+
514+
#[test]
515+
fn metering_works_for_loops() {
516+
const INITIAL_POINTS: u64 = 10_000;
517+
518+
fn cost(operator: &Operator) -> u64 {
519+
match operator {
520+
Operator::Loop { .. } => 1000,
521+
Operator::Br { .. } | Operator::BrIf { .. } => 10,
522+
Operator::F64Const { .. } => 7,
523+
_ => 0,
524+
}
525+
}
526+
527+
// Short loop
528+
529+
let metering = Arc::new(Metering::new(INITIAL_POINTS, cost));
530+
let mut compiler_config = Cranelift::default();
531+
compiler_config.push_middleware(metering);
532+
let mut store = Store::new(EngineBuilder::new(compiler_config));
533+
let module = Module::new(&store, bytecode()).unwrap();
534+
535+
let instance = Instance::new(&mut store, &module, &imports! {}).unwrap();
536+
let short_loop: TypedFunction<(), ()> = instance
537+
.exports
538+
.get_function("short_loop")
539+
.unwrap()
540+
.typed(&store)
541+
.unwrap();
542+
short_loop.call(&mut store).unwrap();
543+
544+
let points_used: u64 = match get_remaining_points(&mut store, &instance) {
545+
MeteringPoints::Exhausted => panic!("Unexpected exhausted"),
546+
MeteringPoints::Remaining(remaining) => INITIAL_POINTS - remaining,
547+
};
548+
549+
assert_eq!(
550+
points_used,
551+
7 /* pre-loop instructions */ +
552+
1000 /* loop instruction */ + 50 /* five conditional breaks */
553+
);
554+
555+
// Infinite loop
556+
557+
let metering = Arc::new(Metering::new(INITIAL_POINTS, cost));
558+
let mut compiler_config = Cranelift::default();
559+
compiler_config.push_middleware(metering);
560+
let mut store = Store::new(EngineBuilder::new(compiler_config));
561+
let module = Module::new(&store, bytecode()).unwrap();
562+
563+
let instance = Instance::new(&mut store, &module, &imports! {}).unwrap();
564+
let infi_loop: TypedFunction<(), ()> = instance
565+
.exports
566+
.get_function("infi_loop")
567+
.unwrap()
568+
.typed(&store)
569+
.unwrap();
570+
infi_loop.call(&mut store).unwrap_err(); // exhausted leads to runtime error
571+
572+
assert_eq!(
573+
get_remaining_points(&mut store, &instance),
574+
MeteringPoints::Exhausted
575+
);
576+
}
489577
}

0 commit comments

Comments
 (0)