From 6d0732c1f19d26c744cb9c541f0ef51d3ac21252 Mon Sep 17 00:00:00 2001 From: Hannes Karppila Date: Mon, 3 Jun 2024 10:14:53 +0300 Subject: [PATCH 1/2] Zero $flag on call --- fuel-vm/src/interpreter/flow.rs | 7 ++-- fuel-vm/src/tests/flow.rs | 69 +++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/fuel-vm/src/interpreter/flow.rs b/fuel-vm/src/interpreter/flow.rs index 9c63f7f19a..f06c613163 100644 --- a/fuel-vm/src/interpreter/flow.rs +++ b/fuel-vm/src/interpreter/flow.rs @@ -420,6 +420,7 @@ struct PrepareCallSystemRegisters<'a> { bal: RegMut<'a, BAL>, cgas: RegMut<'a, CGAS>, ggas: RegMut<'a, GGAS>, + flag: RegMut<'a, FLAG>, } struct PrepareCallRegisters<'a> { @@ -435,7 +436,6 @@ struct PrepareCallUnusedRegisters<'a> { err: Reg<'a, ERR>, ret: Reg<'a, RET>, retl: Reg<'a, RETL>, - flag: Reg<'a, FLAG>, } impl<'a> PrepareCallRegisters<'a> { @@ -607,6 +607,7 @@ where *self.registers.system_registers.bal = self.params.amount_of_coins_to_forward; *self.registers.system_registers.is = *self.registers.system_registers.pc; *self.registers.system_registers.cgas = forward_gas_amount; + *self.registers.system_registers.flag = 0; let receipt = Receipt::call( id, @@ -659,13 +660,13 @@ impl<'a> From<&'a PrepareCallRegisters<'_>> for SystemRegistersRef<'a> { bal: registers.system_registers.bal.as_ref(), cgas: registers.system_registers.cgas.as_ref(), ggas: registers.system_registers.ggas.as_ref(), + flag: registers.system_registers.flag.as_ref(), zero: registers.unused_registers.zero, one: registers.unused_registers.one, of: registers.unused_registers.of, err: registers.unused_registers.err, ret: registers.unused_registers.ret, retl: registers.unused_registers.retl, - flag: registers.unused_registers.flag, } } } @@ -699,6 +700,7 @@ impl<'reg> From> bal: registers.bal, cgas: registers.cgas, ggas: registers.ggas, + flag: registers.flag, }; ( @@ -710,7 +712,6 @@ impl<'reg> From> err: registers.err.into(), ret: registers.ret.into(), retl: registers.retl.into(), - flag: registers.flag.into(), }, ) } diff --git a/fuel-vm/src/tests/flow.rs b/fuel-vm/src/tests/flow.rs index 2fc802307d..23a234056d 100644 --- a/fuel-vm/src/tests/flow.rs +++ b/fuel-vm/src/tests/flow.rs @@ -8,10 +8,12 @@ use crate::{ consts::*, prelude::*, script_with_data_offset, + tests::test_helpers::assert_success, util::test_helpers::TestBuilder, }; use fuel_asm::{ op, + Flags, RegId, }; use fuel_crypto::Hasher; @@ -221,6 +223,73 @@ fn call_frame_code_offset() { assert_eq!(ssp, sp_p); } +#[test] +fn call_zeroes_flag() { + let mut test_context = TestBuilder::new(2322u64); + let gas_limit = 1_000_000; + + let program = vec![ + op::log(RegId::FLAG, RegId::ZERO, RegId::ZERO, RegId::ZERO), + op::ret(RegId::ONE), + ]; + + let contract_id = test_context.setup_contract(program, None, None).contract_id; + + let (script, _) = script_with_data_offset!( + data_offset, + vec![ + op::movi(0x10, Flags::UNSAFEMATH.bits().try_into().unwrap()), + op::flag(0x10), + op::movi(0x10, data_offset as Immediate18), + op::addi(0x11, 0x10, ContractId::LEN as Immediate12), + op::call(0x10, RegId::ZERO, 0x10, 0x10), + op::log(RegId::FLAG, RegId::ZERO, RegId::ZERO, RegId::ZERO), + op::ret(0x30), + ], + test_context.get_tx_params().tx_offset() + ); + + let mut script_data = contract_id.to_vec(); + script_data.extend([0u8; WORD_SIZE * 2]); + + let result = test_context + .start_script(script, script_data) + .script_gas_limit(gas_limit) + .contract_input(contract_id) + .fee_input() + .contract_output(&contract_id) + .execute(); + + let receipts = result.receipts(); + + assert_success(receipts); + + let Receipt::Log { + ra: flag_in_call, .. + } = &receipts[1] + else { + panic!("Expected log receipt"); + }; + let Receipt::Log { + ra: flag_after_call, + .. + } = &receipts[3] + else { + panic!("Expected log receipt"); + }; + + assert_eq!( + *flag_in_call, + Flags::empty().bits(), + "Call should zero $flag" + ); + assert_eq!( + *flag_after_call, + Flags::UNSAFEMATH.bits(), + "Return should restore $flag" + ); +} + #[test] fn revert_from_call_immediately_ends_execution() { let mut test_context = TestBuilder::new(2322u64); From 4a290fa10f6da077a5164d34a71641fa8fb2e0e7 Mon Sep 17 00:00:00 2001 From: Hannes Karppila Date: Mon, 3 Jun 2024 10:19:40 +0300 Subject: [PATCH 2/2] Add changelog entry --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f053c407ea..0c09a22f04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - [#732](https://github.com/FuelLabs/fuel-vm/pull/732): Makes the VM generic over the memory type, allowing reuse of relatively expensive-to-allocate VM memories through `VmMemoryPool`. Functions and traits which require VM initalization such as `estimate_predicates` now take either the memory or `VmMemoryPool` as an argument. The `Interpterter::eq` method now only compares accessible memory regions. `Memory` was renamed into `MemoryInstance` and `Memory` is a trait now. +### Changed + +#### Breaking + +- [#743](https://github.com/FuelLabs/fuel-vm/pull/743): Zeroes `$flag` on `CALL`, so that contracts can assume clean `$flag` state. ## [Version 0.50.0]