Skip to content

Commit

Permalink
Bugfix: Accessing virtual function selectors (hyperledger-solang#1447)
Browse files Browse the repository at this point in the history
The added test case panics in current `main` because accessing the
selector of a virtual function which is not used in any other way will
put the function in `all_functions` but not `virtual_functions`.
`check_inheritance` will insert the function into `all_functions`
because we have this symbol, however because we only access the selector
it's not a virtual function to the contract. The fix is that when we
walk `all_functions` to find the externally callable ones, do not assume
every function marked `virtual` is present in the `virtual_functions` of
this contract.

Signed-off-by: xermicus <cyrill@parity.io>
  • Loading branch information
xermicus authored Jul 18, 2023
1 parent 75c4a90 commit a12d803
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 2 deletions.
5 changes: 4 additions & 1 deletion src/codegen/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2124,7 +2124,10 @@ impl Namespace {
// If a function is virtual, and it is overriden, do not make it public;
// Otherwise the runtime function dispatch will have two identical functions to dispatch to.
if func.is_virtual
&& Some(self.contracts[contract_no].virtual_functions[&func.signature]) != function_no
&& self.contracts[contract_no]
.virtual_functions
.get(&func.signature)
!= function_no.as_ref()
{
return false;
}
Expand Down
34 changes: 33 additions & 1 deletion tests/polkadot_tests/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use parity_scale_codec::{Decode, Encode};

use crate::build_solidity;
use crate::{build_solidity, build_wasm, load_abi};

#[test]
fn constructors() {
Expand Down Expand Up @@ -599,3 +599,35 @@ fn global_functions() {

runtime.function("test", Vec::new());
}

#[test]
fn virtual_function_member_access() {
let src = r##"
interface IERC1155Receiver {
@selector([1, 2, 3, 4])
function onERC1155Received() external returns (bytes4);
}
abstract contract ERC1155 {
function _doSafeTransferAcceptanceCheck() internal pure returns (bytes4) {
return IERC1155Receiver.onERC1155Received.selector;
}
}
contract C is ERC1155 {
function create() public pure returns (bytes4) {
return _doSafeTransferAcceptanceCheck();
}
}"##;

// The create function is the only one appearing in the metadata.
let abi = load_abi(&build_wasm(src, false, false)[0].1);
let messages = abi.spec().messages();
assert_eq!(messages.len(), 1);
assert_eq!(messages[0].label(), "create");

// The create function returns the selector of IERC1155Receiver.onERC1155Received
let mut runtime = build_solidity(src);
runtime.function("create", vec![]);
assert_eq!(runtime.output(), vec![1, 2, 3, 4]);
}

0 comments on commit a12d803

Please sign in to comment.