revive-yul: fix the code block exit (#414)

This PR fixes the missing `STOP` instruction at the end of `code`
blocks.

---------

Signed-off-by: xermicus <bigcyrill@hotmail.com>
This commit is contained in:
xermicus
2025-11-17 18:47:58 +01:00
committed by GitHub
parent dd48baadc7
commit a1090cfa5a
3 changed files with 105 additions and 0 deletions
+3
View File
@@ -10,6 +10,9 @@ Supported `polkadot-sdk` rev: `2509.0.0`
- Instruct the LLVM backend and linker to `--relax` (may lead to smaller contract code size).
- Standard JSON mode: Don't forward EVM bytecode related output selections to solc.
### Fixed:
- The missing `STOP` instruction at the end of `code` blocks.
## v0.5.0
This is a development pre-release.
+99
View File
@@ -1,6 +1,7 @@
use std::str::FromStr;
use alloy_primitives::*;
use resolc::test_utils::build_yul;
use revive_runner::*;
use SpecsAction::*;
@@ -520,3 +521,101 @@ fn create2_salt() {
}
.run();
}
#[test]
fn code_block_stops() {
let code = &build_yul(&[(
"poc.yul",
r#"object "Test"{
code {
tstore(0x7fd9d641,0x7b1e022)
returndatacopy(0x0,0x0,returndatasize())
}
object "Test_deployed" { code{} }
}"#,
)])
.unwrap()["poc.yul:Test"];
Specs {
actions: vec![
Instantiate {
origin: TestAddress::Alice,
value: 0,
gas_limit: Some(GAS_LIMIT),
storage_deposit_limit: None,
code: Code::Bytes(code.to_vec()),
data: Default::default(),
salt: OptionalHex::default(),
},
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: Default::default(),
gas_limit: None,
storage_deposit_limit: None,
data: Default::default(),
},
VerifyCall(Default::default()),
],
differential: false,
..Default::default()
}
.run();
}
#[test]
fn code_block_with_nested_object_stops() {
let code = &build_yul(&[(
"poc.yul",
r#"object "Test" {
code {
function allocate(size) -> ptr {
ptr := mload(0x40)
if iszero(ptr) { ptr := 0x60 }
mstore(0x40, add(ptr, size))
}
let size := datasize("Test_deployed")
let offset := allocate(size)
datacopy(offset, dataoffset("Test_deployed"), size)
return(offset, size)
}
object "Test_deployed" {
code {
sstore(0, 100)
}
object "Test" {
code {
revert(0,0)
}
}
}
}"#,
)])
.unwrap()["poc.yul:Test"];
Specs {
actions: vec![
Instantiate {
origin: TestAddress::Alice,
value: 0,
gas_limit: Some(GAS_LIMIT),
storage_deposit_limit: None,
code: Code::Bytes(code.to_vec()),
data: Default::default(),
salt: OptionalHex::default(),
},
Call {
origin: TestAddress::Alice,
dest: TestAddress::Instantiated(0),
value: Default::default(),
gas_limit: None,
storage_deposit_limit: None,
data: Default::default(),
},
VerifyCall(Default::default()),
],
differential: false,
..Default::default()
}
.run();
}
+3
View File
@@ -64,6 +64,9 @@ impl PolkaVMWriteLLVM for Code {
fn into_llvm(self, context: &mut PolkaVMContext) -> anyhow::Result<()> {
self.block.into_llvm(context)?;
// The EVM lets the code return implicitly.
revive_llvm_context::polkavm_evm_return::stop(context)?;
Ok(())
}
}