diff --git a/slither/core/declarations/solidity_variables.py b/slither/core/declarations/solidity_variables.py index 7c81266bf..2d77a20c0 100644 --- a/slither/core/declarations/solidity_variables.py +++ b/slither/core/declarations/solidity_variables.py @@ -21,7 +21,8 @@ SOLIDITY_VARIABLES = { } SOLIDITY_VARIABLES_COMPOSED = { - "block.basefee": "uint", + "block.basefee": "uint256", + "block.blobbasefee": "uint256", "block.coinbase": "address", "block.difficulty": "uint256", "block.prevrandao": "uint256", @@ -44,6 +45,7 @@ SOLIDITY_VARIABLES_COMPOSED = { } SOLIDITY_FUNCTIONS: Dict[str, List[str]] = { + "blobhash(uint256)": ["bytes32"], "gasleft()": ["uint256"], "assert(bool)": [], "require(bool)": [], diff --git a/slither/solc_parsing/yul/evm_functions.py b/slither/solc_parsing/yul/evm_functions.py index 28ea70e93..23df6e85f 100644 --- a/slither/solc_parsing/yul/evm_functions.py +++ b/slither/solc_parsing/yul/evm_functions.py @@ -1,7 +1,7 @@ from slither.core.declarations.solidity_variables import SOLIDITY_FUNCTIONS from slither.core.expressions import BinaryOperationType, UnaryOperationType -# taken from https://github.com/ethereum/solidity/blob/356cc91084114f840da66804b2a9fc1ac2846cff/libevmasm/Instruction.cpp#L180 +# taken from https://github.com/ethereum/solidity/blob/e11b9ed9f2c254bc894d844c0a64a0eb76bbb4fd/libevmasm/Instruction.cpp#L184 evm_opcodes = [ "STOP", "ADD", @@ -45,6 +45,7 @@ evm_opcodes = [ "EXTCODECOPY", "RETURNDATASIZE", "RETURNDATACOPY", + "MCOPY", "EXTCODEHASH", "BLOCKHASH", "COINBASE", @@ -55,12 +56,17 @@ evm_opcodes = [ "GASLIMIT", "CHAINID", "SELFBALANCE", + "BASEFEE", + "BLOBHASH", + "BLOBBASEFEE", "POP", "MLOAD", "MSTORE", "MSTORE8", "SLOAD", "SSTORE", + "TLOAD", + "TSTORE", "JUMP", "JUMPI", "PC", @@ -183,11 +189,16 @@ function_args = { "mstore8": [2, 0], "sload": [1, 1], "sstore": [2, 0], + "tload": [1, 1], + "tstore": [2, 0], "msize": [1, 1], "gas": [0, 1], "address": [0, 1], "balance": [1, 1], "selfbalance": [0, 1], + "basefee": [0, 1], + "blobhash": [1, 1], + "blobbasefee": [0, 1], "caller": [0, 1], "callvalue": [0, 1], "calldataload": [1, 1], @@ -199,6 +210,7 @@ function_args = { "extcodecopy": [4, 0], "returndatasize": [0, 1], "returndatacopy": [3, 0], + "mcopy": [3, 0], "extcodehash": [1, 1], "create": [3, 1], "create2": [4, 1], diff --git a/tests/e2e/solc_parsing/test_ast_parsing.py b/tests/e2e/solc_parsing/test_ast_parsing.py index f2a7beed3..49cf79f17 100644 --- a/tests/e2e/solc_parsing/test_ast_parsing.py +++ b/tests/e2e/solc_parsing/test_ast_parsing.py @@ -21,12 +21,18 @@ TEST_ROOT = os.path.join(E2E_ROOT, "solc_parsing", "test_data") # pylint: disable=too-few-public-methods class Test: - def __init__(self, test_file: str, solc_versions: List[str], disable_legacy: bool = False): + def __init__( + self, + test_file: str, + solc_versions: List[str], + disable_legacy: bool = False, + solc_args: str = None, + ): self.solc_versions = solc_versions self.test_file = test_file self.disable_legacy = disable_legacy - versions_with_flavors: List[Tuple[str, str]] = [] + versions_with_flavors: List[Tuple[str, str, str]] = [] flavors = ["compact"] if not self.disable_legacy: flavors += ["legacy"] @@ -42,7 +48,7 @@ class Test: ) < parse_version("0.4.12") if legacy_unavailable or compact_unavailable: continue - versions_with_flavors.append((version, flavor)) + versions_with_flavors.append((version, flavor, solc_args)) self.versions_with_flavors = versions_with_flavors @@ -464,6 +470,7 @@ ALL_TESTS = [ Test("type-aliases.sol", ["0.8.19"]), Test("enum-max-min.sol", ["0.8.19"]), Test("event-top-level.sol", ["0.8.22"]), + Test("solidity-0.8.24.sol", ["0.8.24"], solc_args="--evm-version cancun"), ] # create the output folder if needed try: @@ -475,7 +482,7 @@ except OSError: def pytest_generate_tests(metafunc): test_cases = [] for test_item in ALL_TESTS: - for version, flavor in test_item.versions_with_flavors: + for version, flavor, _ in test_item.versions_with_flavors: test_cases.append((test_item.test_file, version, flavor)) metafunc.parametrize("test_file, version, flavor", test_cases) @@ -539,7 +546,7 @@ def _generate_test(test_item: Test, skip_existing=False): flavors = ["compact"] if not test_item.disable_legacy: flavors += ["legacy"] - for version, flavor in test_item.versions_with_flavors: + for version, flavor, _ in test_item.versions_with_flavors: test_file = os.path.join( TEST_ROOT, "compile", f"{test_item.test_file}-{version}-{flavor}.zip" ) @@ -584,7 +591,7 @@ def set_solc(version: str): def _generate_compile(test_item: Test, skip_existing=False): - for version, flavor in test_item.versions_with_flavors: + for version, flavor, solc_args in test_item.versions_with_flavors: test_file = os.path.join(TEST_ROOT, test_item.test_file) expected_file = os.path.join( TEST_ROOT, "compile", f"{test_item.test_file}-{version}-{flavor}.zip" @@ -596,7 +603,9 @@ def _generate_compile(test_item: Test, skip_existing=False): set_solc(version) print(f"Compiled to {expected_file}") - cc = CryticCompile(test_file, solc_force_legacy_json=flavor == "legacy") + cc = CryticCompile( + test_file, solc_force_legacy_json=flavor == "legacy", solc_args=solc_args + ) # pylint: disable=no-member Path(expected_file).parents[0].mkdir(parents=True, exist_ok=True) diff --git a/tests/e2e/solc_parsing/test_data/compile/solidity-0.8.24.sol-0.8.24-compact.zip b/tests/e2e/solc_parsing/test_data/compile/solidity-0.8.24.sol-0.8.24-compact.zip new file mode 100644 index 000000000..40e94f356 Binary files /dev/null and b/tests/e2e/solc_parsing/test_data/compile/solidity-0.8.24.sol-0.8.24-compact.zip differ diff --git a/tests/e2e/solc_parsing/test_data/expected/solidity-0.8.24.sol-0.8.24-compact.json b/tests/e2e/solc_parsing/test_data/expected/solidity-0.8.24.sol-0.8.24-compact.json new file mode 100644 index 000000000..be308dd12 --- /dev/null +++ b/tests/e2e/solc_parsing/test_data/expected/solidity-0.8.24.sol-0.8.24-compact.json @@ -0,0 +1,6 @@ +{ + "A": { + "a()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->12;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: NEW VARIABLE 2\n\"];\n2->3;\n3[label=\"Node Type: INLINE ASM 3\n\"];\n3->4;\n4[label=\"Node Type: NEW VARIABLE 4\n\"];\n4->5;\n5[label=\"Node Type: EXPRESSION 5\n\"];\n5->6;\n6[label=\"Node Type: NEW VARIABLE 6\n\"];\n6->7;\n7[label=\"Node Type: EXPRESSION 7\n\"];\n7->8;\n8[label=\"Node Type: NEW VARIABLE 8\n\"];\n8->9;\n9[label=\"Node Type: EXPRESSION 9\n\"];\n9->10;\n10[label=\"Node Type: EXPRESSION 10\n\"];\n10->11;\n11[label=\"Node Type: END INLINE ASM 11\n\"];\n12[label=\"Node Type: EXPRESSION 12\n\"];\n12->1;\n}\n", + "NonReentrant()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: INLINE ASM 1\n\"];\n1->2;\n2[label=\"Node Type: IF 2\n\"];\n2->4[label=\"True\"];\n2->3[label=\"False\"];\n3[label=\"Node Type: END_IF 3\n\"];\n3->5;\n4[label=\"Node Type: EXPRESSION 4\n\"];\n4->3;\n5[label=\"Node Type: EXPRESSION 5\n\"];\n5->6;\n6[label=\"Node Type: END INLINE ASM 6\n\"];\n6->7;\n7[label=\"Node Type: _ 7\n\"];\n7->8;\n8[label=\"Node Type: INLINE ASM 8\n\"];\n8->9;\n9[label=\"Node Type: EXPRESSION 9\n\"];\n9->10;\n10[label=\"Node Type: END INLINE ASM 10\n\"];\n}\n" + } +} \ No newline at end of file diff --git a/tests/e2e/solc_parsing/test_data/solidity-0.8.24.sol b/tests/e2e/solc_parsing/test_data/solidity-0.8.24.sol new file mode 100644 index 000000000..eb96f5d28 --- /dev/null +++ b/tests/e2e/solc_parsing/test_data/solidity-0.8.24.sol @@ -0,0 +1,26 @@ +contract A { + + modifier NonReentrant { + assembly { + if tload(0) { revert(0, 0) } + tstore(0, 1) + } + _; + assembly { + tstore(0, 0) + } + } + + function a() NonReentrant public { + bytes32 _blobhash = blobhash(2); + uint _blobbasefee = block.blobbasefee; + + assembly { + let __blobbasefee := blobbasefee() + let _basefee := basefee() + let __blobhash := blobhash(3) + mcopy(0, 0x40, 0x20) + } + } +} +