diff --git a/slither/core/declarations/custom_error.py b/slither/core/declarations/custom_error.py index 9ae6370ae..a1a689fcc 100644 --- a/slither/core/declarations/custom_error.py +++ b/slither/core/declarations/custom_error.py @@ -16,6 +16,7 @@ class CustomError(SourceMapping): self._compilation_unit = compilation_unit self._solidity_signature: Optional[str] = None + self._full_name: Optional[str] = None @property def name(self) -> str: @@ -50,7 +51,7 @@ class CustomError(SourceMapping): return str(t) @property - def solidity_signature(self) -> str: + def solidity_signature(self) -> Optional[str]: """ Return a signature following the Solidity Standard Contract and converted into address @@ -71,8 +72,21 @@ class CustomError(SourceMapping): Returns: """ - parameters = [self._convert_type_for_solidity_signature(x.type) for x in self.parameters] - self._solidity_signature = self.name + "(" + ",".join(parameters) + ")" + parameters = [x.type for x in self.parameters] + self._full_name = self.name + "(" + ",".join(map(str, parameters)) + ")" + solidity_parameters = map(self._convert_type_for_solidity_signature, parameters) + self._solidity_signature = self.name + "(" + ",".join(solidity_parameters) + ")" + + @property + def full_name(self) -> Optional[str]: + """ + Return the error signature without + converting contract into address + :return: the error signature + """ + if self._full_name is None: + raise ValueError("Custom Error not yet built") + return self._full_name # endregion ################################################################################### diff --git a/slither/core/expressions/literal.py b/slither/core/expressions/literal.py index ffda38b4d..3303a9aa8 100644 --- a/slither/core/expressions/literal.py +++ b/slither/core/expressions/literal.py @@ -31,3 +31,8 @@ class Literal(Expression): return str(convert_subdenomination(self._value, self.subdenomination)) # be sure to handle any character return str(self._value) + + def __eq__(self, other): + if not isinstance(other, Literal): + return False + return (self.value, self.subdenomination) == (other.value, other.subdenomination) diff --git a/slither/detectors/statements/unprotected_upgradeable.py b/slither/detectors/statements/unprotected_upgradeable.py index 89abaa34b..c91b5bb16 100644 --- a/slither/detectors/statements/unprotected_upgradeable.py +++ b/slither/detectors/statements/unprotected_upgradeable.py @@ -22,11 +22,20 @@ def _can_be_destroyed(contract: Contract) -> List[Function]: return targets -def _has_initializer_modifier(functions: List[Function]) -> bool: +def _has_initializing_protection(functions: List[Function]) -> bool: + # Detects "initializer" constructor modifiers and "_disableInitializers()" constructor internal calls + # https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#initializing_the_implementation_contract + for f in functions: for m in f.modifiers: if m.name == "initializer": return True + for ifc in f.all_internal_calls(): + if ifc.name == "_disableInitializers": + return True + + # to avoid future FPs in different modifier + function naming implementations, we can also implement a broader check for state var "_initialized" being written to in the constructor + # though this is still subject to naming false positives... return False @@ -82,7 +91,7 @@ class UnprotectedUpgradeable(AbstractDetector): for contract in self.compilation_unit.contracts_derived: if contract.is_upgradeable: - if not _has_initializer_modifier(contract.constructors): + if not _has_initializing_protection(contract.constructors): functions_that_can_destroy = _can_be_destroyed(contract) if functions_that_can_destroy: initialize_functions = _initialize_functions(contract) diff --git a/slither/slithir/variables/constant.py b/slither/slithir/variables/constant.py index 96a2864e9..09a5ee34f 100644 --- a/slither/slithir/variables/constant.py +++ b/slither/slithir/variables/constant.py @@ -75,3 +75,6 @@ class Constant(SlithIRVariable): def __repr__(self): return f"{str(self.value)}" + + def __hash__(self) -> int: + return self._val.__hash__() diff --git a/slither/solc_parsing/expressions/find_variable.py b/slither/solc_parsing/expressions/find_variable.py index 200e14a41..471f1a750 100644 --- a/slither/solc_parsing/expressions/find_variable.py +++ b/slither/solc_parsing/expressions/find_variable.py @@ -224,7 +224,7 @@ def _find_in_contract( custom_errors = contract.custom_errors try: for custom_error in custom_errors: - if var_name == custom_error.solidity_signature: + if var_name in [custom_error.solidity_signature, custom_error.full_name]: return custom_error except ValueError: # This can happen as custom error sol signature might not have been built diff --git a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.10-compact.zip b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.10-compact.zip new file mode 100644 index 000000000..fc45cb40e Binary files /dev/null and b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.10-compact.zip differ diff --git a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.11-compact.zip b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.11-compact.zip new file mode 100644 index 000000000..853879cf5 Binary files /dev/null and b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.11-compact.zip differ diff --git a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.12-compact.zip b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.12-compact.zip new file mode 100644 index 000000000..c72629231 Binary files /dev/null and b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.12-compact.zip differ diff --git a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.13-compact.zip b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.13-compact.zip new file mode 100644 index 000000000..9ada2c335 Binary files /dev/null and b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.13-compact.zip differ diff --git a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.14-compact.zip b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.14-compact.zip new file mode 100644 index 000000000..e36f5b94e Binary files /dev/null and b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.14-compact.zip differ diff --git a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.15-compact.zip b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.15-compact.zip new file mode 100644 index 000000000..1023ab1d4 Binary files /dev/null and b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.15-compact.zip differ diff --git a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.4-compact.zip b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.4-compact.zip index 15e749a19..5ecf2b037 100644 Binary files a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.4-compact.zip and b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.4-compact.zip differ diff --git a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.5-compact.zip b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.5-compact.zip index 070019e18..357554c09 100644 Binary files a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.5-compact.zip and b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.5-compact.zip differ diff --git a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.6-compact.zip b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.6-compact.zip index e99b78ab6..c5f05ef20 100644 Binary files a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.6-compact.zip and b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.6-compact.zip differ diff --git a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.7-compact.zip b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.7-compact.zip index 42062d708..51828bce7 100644 Binary files a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.7-compact.zip and b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.7-compact.zip differ diff --git a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.8-compact.zip b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.8-compact.zip index d11a080ff..eb6ba091b 100644 Binary files a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.8-compact.zip and b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.8-compact.zip differ diff --git a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.9-compact.zip b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.9-compact.zip index 1b450a6e3..17e752018 100644 Binary files a/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.9-compact.zip and b/tests/ast-parsing/compile/custom_error-0.8.4.sol-0.8.9-compact.zip differ diff --git a/tests/ast-parsing/custom_error-0.8.4.sol b/tests/ast-parsing/custom_error-0.8.4.sol index ea185de89..4e1e388fb 100644 --- a/tests/ast-parsing/custom_error-0.8.4.sol +++ b/tests/ast-parsing/custom_error-0.8.4.sol @@ -52,4 +52,21 @@ contract B is A{ } } +contract ContractArgCustomError { + error E(ContractArgCustomError a); + + function f() payable external { + g(); + } + + function g() private { + bool something = h(); + if (something) { + revert E(this); + } + } + + function h() private returns (bool something) { + } +} diff --git a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.10-compact.json b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.10-compact.json new file mode 100644 index 000000000..9020c8d52 --- /dev/null +++ b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.10-compact.json @@ -0,0 +1,23 @@ +{ + "I": {}, + "VendingMachine": { + "err0()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err1()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", + "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", + "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + }, + "A": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + }, + "B": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "ContractArgCustomError": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: IF 2\n\"];\n2->3[label=\"True\"];\n2->4[label=\"False\"];\n3[label=\"Node Type: EXPRESSION 3\n\"];\n3->4;\n4[label=\"Node Type: END_IF 4\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n" + } +} \ No newline at end of file diff --git a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.11-compact.json b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.11-compact.json new file mode 100644 index 000000000..9020c8d52 --- /dev/null +++ b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.11-compact.json @@ -0,0 +1,23 @@ +{ + "I": {}, + "VendingMachine": { + "err0()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err1()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", + "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", + "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + }, + "A": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + }, + "B": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "ContractArgCustomError": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: IF 2\n\"];\n2->3[label=\"True\"];\n2->4[label=\"False\"];\n3[label=\"Node Type: EXPRESSION 3\n\"];\n3->4;\n4[label=\"Node Type: END_IF 4\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n" + } +} \ No newline at end of file diff --git a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.12-compact.json b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.12-compact.json new file mode 100644 index 000000000..9020c8d52 --- /dev/null +++ b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.12-compact.json @@ -0,0 +1,23 @@ +{ + "I": {}, + "VendingMachine": { + "err0()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err1()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", + "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", + "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + }, + "A": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + }, + "B": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "ContractArgCustomError": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: IF 2\n\"];\n2->3[label=\"True\"];\n2->4[label=\"False\"];\n3[label=\"Node Type: EXPRESSION 3\n\"];\n3->4;\n4[label=\"Node Type: END_IF 4\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n" + } +} \ No newline at end of file diff --git a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.13-compact.json b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.13-compact.json new file mode 100644 index 000000000..9020c8d52 --- /dev/null +++ b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.13-compact.json @@ -0,0 +1,23 @@ +{ + "I": {}, + "VendingMachine": { + "err0()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err1()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", + "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", + "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + }, + "A": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + }, + "B": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "ContractArgCustomError": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: IF 2\n\"];\n2->3[label=\"True\"];\n2->4[label=\"False\"];\n3[label=\"Node Type: EXPRESSION 3\n\"];\n3->4;\n4[label=\"Node Type: END_IF 4\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n" + } +} \ No newline at end of file diff --git a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.14-compact.json b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.14-compact.json new file mode 100644 index 000000000..9020c8d52 --- /dev/null +++ b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.14-compact.json @@ -0,0 +1,23 @@ +{ + "I": {}, + "VendingMachine": { + "err0()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err1()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", + "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", + "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + }, + "A": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + }, + "B": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "ContractArgCustomError": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: IF 2\n\"];\n2->3[label=\"True\"];\n2->4[label=\"False\"];\n3[label=\"Node Type: EXPRESSION 3\n\"];\n3->4;\n4[label=\"Node Type: END_IF 4\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n" + } +} \ No newline at end of file diff --git a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.15-compact.json b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.15-compact.json new file mode 100644 index 000000000..9020c8d52 --- /dev/null +++ b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.15-compact.json @@ -0,0 +1,23 @@ +{ + "I": {}, + "VendingMachine": { + "err0()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err1()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", + "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", + "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + }, + "A": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + }, + "B": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "ContractArgCustomError": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: IF 2\n\"];\n2->3[label=\"True\"];\n2->4[label=\"False\"];\n3[label=\"Node Type: EXPRESSION 3\n\"];\n3->4;\n4[label=\"Node Type: END_IF 4\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n" + } +} \ No newline at end of file diff --git a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.4-compact.json b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.4-compact.json index 0a9029979..9020c8d52 100644 --- a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.4-compact.json +++ b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.4-compact.json @@ -14,5 +14,10 @@ "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "ContractArgCustomError": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: IF 2\n\"];\n2->3[label=\"True\"];\n2->4[label=\"False\"];\n3[label=\"Node Type: EXPRESSION 3\n\"];\n3->4;\n4[label=\"Node Type: END_IF 4\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n" } } \ No newline at end of file diff --git a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.5-compact.json b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.5-compact.json index 0a9029979..9020c8d52 100644 --- a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.5-compact.json +++ b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.5-compact.json @@ -14,5 +14,10 @@ "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "ContractArgCustomError": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: IF 2\n\"];\n2->3[label=\"True\"];\n2->4[label=\"False\"];\n3[label=\"Node Type: EXPRESSION 3\n\"];\n3->4;\n4[label=\"Node Type: END_IF 4\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n" } } \ No newline at end of file diff --git a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.6-compact.json b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.6-compact.json index 0a9029979..9020c8d52 100644 --- a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.6-compact.json +++ b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.6-compact.json @@ -14,5 +14,10 @@ "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "ContractArgCustomError": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: IF 2\n\"];\n2->3[label=\"True\"];\n2->4[label=\"False\"];\n3[label=\"Node Type: EXPRESSION 3\n\"];\n3->4;\n4[label=\"Node Type: END_IF 4\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n" } } \ No newline at end of file diff --git a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.7-compact.json b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.7-compact.json index 0a9029979..9020c8d52 100644 --- a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.7-compact.json +++ b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.7-compact.json @@ -14,5 +14,10 @@ "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "ContractArgCustomError": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: IF 2\n\"];\n2->3[label=\"True\"];\n2->4[label=\"False\"];\n3[label=\"Node Type: EXPRESSION 3\n\"];\n3->4;\n4[label=\"Node Type: END_IF 4\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n" } } \ No newline at end of file diff --git a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.8-compact.json b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.8-compact.json index 0a9029979..9020c8d52 100644 --- a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.8-compact.json +++ b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.8-compact.json @@ -14,5 +14,10 @@ "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "ContractArgCustomError": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: IF 2\n\"];\n2->3[label=\"True\"];\n2->4[label=\"False\"];\n3[label=\"Node Type: EXPRESSION 3\n\"];\n3->4;\n4[label=\"Node Type: END_IF 4\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n" } } \ No newline at end of file diff --git a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.9-compact.json b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.9-compact.json index 0a9029979..9020c8d52 100644 --- a/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.9-compact.json +++ b/tests/ast-parsing/expected/custom_error-0.8.4.sol-0.8.9-compact.json @@ -14,5 +14,10 @@ "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "ContractArgCustomError": { + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "g()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: IF 2\n\"];\n2->3[label=\"True\"];\n2->4[label=\"False\"];\n3[label=\"Node Type: EXPRESSION 3\n\"];\n3->4;\n4[label=\"Node Type: END_IF 4\n\"];\n}\n", + "h()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n" } } \ No newline at end of file diff --git a/tests/detectors/unprotected-upgrade/0.7.6/Fixed.sol b/tests/detectors/unprotected-upgrade/0.7.6/Fixed.sol index f9e8d45c3..53a949ee0 100644 --- a/tests/detectors/unprotected-upgrade/0.7.6/Fixed.sol +++ b/tests/detectors/unprotected-upgrade/0.7.6/Fixed.sol @@ -47,6 +47,24 @@ contract Fixed2 is Initializable { owner = msg.sender; } + function kill() external { + require(msg.sender == owner); + selfdestruct(owner); + } +} + +contract Fixed3 is Initializable { + address payable owner; + + constructor() { + _disableInitializers(); + } + + function initialize() external initializer { + require(owner == address(0)); + owner = payable(msg.sender); + } + function kill() external { require(msg.sender == owner); selfdestruct(owner); diff --git a/tests/detectors/unprotected-upgrade/0.7.6/Initializable.sol b/tests/detectors/unprotected-upgrade/0.7.6/Initializable.sol index 779a0e87c..cff401bae 100644 --- a/tests/detectors/unprotected-upgrade/0.7.6/Initializable.sol +++ b/tests/detectors/unprotected-upgrade/0.7.6/Initializable.sol @@ -1,5 +1,15 @@ contract Initializable{ - modifier initializer() { - _; - } + uint8 private _initialized; + bool private _initializing; + + modifier initializer() { + _; + } + + function _disableInitializers() internal virtual { + require(!_initializing, "Initializable: contract is initializing"); + if (_initialized < type(uint8).max) { + _initialized = type(uint8).max; + } + } } \ No newline at end of file diff --git a/tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol b/tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol new file mode 100644 index 000000000..dd27ddd82 --- /dev/null +++ b/tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol @@ -0,0 +1,14 @@ +import "./Initializable.sol"; + +contract Buggy is Initializable{ + address payable owner; + + function initialize() external initializer{ + require(owner == address(0)); + owner = payable(msg.sender); + } + function kill() external{ + require(msg.sender == owner); + selfdestruct(owner); + } +} diff --git a/tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol.0.8.15.UnprotectedUpgradeable.json b/tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol.0.8.15.UnprotectedUpgradeable.json new file mode 100644 index 000000000..79bcda746 --- /dev/null +++ b/tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol.0.8.15.UnprotectedUpgradeable.json @@ -0,0 +1,145 @@ +[ + [ + { + "elements": [ + { + "type": "contract", + "name": "Buggy", + "source_mapping": { + "start": 31, + "length": 294, + "filename_relative": "tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14 + ], + "starting_column": 1, + "ending_column": 2 + } + }, + { + "type": "function", + "name": "initialize", + "source_mapping": { + "start": 96, + "length": 124, + "filename_relative": "tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol", + "is_dependency": false, + "lines": [ + 6, + 7, + 8, + 9 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "Buggy", + "source_mapping": { + "start": 31, + "length": 294, + "filename_relative": "tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14 + ], + "starting_column": 1, + "ending_column": 2 + } + }, + "signature": "initialize()" + } + }, + { + "type": "function", + "name": "kill", + "source_mapping": { + "start": 225, + "length": 98, + "filename_relative": "tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol", + "is_dependency": false, + "lines": [ + 10, + 11, + 12, + 13 + ], + "starting_column": 5, + "ending_column": 6 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "Buggy", + "source_mapping": { + "start": 31, + "length": 294, + "filename_relative": "tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol", + "is_dependency": false, + "lines": [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14 + ], + "starting_column": 1, + "ending_column": 2 + } + }, + "signature": "kill()" + } + } + ], + "description": "Buggy (tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol#3-14) is an upgradeable contract that does not protect its initialize functions: Buggy.initialize() (tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol#6-9). Anyone can delete the contract with: Buggy.kill() (tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol#10-13)", + "markdown": "[Buggy](tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol#L3-L14) is an upgradeable contract that does not protect its initialize functions: [Buggy.initialize()](tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol#L6-L9). Anyone can delete the contract with: [Buggy.kill()](tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol#L10-L13)", + "first_markdown_element": "tests/detectors/unprotected-upgrade/0.8.15/Buggy.sol#L3-L14", + "id": "d85b90230632a30f7ffb5140a791d4a9ae8b0be045c5b27175f3c477e189c08c", + "check": "unprotected-upgrade", + "impact": "High", + "confidence": "High" + } + ] +] \ No newline at end of file diff --git a/tests/detectors/unprotected-upgrade/0.8.15/Fixed.sol b/tests/detectors/unprotected-upgrade/0.8.15/Fixed.sol new file mode 100644 index 000000000..a4ae7b206 --- /dev/null +++ b/tests/detectors/unprotected-upgrade/0.8.15/Fixed.sol @@ -0,0 +1,73 @@ +import "./Initializable.sol"; + +contract Fixed is Initializable{ + address payable owner; + + constructor() { + owner = payable(msg.sender); + } + + function initialize() external initializer{ + require(owner == address(0)); + owner = payable(msg.sender); + + } + function kill() external{ + require(msg.sender == owner); + selfdestruct(owner); + } + + function other_function() external{ + + } +} + +contract Not_Upgradeable{ +} + +contract UpgradeableNoDestruct is Initializable{ + address payable owner; + + constructor() { + owner = payable(msg.sender); + } + + function initialize() external initializer{ + require(owner == address(0)); + owner = payable(msg.sender); + } +} + +contract Fixed2 is Initializable { + address payable owner; + + constructor() initializer {} + + function initialize() external initializer { + require(owner == address(0)); + owner = payable(msg.sender); + } + + function kill() external { + require(msg.sender == owner); + selfdestruct(owner); + } +} + +contract Fixed3 is Initializable { + address payable owner; + + constructor() { + _disableInitializers(); + } + + function initialize() external initializer { + require(owner == address(0)); + owner = payable(msg.sender); + } + + function kill() external { + require(msg.sender == owner); + selfdestruct(owner); + } +} \ No newline at end of file diff --git a/tests/detectors/unprotected-upgrade/0.8.15/Fixed.sol.0.8.15.UnprotectedUpgradeable.json b/tests/detectors/unprotected-upgrade/0.8.15/Fixed.sol.0.8.15.UnprotectedUpgradeable.json new file mode 100644 index 000000000..5825bcacc --- /dev/null +++ b/tests/detectors/unprotected-upgrade/0.8.15/Fixed.sol.0.8.15.UnprotectedUpgradeable.json @@ -0,0 +1,3 @@ +[ + [] +] \ No newline at end of file diff --git a/tests/detectors/unprotected-upgrade/0.8.15/Initializable.sol b/tests/detectors/unprotected-upgrade/0.8.15/Initializable.sol new file mode 100644 index 000000000..4fd7561c8 --- /dev/null +++ b/tests/detectors/unprotected-upgrade/0.8.15/Initializable.sol @@ -0,0 +1,15 @@ +contract Initializable { + uint8 private _initialized; + bool private _initializing; + + modifier initializer() { + _; + } + + function _disableInitializers() internal virtual { + require(!_initializing, "Initializable: contract is initializing"); + if (_initialized < type(uint8).max) { + _initialized = type(uint8).max; + } + } +} \ No newline at end of file diff --git a/tests/detectors/unprotected-upgrade/0.8.15/OnlyProxy.sol b/tests/detectors/unprotected-upgrade/0.8.15/OnlyProxy.sol new file mode 100644 index 000000000..1ffa63272 --- /dev/null +++ b/tests/detectors/unprotected-upgrade/0.8.15/OnlyProxy.sol @@ -0,0 +1,5 @@ +contract OnlyProxy { + modifier onlyProxy() { + _; + } +} diff --git a/tests/detectors/unprotected-upgrade/0.8.15/whitelisted.sol b/tests/detectors/unprotected-upgrade/0.8.15/whitelisted.sol new file mode 100644 index 000000000..dafeff691 --- /dev/null +++ b/tests/detectors/unprotected-upgrade/0.8.15/whitelisted.sol @@ -0,0 +1,15 @@ +import "./Initializable.sol"; +import "./OnlyProxy.sol"; + +contract Whitelisted is Initializable, OnlyProxy{ + address payable owner; + + function initialize() external initializer onlyProxy { + owner = payable(msg.sender); + } + + function kill() external { + require(msg.sender == owner); + selfdestruct(owner); + } +} diff --git a/tests/detectors/unprotected-upgrade/0.8.15/whitelisted.sol.0.8.15.UnprotectedUpgradeable.json b/tests/detectors/unprotected-upgrade/0.8.15/whitelisted.sol.0.8.15.UnprotectedUpgradeable.json new file mode 100644 index 000000000..5825bcacc --- /dev/null +++ b/tests/detectors/unprotected-upgrade/0.8.15/whitelisted.sol.0.8.15.UnprotectedUpgradeable.json @@ -0,0 +1,3 @@ +[ + [] +] \ No newline at end of file diff --git a/tests/test_ast_parsing.py b/tests/test_ast_parsing.py index 005971374..506ee3d6b 100644 --- a/tests/test_ast_parsing.py +++ b/tests/test_ast_parsing.py @@ -323,7 +323,7 @@ ALL_TESTS = [ "custom_error-0.4.0.sol", ALL_VERSIONS, ), - Test("custom_error-0.8.4.sol", make_version(8, 4, 9)), + Test("custom_error-0.8.4.sol", make_version(8, 4, 15)), Test( "top-level-0.4.0.sol", VERSIONS_04 + VERSIONS_05 + VERSIONS_06 + ["0.7.0"], diff --git a/tests/test_detectors.py b/tests/test_detectors.py index dfd23956c..796b5ff5c 100644 --- a/tests/test_detectors.py +++ b/tests/test_detectors.py @@ -929,6 +929,21 @@ ALL_TEST_OBJECTS = [ "whitelisted.sol", "0.7.6", ), + Test( + all_detectors.UnprotectedUpgradeable, + "Buggy.sol", + "0.8.15", + ), + Test( + all_detectors.UnprotectedUpgradeable, + "Fixed.sol", + "0.8.15", + ), + Test( + all_detectors.UnprotectedUpgradeable, + "whitelisted.sol", + "0.8.15", + ), Test( all_detectors.ABIEncoderV2Array, "storage_ABIEncoderV2_array.sol",