From b9a3ea6189c374efc2c4508cdb25c3a067cb7b9f Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Tue, 4 Jun 2024 18:29:09 -0500 Subject: [PATCH] remove similar-names bc it's slow (#2469) --- slither/detectors/all_detectors.py | 1 - .../detectors/variables/similar_variables.py | 106 ------------------ ...ection_0_4_25_similar_variables_sol__0.txt | 2 - ...ection_0_5_16_similar_variables_sol__0.txt | 2 - ...ection_0_6_11_similar_variables_sol__0.txt | 2 - ...tection_0_7_6_similar_variables_sol__0.txt | 2 - .../0.4.25/similar_variables.sol | 7 -- .../0.4.25/similar_variables.sol-0.4.25.zip | Bin 1788 -> 0 bytes .../0.5.16/similar_variables.sol | 7 -- .../0.5.16/similar_variables.sol-0.5.16.zip | Bin 1787 -> 0 bytes .../0.6.11/similar_variables.sol | 7 -- .../0.6.11/similar_variables.sol-0.6.11.zip | Bin 1811 -> 0 bytes .../similar-names/0.7.6/similar_variables.sol | 7 -- .../0.7.6/similar_variables.sol-0.7.6.zip | Bin 1753 -> 0 bytes tests/e2e/detectors/test_detectors.py | 20 ---- 15 files changed, 163 deletions(-) delete mode 100644 slither/detectors/variables/similar_variables.py delete mode 100644 tests/e2e/detectors/snapshots/detectors__detector_SimilarVarsDetection_0_4_25_similar_variables_sol__0.txt delete mode 100644 tests/e2e/detectors/snapshots/detectors__detector_SimilarVarsDetection_0_5_16_similar_variables_sol__0.txt delete mode 100644 tests/e2e/detectors/snapshots/detectors__detector_SimilarVarsDetection_0_6_11_similar_variables_sol__0.txt delete mode 100644 tests/e2e/detectors/snapshots/detectors__detector_SimilarVarsDetection_0_7_6_similar_variables_sol__0.txt delete mode 100644 tests/e2e/detectors/test_data/similar-names/0.4.25/similar_variables.sol delete mode 100644 tests/e2e/detectors/test_data/similar-names/0.4.25/similar_variables.sol-0.4.25.zip delete mode 100644 tests/e2e/detectors/test_data/similar-names/0.5.16/similar_variables.sol delete mode 100644 tests/e2e/detectors/test_data/similar-names/0.5.16/similar_variables.sol-0.5.16.zip delete mode 100644 tests/e2e/detectors/test_data/similar-names/0.6.11/similar_variables.sol delete mode 100644 tests/e2e/detectors/test_data/similar-names/0.6.11/similar_variables.sol-0.6.11.zip delete mode 100644 tests/e2e/detectors/test_data/similar-names/0.7.6/similar_variables.sol delete mode 100644 tests/e2e/detectors/test_data/similar-names/0.7.6/similar_variables.sol-0.7.6.zip diff --git a/slither/detectors/all_detectors.py b/slither/detectors/all_detectors.py index ff1c352c31..7c54844316 100644 --- a/slither/detectors/all_detectors.py +++ b/slither/detectors/all_detectors.py @@ -57,7 +57,6 @@ from .functions.unimplemented import UnimplementedFunctionDetection from .statements.mapping_deletion import MappingDeletionDetection from .statements.array_length_assignment import ArrayLengthAssignment -from .variables.similar_variables import SimilarVarsDetection from .variables.function_init_state_variables import FunctionInitializedState from .statements.redundant_statements import RedundantStatements from .operations.bad_prng import BadPRNG diff --git a/slither/detectors/variables/similar_variables.py b/slither/detectors/variables/similar_variables.py deleted file mode 100644 index dccaf09c49..0000000000 --- a/slither/detectors/variables/similar_variables.py +++ /dev/null @@ -1,106 +0,0 @@ -""" -Check for state variables too similar -Do not check contract inheritance -""" -import difflib -from typing import List, Set, Tuple - -from slither.core.declarations.contract import Contract -from slither.core.variables.local_variable import LocalVariable -from slither.detectors.abstract_detector import ( - AbstractDetector, - DetectorClassification, - DETECTOR_INFO, -) -from slither.utils.output import Output - - -class SimilarVarsDetection(AbstractDetector): - """ - Variable similar detector - """ - - ARGUMENT = "similar-names" - HELP = "Variable names are too similar" - IMPACT = DetectorClassification.INFORMATIONAL - CONFIDENCE = DetectorClassification.MEDIUM - - WIKI = ( - "https://github.com/crytic/slither/wiki/Detector-Documentation#variable-names-too-similar" - ) - - WIKI_TITLE = "Variable names too similar" - WIKI_DESCRIPTION = "Detect variables with names that are too similar." - WIKI_EXPLOIT_SCENARIO = "Bob uses several variables with similar names. As a result, his code is difficult to review." - WIKI_RECOMMENDATION = "Prevent variables from having similar names." - - @staticmethod - def similar(seq1: str, seq2: str) -> bool: - """Test the name similarity - - Two name are similar if difflib.SequenceMatcher on the lowercase - version of the name is greater than 0.90 - See: https://docs.python.org/2/library/difflib.html - Args: - seq1 (str): first name - seq2 (str): second name - Returns: - bool: true if names are similar - """ - val = difflib.SequenceMatcher(a=seq1, b=seq2).ratio() - ret = val > 0.90 - return ret - - @staticmethod - def detect_sim(contract: Contract) -> Set[Tuple[LocalVariable, LocalVariable]]: - """Detect variables with similar name - - Returns: - bool: true if variables have similar name - """ - all_var = [x.variables for x in contract.functions] - all_var = [x for l in all_var for x in l] - - contract_var = contract.variables - - all_var = list(set(all_var + contract_var)) - - ret = set() - # pylint: disable=consider-using-enumerate - for i in range(len(all_var)): - v1 = all_var[i] - _v1_name_lower = v1.name.lower() - for j in range(i, len(all_var)): - v2 = all_var[j] - if len(v1.name) != len(v2.name): - continue - _v2_name_lower = v2.name.lower() - if _v1_name_lower != _v2_name_lower: - if SimilarVarsDetection.similar(_v1_name_lower, _v2_name_lower): - ret.add((v1, v2)) - - return ret - - def _detect(self) -> List[Output]: - """Detect similar variables name - - Returns: - list: {'vuln', 'filename,'contract','vars'} - """ - results = [] - for c in self.contracts: - allVars = self.detect_sim(c) - if allVars: - for (v1, v2) in sorted(allVars, key=lambda x: (x[0].name, x[1].name)): - v_left = v1 if v1.name < v2.name else v2 - v_right = v2 if v_left == v1 else v1 - info: DETECTOR_INFO = [ - "Variable ", - v_left, - " is too similar to ", - v_right, - "\n", - ] - json = self.generate_result(info) - results.append(json) - return results diff --git a/tests/e2e/detectors/snapshots/detectors__detector_SimilarVarsDetection_0_4_25_similar_variables_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_SimilarVarsDetection_0_4_25_similar_variables_sol__0.txt deleted file mode 100644 index 7f6fa4da1f..0000000000 --- a/tests/e2e/detectors/snapshots/detectors__detector_SimilarVarsDetection_0_4_25_similar_variables_sol__0.txt +++ /dev/null @@ -1,2 +0,0 @@ -Variable Similar.f().testVariable (tests/e2e/detectors/test_data/similar-names/0.4.25/similar_variables.sol#3) is too similar to Similar.f().textVariable (tests/e2e/detectors/test_data/similar-names/0.4.25/similar_variables.sol#4) - diff --git a/tests/e2e/detectors/snapshots/detectors__detector_SimilarVarsDetection_0_5_16_similar_variables_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_SimilarVarsDetection_0_5_16_similar_variables_sol__0.txt deleted file mode 100644 index 70b5c329b1..0000000000 --- a/tests/e2e/detectors/snapshots/detectors__detector_SimilarVarsDetection_0_5_16_similar_variables_sol__0.txt +++ /dev/null @@ -1,2 +0,0 @@ -Variable Similar.f().testVariable (tests/e2e/detectors/test_data/similar-names/0.5.16/similar_variables.sol#3) is too similar to Similar.f().textVariable (tests/e2e/detectors/test_data/similar-names/0.5.16/similar_variables.sol#4) - diff --git a/tests/e2e/detectors/snapshots/detectors__detector_SimilarVarsDetection_0_6_11_similar_variables_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_SimilarVarsDetection_0_6_11_similar_variables_sol__0.txt deleted file mode 100644 index efb92b5aa8..0000000000 --- a/tests/e2e/detectors/snapshots/detectors__detector_SimilarVarsDetection_0_6_11_similar_variables_sol__0.txt +++ /dev/null @@ -1,2 +0,0 @@ -Variable Similar.f().testVariable (tests/e2e/detectors/test_data/similar-names/0.6.11/similar_variables.sol#3) is too similar to Similar.f().textVariable (tests/e2e/detectors/test_data/similar-names/0.6.11/similar_variables.sol#4) - diff --git a/tests/e2e/detectors/snapshots/detectors__detector_SimilarVarsDetection_0_7_6_similar_variables_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_SimilarVarsDetection_0_7_6_similar_variables_sol__0.txt deleted file mode 100644 index 67d4823289..0000000000 --- a/tests/e2e/detectors/snapshots/detectors__detector_SimilarVarsDetection_0_7_6_similar_variables_sol__0.txt +++ /dev/null @@ -1,2 +0,0 @@ -Variable Similar.f().testVariable (tests/e2e/detectors/test_data/similar-names/0.7.6/similar_variables.sol#3) is too similar to Similar.f().textVariable (tests/e2e/detectors/test_data/similar-names/0.7.6/similar_variables.sol#4) - diff --git a/tests/e2e/detectors/test_data/similar-names/0.4.25/similar_variables.sol b/tests/e2e/detectors/test_data/similar-names/0.4.25/similar_variables.sol deleted file mode 100644 index 57f9698675..0000000000 --- a/tests/e2e/detectors/test_data/similar-names/0.4.25/similar_variables.sol +++ /dev/null @@ -1,7 +0,0 @@ -contract Similar { - function f() public returns (uint) { - uint testVariable = 1; - uint textVariable = 2; - return testVariable + textVariable; - } -} \ No newline at end of file diff --git a/tests/e2e/detectors/test_data/similar-names/0.4.25/similar_variables.sol-0.4.25.zip b/tests/e2e/detectors/test_data/similar-names/0.4.25/similar_variables.sol-0.4.25.zip deleted file mode 100644 index b91c8f6ffec918553447028a840b0e1095858ddf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1788 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