Merge pull request #2281 from crytic/dev-solidity-0.8.24

Add support Solidity 0.8.24
pull/2146/head
alpharush 9 months ago committed by GitHub
commit 458084478e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      slither/core/declarations/solidity_variables.py
  2. 14
      slither/solc_parsing/yul/evm_functions.py
  3. 23
      tests/e2e/solc_parsing/test_ast_parsing.py
  4. BIN
      tests/e2e/solc_parsing/test_data/compile/solidity-0.8.24.sol-0.8.24-compact.zip
  5. 6
      tests/e2e/solc_parsing/test_data/expected/solidity-0.8.24.sol-0.8.24-compact.json
  6. 26
      tests/e2e/solc_parsing/test_data/solidity-0.8.24.sol

@ -21,7 +21,8 @@ SOLIDITY_VARIABLES = {
} }
SOLIDITY_VARIABLES_COMPOSED = { SOLIDITY_VARIABLES_COMPOSED = {
"block.basefee": "uint", "block.basefee": "uint256",
"block.blobbasefee": "uint256",
"block.coinbase": "address", "block.coinbase": "address",
"block.difficulty": "uint256", "block.difficulty": "uint256",
"block.prevrandao": "uint256", "block.prevrandao": "uint256",
@ -44,6 +45,7 @@ SOLIDITY_VARIABLES_COMPOSED = {
} }
SOLIDITY_FUNCTIONS: Dict[str, List[str]] = { SOLIDITY_FUNCTIONS: Dict[str, List[str]] = {
"blobhash(uint256)": ["bytes32"],
"gasleft()": ["uint256"], "gasleft()": ["uint256"],
"assert(bool)": [], "assert(bool)": [],
"require(bool)": [], "require(bool)": [],

@ -1,7 +1,7 @@
from slither.core.declarations.solidity_variables import SOLIDITY_FUNCTIONS from slither.core.declarations.solidity_variables import SOLIDITY_FUNCTIONS
from slither.core.expressions import BinaryOperationType, UnaryOperationType 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 = [ evm_opcodes = [
"STOP", "STOP",
"ADD", "ADD",
@ -45,6 +45,7 @@ evm_opcodes = [
"EXTCODECOPY", "EXTCODECOPY",
"RETURNDATASIZE", "RETURNDATASIZE",
"RETURNDATACOPY", "RETURNDATACOPY",
"MCOPY",
"EXTCODEHASH", "EXTCODEHASH",
"BLOCKHASH", "BLOCKHASH",
"COINBASE", "COINBASE",
@ -55,12 +56,17 @@ evm_opcodes = [
"GASLIMIT", "GASLIMIT",
"CHAINID", "CHAINID",
"SELFBALANCE", "SELFBALANCE",
"BASEFEE",
"BLOBHASH",
"BLOBBASEFEE",
"POP", "POP",
"MLOAD", "MLOAD",
"MSTORE", "MSTORE",
"MSTORE8", "MSTORE8",
"SLOAD", "SLOAD",
"SSTORE", "SSTORE",
"TLOAD",
"TSTORE",
"JUMP", "JUMP",
"JUMPI", "JUMPI",
"PC", "PC",
@ -183,11 +189,16 @@ function_args = {
"mstore8": [2, 0], "mstore8": [2, 0],
"sload": [1, 1], "sload": [1, 1],
"sstore": [2, 0], "sstore": [2, 0],
"tload": [1, 1],
"tstore": [2, 0],
"msize": [1, 1], "msize": [1, 1],
"gas": [0, 1], "gas": [0, 1],
"address": [0, 1], "address": [0, 1],
"balance": [1, 1], "balance": [1, 1],
"selfbalance": [0, 1], "selfbalance": [0, 1],
"basefee": [0, 1],
"blobhash": [1, 1],
"blobbasefee": [0, 1],
"caller": [0, 1], "caller": [0, 1],
"callvalue": [0, 1], "callvalue": [0, 1],
"calldataload": [1, 1], "calldataload": [1, 1],
@ -199,6 +210,7 @@ function_args = {
"extcodecopy": [4, 0], "extcodecopy": [4, 0],
"returndatasize": [0, 1], "returndatasize": [0, 1],
"returndatacopy": [3, 0], "returndatacopy": [3, 0],
"mcopy": [3, 0],
"extcodehash": [1, 1], "extcodehash": [1, 1],
"create": [3, 1], "create": [3, 1],
"create2": [4, 1], "create2": [4, 1],

@ -21,12 +21,18 @@ TEST_ROOT = os.path.join(E2E_ROOT, "solc_parsing", "test_data")
# pylint: disable=too-few-public-methods # pylint: disable=too-few-public-methods
class Test: 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.solc_versions = solc_versions
self.test_file = test_file self.test_file = test_file
self.disable_legacy = disable_legacy self.disable_legacy = disable_legacy
versions_with_flavors: List[Tuple[str, str]] = [] versions_with_flavors: List[Tuple[str, str, str]] = []
flavors = ["compact"] flavors = ["compact"]
if not self.disable_legacy: if not self.disable_legacy:
flavors += ["legacy"] flavors += ["legacy"]
@ -42,7 +48,7 @@ class Test:
) < parse_version("0.4.12") ) < parse_version("0.4.12")
if legacy_unavailable or compact_unavailable: if legacy_unavailable or compact_unavailable:
continue continue
versions_with_flavors.append((version, flavor)) versions_with_flavors.append((version, flavor, solc_args))
self.versions_with_flavors = versions_with_flavors self.versions_with_flavors = versions_with_flavors
@ -464,6 +470,7 @@ ALL_TESTS = [
Test("type-aliases.sol", ["0.8.19"]), Test("type-aliases.sol", ["0.8.19"]),
Test("enum-max-min.sol", ["0.8.19"]), Test("enum-max-min.sol", ["0.8.19"]),
Test("event-top-level.sol", ["0.8.22"]), 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 # create the output folder if needed
try: try:
@ -475,7 +482,7 @@ except OSError:
def pytest_generate_tests(metafunc): def pytest_generate_tests(metafunc):
test_cases = [] test_cases = []
for test_item in ALL_TESTS: 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)) test_cases.append((test_item.test_file, version, flavor))
metafunc.parametrize("test_file, version, flavor", test_cases) metafunc.parametrize("test_file, version, flavor", test_cases)
@ -539,7 +546,7 @@ def _generate_test(test_item: Test, skip_existing=False):
flavors = ["compact"] flavors = ["compact"]
if not test_item.disable_legacy: if not test_item.disable_legacy:
flavors += ["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_file = os.path.join(
TEST_ROOT, "compile", f"{test_item.test_file}-{version}-{flavor}.zip" 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): 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) test_file = os.path.join(TEST_ROOT, test_item.test_file)
expected_file = os.path.join( expected_file = os.path.join(
TEST_ROOT, "compile", f"{test_item.test_file}-{version}-{flavor}.zip" 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) set_solc(version)
print(f"Compiled to {expected_file}") 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 # pylint: disable=no-member
Path(expected_file).parents[0].mkdir(parents=True, exist_ok=True) Path(expected_file).parents[0].mkdir(parents=True, exist_ok=True)

@ -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"
}
}

@ -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)
}
}
}
Loading…
Cancel
Save