Skip to content

Commit

Permalink
Fix struct unpacking in libraries (#892)
Browse files Browse the repository at this point in the history
* Fix struct unpacking in libraries

* Formatting

* Add a `struct` to `library SimpleMath`

* Update expected output
  • Loading branch information
palinatolmach authored Nov 26, 2024
1 parent 9d4eb66 commit 27e4914
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 10 deletions.
26 changes: 16 additions & 10 deletions src/kontrol/solc_to_k.py
Original file line number Diff line number Diff line change
Expand Up @@ -818,11 +818,13 @@ def process_references(bytecode: dict, target_lib_refs: dict, update_link_ranges
self.constructor = None

contract_ast_nodes = [
node
(node, node.get('contractKind'))
for node in self.contract_json['ast']['nodes']
if node['nodeType'] == 'ContractDefinition' and node['name'] == self._name
]
contract_ast = single(contract_ast_nodes) if len(contract_ast_nodes) > 0 else {'nodes': []}
contract_ast, contract_kind = (
single(contract_ast_nodes) if len(contract_ast_nodes) > 0 else ({'nodes': []}, None)
)
function_asts = {
node['functionSelector']: node
for node in contract_ast['nodes']
Expand All @@ -843,7 +845,7 @@ def process_references(bytecode: dict, target_lib_refs: dict, update_link_ranges

for method in contract_json['abi']:
if method['type'] == 'function':
msig = method_sig_from_abi(method)
msig = method_sig_from_abi(method, contract_kind == 'library')
method_selector: str = str(evm['methodIdentifiers'][msig])
mid = int(method_selector, 16)
method_ast = function_asts[method_selector] if method_selector in function_asts else {}
Expand Down Expand Up @@ -1334,7 +1336,7 @@ def _range_predicate_bytes(term: KInner, type_label: str) -> tuple[bool, KApply
return (False, None)


def method_sig_from_abi(method_json: dict) -> str:
def method_sig_from_abi(method_json: dict, is_library: bool = False) -> str:
def unparse_input(input_json: dict) -> str:
array_sizes = []
base_type = input_json['type']
Expand All @@ -1343,12 +1345,16 @@ def unparse_input(input_json: dict) -> str:
array_sizes.append(array_size_str if array_size_str != '' else '')
base_type = base_type.rpartition('[')[0]
if base_type == 'tuple':
input_type = '('
for i, component in enumerate(input_json['components']):
if i != 0:
input_type += ','
input_type += unparse_input(component)
input_type += ')'
# If the contract is a library, structs are not unpacked
if not is_library:
input_type = '('
for i, component in enumerate(input_json['components']):
if i != 0:
input_type += ','
input_type += unparse_input(component)
input_type += ')'
else:
input_type = input_json['internalType'].split(' ')[1]
else:
input_type = base_type
for array_size in reversed(array_sizes):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ pragma solidity =0.8.13;
import "forge-std/Test.sol";

library SimpleMath {
struct LibStruct {
uint256 elementOne;
address elementTwo;
}

function structInput(LibStruct memory s) public pure returns (uint256) {
return s.elementOne;
}

function square(uint256 x) public pure returns (uint256) {
return x * x;
}
Expand Down
11 changes: 11 additions & 0 deletions src/tests/integration/test-data/show/contracts.k.expected
Original file line number Diff line number Diff line change
Expand Up @@ -4931,12 +4931,23 @@ module S2KtestZModSimpleMath-CONTRACT

syntax S2KtestZModSimpleMathMethod ::= "S2Ksquare" "(" Int ":" "uint256" ")" [symbol("method_test%SimpleMath_S2Ksquare_uint256")]

syntax S2KtestZModSimpleMathMethod ::= "S2KstructInput" "(" Int ":" "uint256" "," Int ":" "address" ")" [symbol("method_test%SimpleMath_S2KstructInput_uint256_address")]

rule ( S2KtestZModSimpleMath . S2Ksquare ( KV0_x : uint256 ) => #abiCallData ( "square" , ( #uint256 ( KV0_x ) , .TypedArgs ) ) )
ensures #rangeUInt ( 256 , KV0_x )


rule ( S2KtestZModSimpleMath . S2KstructInput ( KV0_elementOne : uint256 , KV1_elementTwo : address ) => #abiCallData ( "structInput" , ( #tuple ( ( #uint256 ( KV0_elementOne ) , ( #address ( KV1_elementTwo ) , .TypedArgs ) ) ) , .TypedArgs ) ) )
ensures ( #rangeUInt ( 256 , KV0_elementOne )
andBool ( #rangeAddress ( KV1_elementTwo )
))


rule ( selector ( "square(uint256)" ) => 2066295049 )


rule ( selector ( "structInput(SimpleMath.LibStruct)" ) => 1313163024 )


endmodule

Expand Down

0 comments on commit 27e4914

Please sign in to comment.