diff --git a/slither/detectors/functions/external_function.py b/slither/detectors/functions/external_function.py index 9c95bde31..773526bfb 100644 --- a/slither/detectors/functions/external_function.py +++ b/slither/detectors/functions/external_function.py @@ -96,6 +96,13 @@ class ExternalFunction(AbstractDetector): for function in derived_contract.functions if function.full_name == base_most_function.full_name] + @staticmethod + def function_parameters_written(function): + for node in function.nodes: + if any (var.name == parameter.name for var in node.local_variables_written for parameter in function.parameters): + return True + return False + def _detect(self): results = [] @@ -130,6 +137,11 @@ class ExternalFunction(AbstractDetector): if function in completed_functions: continue + # If the function has parameters which are written-to in function body, we skip + # because parameters of external functions will be allocated in calldata region which is immutable + if self.function_parameters_written(function): + continue + # Get the base-most function to know our origin of this function. base_most_function = self.get_base_most_function(function) diff --git a/tests/external_function.sol b/tests/external_function.sol index 1ed7c70c0..cc2910aa4 100644 --- a/tests/external_function.sol +++ b/tests/external_function.sol @@ -68,3 +68,15 @@ contract InternalCall { } } + +contract FunctionParameterWrite { + + function parameter_read_ok_for_external (uint i) public { + uint local = i; + } + + function parameter_read_not_ok_for_external (uint i) public returns (uint) { + i += 1; + return (i); + } +}