@@ -12,15 +12,16 @@ use wasmer_singlepass_backend::ModuleCodeGenerator as SinglePassMCG;
1212use crate :: errors:: VmResult ;
1313use crate :: middleware:: DeterministicMiddleware ;
1414
15- /// In Wasmer, The gas limit on instances is set during compile time and is included in the compiled binaries.
16- /// This causes issues when trying to reuse the same precompiled binaries for another instance with a different
17- /// gas limit.
18- /// https://github.com/wasmerio/wasmer/pull/996
19- /// To work around that, we set the gas limit of all Wasmer instances to this very-high gas limit value, under
20- /// the assumption that users won't request more than this amount of gas. Then to set a gas limit below that figure,
21- /// we pretend to consume the difference between the two in `set_gas_limit`, so the amount of units left is equal to
22- /// the requested gas limit.
23- pub const GAS_LIMIT : u64 = 10_000_000_000 ;
15+ /// In Wasmer, the gas limit is set on modules during compilation and is included in the cached modules.
16+ /// This causes issues when trying to instantiate the same compiled module with a different gas limit.
17+ /// A fix for this is proposed here: https://github.com/wasmerio/wasmer/pull/996.
18+ ///
19+ /// To work around this limitation, we set the gas limit of all Wasmer instances to this very high value,
20+ /// assuming users won't request more than this amount of gas. In order to set the real gas limit, we pretend
21+ /// to consume the difference between the two in `set_gas_limit` ("points used" in the metering middleware).
22+ /// Since we observed overflow behaviour in the points used, we ensure both MAX_GAS_LIMIT and points used stay
23+ /// far below u64::MAX.
24+ const MAX_GAS_LIMIT : u64 = u64:: MAX / 2 ;
2425
2526pub fn compile ( code : & [ u8 ] ) -> VmResult < Module > {
2627 let module = compile_with ( code, compiler ( ) . as_ref ( ) ) ?;
@@ -31,7 +32,7 @@ pub fn compiler() -> Box<dyn Compiler> {
3132 let c: StreamingCompiler < SinglePassMCG , _ , _ , _ , _ > = StreamingCompiler :: new ( move || {
3233 let mut chain = MiddlewareChain :: new ( ) ;
3334 chain. push ( DeterministicMiddleware :: new ( ) ) ;
34- chain. push ( metering:: Metering :: new ( GAS_LIMIT ) ) ;
35+ chain. push ( metering:: Metering :: new ( MAX_GAS_LIMIT ) ) ;
3536 chain
3637 } ) ;
3738 Box :: new ( c)
@@ -43,13 +44,75 @@ pub fn backend() -> &'static str {
4344
4445/// Set the amount of gas units that can be used in the instance.
4546pub fn set_gas_limit ( instance : & mut WasmerInstance , limit : u64 ) {
46- let used = GAS_LIMIT . saturating_sub ( limit) ;
47- metering:: set_points_used ( instance, used)
47+ if limit > MAX_GAS_LIMIT {
48+ panic ! (
49+ "Attempted to set gas limit larger than max gas limit (got: {}; maximum: {})." ,
50+ limit, MAX_GAS_LIMIT
51+ ) ;
52+ } else {
53+ let used = MAX_GAS_LIMIT - limit;
54+ metering:: set_points_used ( instance, used) ;
55+ }
4856}
4957
5058/// Get how many more gas units can be used in the instance.
5159pub fn get_gas_left ( instance : & WasmerInstance ) -> u64 {
5260 let used = metering:: get_points_used ( instance) ;
53- // when running out of gas, get_points_used can exceed GAS_LIMIT
54- GAS_LIMIT . saturating_sub ( used)
61+ // when running out of gas, get_points_used can exceed MAX_GAS_LIMIT
62+ MAX_GAS_LIMIT . saturating_sub ( used)
63+ }
64+
65+ #[ cfg( test) ]
66+ mod test {
67+ use super :: * ;
68+ use wabt:: wat2wasm;
69+ use wasmer_runtime_core:: imports;
70+
71+ fn instantiate ( code : & [ u8 ] ) -> WasmerInstance {
72+ let module = compile ( code) . unwrap ( ) ;
73+ let import_obj = imports ! { "env" => { } , } ;
74+ module. instantiate ( & import_obj) . unwrap ( )
75+ }
76+
77+ #[ test]
78+ fn get_gas_left_defaults_to_constant ( ) {
79+ let wasm = wat2wasm ( "(module)" ) . unwrap ( ) ;
80+ let instance = instantiate ( & wasm) ;
81+ let gas_left = get_gas_left ( & instance) ;
82+ assert_eq ! ( gas_left, MAX_GAS_LIMIT ) ;
83+ }
84+
85+ #[ test]
86+ fn set_gas_limit_works ( ) {
87+ let wasm = wat2wasm ( "(module)" ) . unwrap ( ) ;
88+ let mut instance = instantiate ( & wasm) ;
89+
90+ let limit = 3456789 ;
91+ set_gas_limit ( & mut instance, limit) ;
92+ assert_eq ! ( get_gas_left( & instance) , limit) ;
93+
94+ let limit = 1 ;
95+ set_gas_limit ( & mut instance, limit) ;
96+ assert_eq ! ( get_gas_left( & instance) , limit) ;
97+
98+ let limit = 0 ;
99+ set_gas_limit ( & mut instance, limit) ;
100+ assert_eq ! ( get_gas_left( & instance) , limit) ;
101+
102+ let limit = MAX_GAS_LIMIT ;
103+ set_gas_limit ( & mut instance, limit) ;
104+ assert_eq ! ( get_gas_left( & instance) , limit) ;
105+ }
106+
107+ #[ test]
108+ #[ should_panic(
109+ expected = "Attempted to set gas limit larger than max gas limit (got: 9223372036854775808; maximum: 9223372036854775807)."
110+ ) ]
111+ fn set_gas_limit_panic_for_values_too_large ( ) {
112+ let wasm = wat2wasm ( "(module)" ) . unwrap ( ) ;
113+ let mut instance = instantiate ( & wasm) ;
114+
115+ let limit = MAX_GAS_LIMIT + 1 ;
116+ set_gas_limit ( & mut instance, limit) ;
117+ }
55118}
0 commit comments