From 789e107a8d979c03418da6379eb747fa8911655d Mon Sep 17 00:00:00 2001 From: bohendo Date: Mon, 27 Jan 2025 12:32:20 -0500 Subject: [PATCH 1/8] fix unicode patches during mutation --- slither/core/source_mapping/source_mapping.py | 2 +- slither/tools/mutator/mutators/AOR.py | 2 +- slither/tools/mutator/mutators/ASOR.py | 2 +- slither/tools/mutator/mutators/BOR.py | 2 +- slither/tools/mutator/mutators/CR.py | 2 +- slither/tools/mutator/mutators/FHR.py | 2 +- slither/tools/mutator/mutators/LIR.py | 4 ++-- slither/tools/mutator/mutators/LOR.py | 2 +- slither/tools/mutator/mutators/MIA.py | 2 +- slither/tools/mutator/mutators/MVIE.py | 4 ++-- slither/tools/mutator/mutators/MVIV.py | 4 ++-- slither/tools/mutator/mutators/MWA.py | 2 +- slither/tools/mutator/mutators/ROR.py | 2 +- slither/tools/mutator/mutators/RR.py | 10 ++++++---- slither/tools/mutator/mutators/SBR.py | 4 ++-- slither/tools/mutator/mutators/UOR.py | 2 +- 16 files changed, 25 insertions(+), 23 deletions(-) diff --git a/slither/core/source_mapping/source_mapping.py b/slither/core/source_mapping/source_mapping.py index 355aa5538..61545c8f5 100644 --- a/slither/core/source_mapping/source_mapping.py +++ b/slither/core/source_mapping/source_mapping.py @@ -79,7 +79,7 @@ def content(self) -> str: # If the compilation unit was not initialized, it means that the set_offset was never called # on the corresponding object, which should not happen assert self.compilation_unit - return self.compilation_unit.core.source_code[self.filename.absolute][self.start : self.end] + return self.compilation_unit.core.source_code[self.filename.absolute].encode("utf-8")[self.start : self.end].decode("utf-8") @property def content_hash(self) -> str: diff --git a/slither/tools/mutator/mutators/AOR.py b/slither/tools/mutator/mutators/AOR.py index f86e7d3d4..d74c57371 100644 --- a/slither/tools/mutator/mutators/AOR.py +++ b/slither/tools/mutator/mutators/AOR.py @@ -74,7 +74,7 @@ def _mutate(self) -> Dict: # Get the string start = node.source_mapping.start stop = start + node.source_mapping.length - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content line_no = node.source_mapping.lines if not line_no[0] in self.dont_mutate_line: # Replace the expression with true diff --git a/slither/tools/mutator/mutators/ASOR.py b/slither/tools/mutator/mutators/ASOR.py index 2ff403b38..18beb63c5 100644 --- a/slither/tools/mutator/mutators/ASOR.py +++ b/slither/tools/mutator/mutators/ASOR.py @@ -48,7 +48,7 @@ def _mutate(self) -> Dict: if op != ir.expression: start = node.source_mapping.start stop = start + node.source_mapping.length - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content line_no = node.source_mapping.lines if not line_no[0] in self.dont_mutate_line: # Replace the expression with true diff --git a/slither/tools/mutator/mutators/BOR.py b/slither/tools/mutator/mutators/BOR.py index a8720a4b6..fed5319ec 100644 --- a/slither/tools/mutator/mutators/BOR.py +++ b/slither/tools/mutator/mutators/BOR.py @@ -31,7 +31,7 @@ def _mutate(self) -> Dict: # Get the string start = node.source_mapping.start stop = start + node.source_mapping.length - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content line_no = node.source_mapping.lines if not line_no[0] in self.dont_mutate_line: # Replace the expression with true diff --git a/slither/tools/mutator/mutators/CR.py b/slither/tools/mutator/mutators/CR.py index ebf93bf18..2c1ebc4d9 100644 --- a/slither/tools/mutator/mutators/CR.py +++ b/slither/tools/mutator/mutators/CR.py @@ -23,7 +23,7 @@ def _mutate(self) -> Dict: # Get the string start = node.source_mapping.start stop = start + node.source_mapping.length - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content line_no = node.source_mapping.lines if not line_no[0] in self.dont_mutate_line: new_str = "//" + old_str diff --git a/slither/tools/mutator/mutators/FHR.py b/slither/tools/mutator/mutators/FHR.py index 028c1916c..c874b489d 100644 --- a/slither/tools/mutator/mutators/FHR.py +++ b/slither/tools/mutator/mutators/FHR.py @@ -22,7 +22,7 @@ def _mutate(self) -> Dict: for function in self.contract.functions_and_modifiers_declared: start = function.source_mapping.start stop = start + function.source_mapping.content.find("{") - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content line_no = function.source_mapping.lines if not line_no[0] in self.dont_mutate_line: for value in function_header_replacements: diff --git a/slither/tools/mutator/mutators/LIR.py b/slither/tools/mutator/mutators/LIR.py index fc621829f..d2ad3e5b3 100644 --- a/slither/tools/mutator/mutators/LIR.py +++ b/slither/tools/mutator/mutators/LIR.py @@ -36,7 +36,7 @@ def _mutate(self) -> Dict: # pylint: disable=too-many-branches # Get the string start = variable.source_mapping.start stop = start + variable.source_mapping.length - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content line_no = variable.node_initialization.source_mapping.lines if not line_no[0] in self.dont_mutate_line: for value in literal_replacements: @@ -67,7 +67,7 @@ def _mutate(self) -> Dict: # pylint: disable=too-many-branches literal_replacements.append("-1") start = variable.source_mapping.start stop = start + variable.source_mapping.length - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content line_no = variable.source_mapping.lines if not line_no[0] in self.dont_mutate_line: for new_value in literal_replacements: diff --git a/slither/tools/mutator/mutators/LOR.py b/slither/tools/mutator/mutators/LOR.py index 2d1535b1a..64285ed77 100644 --- a/slither/tools/mutator/mutators/LOR.py +++ b/slither/tools/mutator/mutators/LOR.py @@ -29,7 +29,7 @@ def _mutate(self) -> Dict: # Get the string start = node.source_mapping.start stop = start + node.source_mapping.length - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content line_no = node.source_mapping.lines if not line_no[0] in self.dont_mutate_line: # Replace the expression with true diff --git a/slither/tools/mutator/mutators/MIA.py b/slither/tools/mutator/mutators/MIA.py index f29569f63..07946dc55 100644 --- a/slither/tools/mutator/mutators/MIA.py +++ b/slither/tools/mutator/mutators/MIA.py @@ -17,7 +17,7 @@ def _mutate(self) -> Dict: # Get the string start = node.expression.source_mapping.start stop = start + node.expression.source_mapping.length - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content line_no = node.source_mapping.lines if not line_no[0] in self.dont_mutate_line: # Replace the expression with true and false diff --git a/slither/tools/mutator/mutators/MVIE.py b/slither/tools/mutator/mutators/MVIE.py index ce51792ff..983b7cf15 100644 --- a/slither/tools/mutator/mutators/MVIE.py +++ b/slither/tools/mutator/mutators/MVIE.py @@ -24,7 +24,7 @@ def _mutate(self) -> Dict: # Get the string start = variable.source_mapping.start stop = variable.expression.source_mapping.start - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content new_str = old_str[: old_str.find("=")] line_no = variable.node_initialization.source_mapping.lines if not line_no[0] in self.dont_mutate_line: @@ -44,7 +44,7 @@ def _mutate(self) -> Dict: # Get the string start = variable.source_mapping.start stop = variable.expression.source_mapping.start - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content new_str = old_str[: old_str.find("=")] line_no = variable.source_mapping.lines if not line_no[0] in self.dont_mutate_line: diff --git a/slither/tools/mutator/mutators/MVIV.py b/slither/tools/mutator/mutators/MVIV.py index f9e51c553..d51414a7d 100644 --- a/slither/tools/mutator/mutators/MVIV.py +++ b/slither/tools/mutator/mutators/MVIV.py @@ -24,7 +24,7 @@ def _mutate(self) -> Dict: # Get the string start = variable.source_mapping.start stop = variable.expression.source_mapping.start - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content new_str = old_str[: old_str.find("=")] line_no = variable.node_initialization.source_mapping.lines if not line_no[0] in self.dont_mutate_line: @@ -43,7 +43,7 @@ def _mutate(self) -> Dict: if variable.initialized and isinstance(variable.expression, Literal): start = variable.source_mapping.start stop = variable.expression.source_mapping.start - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content new_str = old_str[: old_str.find("=")] line_no = variable.source_mapping.lines if not line_no[0] in self.dont_mutate_line: diff --git a/slither/tools/mutator/mutators/MWA.py b/slither/tools/mutator/mutators/MWA.py index 9682f10ca..1ba56b3e1 100644 --- a/slither/tools/mutator/mutators/MWA.py +++ b/slither/tools/mutator/mutators/MWA.py @@ -18,7 +18,7 @@ def _mutate(self) -> Dict: # Get the string start = node.source_mapping.start stop = start + node.source_mapping.length - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content line_no = node.source_mapping.lines if not line_no[0] in self.dont_mutate_line: if not isinstance(node.expression, UnaryOperation): diff --git a/slither/tools/mutator/mutators/ROR.py b/slither/tools/mutator/mutators/ROR.py index 9daae0663..aea209f4b 100644 --- a/slither/tools/mutator/mutators/ROR.py +++ b/slither/tools/mutator/mutators/ROR.py @@ -36,7 +36,7 @@ def _mutate(self) -> Dict: # Get the string start = ir.expression.source_mapping.start stop = start + ir.expression.source_mapping.length - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content line_no = node.source_mapping.lines if not line_no[0] in self.dont_mutate_line: # Replace the expression with true diff --git a/slither/tools/mutator/mutators/RR.py b/slither/tools/mutator/mutators/RR.py index ba76d657f..d37f2e9b6 100644 --- a/slither/tools/mutator/mutators/RR.py +++ b/slither/tools/mutator/mutators/RR.py @@ -21,9 +21,11 @@ def _mutate(self) -> Dict: # Get the string start = node.source_mapping.start stop = start + node.source_mapping.length - old_str = self.in_file_str[start:stop] - line_no = node.source_mapping.lines - if not line_no[0] in self.dont_mutate_line: + old_str = node.source_mapping.content + line_no = node.source_mapping.lines[0] + if not line_no in self.dont_mutate_line: + if node.type == NodeType.RETURN and not old_str.lstrip().startswith("return"): + continue # skip the return declarations in fn signatures if not old_str.lstrip().startswith("revert"): new_str = "revert()" create_patch_with_line( @@ -33,6 +35,6 @@ def _mutate(self) -> Dict: stop, old_str, new_str, - line_no[0], + line_no, ) return result diff --git a/slither/tools/mutator/mutators/SBR.py b/slither/tools/mutator/mutators/SBR.py index efbda4877..18cea69d9 100644 --- a/slither/tools/mutator/mutators/SBR.py +++ b/slither/tools/mutator/mutators/SBR.py @@ -64,7 +64,7 @@ def _mutate(self) -> Dict: # Get the string start = node.source_mapping.start stop = start + node.source_mapping.length - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content line_no = node.source_mapping.lines if not line_no[0] in self.dont_mutate_line: for value in solidity_rules: @@ -89,7 +89,7 @@ def _mutate(self) -> Dict: if node: start = node.source_mapping.start stop = start + node.source_mapping.length - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content line_no = node.source_mapping.lines if not line_no[0] in self.dont_mutate_line: for value in solidity_rules: diff --git a/slither/tools/mutator/mutators/UOR.py b/slither/tools/mutator/mutators/UOR.py index f427c2fbf..bd22f1f37 100644 --- a/slither/tools/mutator/mutators/UOR.py +++ b/slither/tools/mutator/mutators/UOR.py @@ -29,7 +29,7 @@ def _mutate(self) -> Dict: continue start = node.source_mapping.start stop = start + node.source_mapping.length - old_str = self.in_file_str[start:stop] + old_str = node.source_mapping.content line_no = node.source_mapping.lines if not line_no[0] in self.dont_mutate_line: if ( From e31a88196d3a2fe6f33ee88cb606a61163981586 Mon Sep 17 00:00:00 2001 From: bohendo Date: Mon, 27 Jan 2025 12:34:33 -0500 Subject: [PATCH 2/8] fix mutation logs & RR mutator --- slither/tools/mutator/__main__.py | 15 +++++++++++---- slither/tools/mutator/mutators/RR.py | 3 ++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/slither/tools/mutator/__main__.py b/slither/tools/mutator/__main__.py index d97806e28..f71ef26b5 100644 --- a/slither/tools/mutator/__main__.py +++ b/slither/tools/mutator/__main__.py @@ -167,7 +167,10 @@ def main() -> None: # pylint: disable=too-many-statements,too-many-branches,too # get all the contracts as a list from given codebase sol_file_list: List[str] = get_sol_file_list(Path(args.codebase), paths_to_ignore_list) - logger.info(blue("Preparing to mutate files:\n- " + "\n- ".join(sol_file_list))) + if not contract_names: + logger.info(blue("Preparing to mutate files:\n- " + "\n- ".join(sol_file_list))) + else: + logger.info(blue("Preparing to mutate contracts:\n- " + "\n- ".join(contract_names))) # folder where backup files and uncaught mutants are saved if output_dir is None: @@ -240,7 +243,8 @@ def main() -> None: # pylint: disable=too-many-statements,too-many-branches,too # perform mutations on {target_contract} in file {file_name} # setup placeholder val to signal whether we need to skip if no target_contract is found - target_contract = "SLITHER_SKIP_MUTATIONS" if contract_names else "" + skip_flag = "SLITHER_SKIP_MUTATIONS" + target_contract = skip_flag if contract_names else "" try: # loop through all contracts in file_name for compilation_unit_of_main_file in sl.compilation_units: @@ -258,8 +262,7 @@ def main() -> None: # pylint: disable=too-many-statements,too-many-branches,too ) continue - if target_contract == "SLITHER_SKIP_MUTATIONS": - logger.debug(f"Skipping mutations in {filename}") + if target_contract == skip_flag: continue # TODO: find a more specific way to omit interfaces @@ -334,6 +337,10 @@ def main() -> None: # pylint: disable=too-many-statements,too-many-branches,too # transfer and delete the backup files transfer_and_delete(files_dict) + if target_contract == skip_flag: + logger.debug(f"No target contracts found in {filename}, skipping") + continue + # log results for this file logger.info(blue(f"Done mutating {target_contract}.")) if total_mutant_counts[0] > 0: diff --git a/slither/tools/mutator/mutators/RR.py b/slither/tools/mutator/mutators/RR.py index d37f2e9b6..174daa671 100644 --- a/slither/tools/mutator/mutators/RR.py +++ b/slither/tools/mutator/mutators/RR.py @@ -3,7 +3,6 @@ from slither.tools.mutator.utils.patch import create_patch_with_line from slither.tools.mutator.mutators.abstract_mutator import AbstractMutator - class RR(AbstractMutator): # pylint: disable=too-few-public-methods NAME = "RR" HELP = "Revert Replacement" @@ -15,8 +14,10 @@ def _mutate(self) -> Dict: for node in function.nodes: if node.type not in ( NodeType.ENTRYPOINT, + NodeType.IF, NodeType.ENDIF, NodeType.ENDLOOP, + NodeType.PLACEHOLDER, ): # Get the string start = node.source_mapping.start From 8b9590dc96e12959a5c743b79af953282b127a06 Mon Sep 17 00:00:00 2001 From: bohendo Date: Mon, 27 Jan 2025 13:26:03 -0500 Subject: [PATCH 3/8] skip assembly in BOR mutator --- slither/tools/mutator/mutators/BOR.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/slither/tools/mutator/mutators/BOR.py b/slither/tools/mutator/mutators/BOR.py index fed5319ec..d6638daf8 100644 --- a/slither/tools/mutator/mutators/BOR.py +++ b/slither/tools/mutator/mutators/BOR.py @@ -35,7 +35,10 @@ def _mutate(self) -> Dict: line_no = node.source_mapping.lines if not line_no[0] in self.dont_mutate_line: # Replace the expression with true - new_str = f"{old_str.split(ir.type.value)[0]}{op.value}{old_str.split(ir.type.value)[1]}" + halves = old_str.split(ir.type.value) + if len(halves) != 2: + continue # skip if assembly + new_str = f"{halves[0]}{op.value}{halves[1]}" create_patch_with_line( result, self.in_file, From 2295939b63103d96bab291829db7ac66d0dda59f Mon Sep 17 00:00:00 2001 From: bohendo Date: Mon, 27 Jan 2025 15:21:58 -0500 Subject: [PATCH 4/8] fix bugs in other mutators --- slither/tools/mutator/mutators/AOR.py | 6 ++++-- slither/tools/mutator/mutators/FHR.py | 2 +- slither/tools/mutator/mutators/MVIE.py | 4 ++-- slither/tools/mutator/mutators/ROR.py | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/slither/tools/mutator/mutators/AOR.py b/slither/tools/mutator/mutators/AOR.py index d74c57371..a9e816f9e 100644 --- a/slither/tools/mutator/mutators/AOR.py +++ b/slither/tools/mutator/mutators/AOR.py @@ -77,8 +77,10 @@ def _mutate(self) -> Dict: old_str = node.source_mapping.content line_no = node.source_mapping.lines if not line_no[0] in self.dont_mutate_line: - # Replace the expression with true - new_str = f"{old_str.split(ir.type.value)[0]}{op.value}{old_str.split(ir.type.value)[1]}" + halves = old_str.split(ir.type.value) + if len(halves) != 2: + continue # skip if assembly + new_str = f"{halves[0]}{op.value}{halves[1]}" create_patch_with_line( result, self.in_file, diff --git a/slither/tools/mutator/mutators/FHR.py b/slither/tools/mutator/mutators/FHR.py index c874b489d..c847542ca 100644 --- a/slither/tools/mutator/mutators/FHR.py +++ b/slither/tools/mutator/mutators/FHR.py @@ -22,7 +22,7 @@ def _mutate(self) -> Dict: for function in self.contract.functions_and_modifiers_declared: start = function.source_mapping.start stop = start + function.source_mapping.content.find("{") - old_str = node.source_mapping.content + old_str = function.source_mapping.content line_no = function.source_mapping.lines if not line_no[0] in self.dont_mutate_line: for value in function_header_replacements: diff --git a/slither/tools/mutator/mutators/MVIE.py b/slither/tools/mutator/mutators/MVIE.py index 983b7cf15..be0a80daf 100644 --- a/slither/tools/mutator/mutators/MVIE.py +++ b/slither/tools/mutator/mutators/MVIE.py @@ -24,7 +24,7 @@ def _mutate(self) -> Dict: # Get the string start = variable.source_mapping.start stop = variable.expression.source_mapping.start - old_str = node.source_mapping.content + old_str = variable.source_mapping.content new_str = old_str[: old_str.find("=")] line_no = variable.node_initialization.source_mapping.lines if not line_no[0] in self.dont_mutate_line: @@ -44,7 +44,7 @@ def _mutate(self) -> Dict: # Get the string start = variable.source_mapping.start stop = variable.expression.source_mapping.start - old_str = node.source_mapping.content + old_str = variable.source_mapping.content new_str = old_str[: old_str.find("=")] line_no = variable.source_mapping.lines if not line_no[0] in self.dont_mutate_line: diff --git a/slither/tools/mutator/mutators/ROR.py b/slither/tools/mutator/mutators/ROR.py index aea209f4b..8c13ce672 100644 --- a/slither/tools/mutator/mutators/ROR.py +++ b/slither/tools/mutator/mutators/ROR.py @@ -40,7 +40,7 @@ def _mutate(self) -> Dict: line_no = node.source_mapping.lines if not line_no[0] in self.dont_mutate_line: # Replace the expression with true - new_str = f"{old_str.split(ir.type.value)[0]} {op.value} {old_str.split(ir.type.value)[1]}" + new_str = f"{old_str.split(ir.type.value)[0]}{op.value}{old_str.split(ir.type.value)[1]}" create_patch_with_line( result, self.in_file, From 5b03e0a153abf66b7ede75ec92a6ef622bfb4d85 Mon Sep 17 00:00:00 2001 From: bohendo Date: Mon, 27 Jan 2025 15:23:00 -0500 Subject: [PATCH 5/8] try/catch mutant generation --- slither/tools/mutator/mutators/abstract_mutator.py | 11 ++++++++--- .../tools/mutator/utils/testing_generated_mutant.py | 4 +--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/slither/tools/mutator/mutators/abstract_mutator.py b/slither/tools/mutator/mutators/abstract_mutator.py index 2e99466d9..21ce52ebe 100644 --- a/slither/tools/mutator/mutators/abstract_mutator.py +++ b/slither/tools/mutator/mutators/abstract_mutator.py @@ -6,6 +6,7 @@ from slither.formatters.utils.patches import apply_patch, create_diff from slither.tools.mutator.utils.testing_generated_mutant import test_patch from slither.core.declarations import Contract +from slither.utils.colors import red logger = logging.getLogger("Slither-Mutate") @@ -70,13 +71,17 @@ def __init__( # pylint: disable=too-many-arguments @abc.abstractmethod def _mutate(self) -> Dict: - """TODO Documentation""" + """Abstract placeholder, will be overwritten by each mutator""" return {} # pylint: disable=too-many-branches def mutate(self) -> Tuple[List[int], List[int], List[int]]: - # call _mutate function from different mutators - (all_patches) = self._mutate() + all_patches: Dict = {} + try: + # call _mutate function from different mutators + (all_patches) = self._mutate() + except Exception as e: + logger.error(red("%s mutator failed in %s: %s"), self.NAME, self.contract.name, str(e)) if "patches" not in all_patches: logger.debug("No patches found by %s", self.NAME) return [0, 0, 0], [0, 0, 0], self.dont_mutate_line diff --git a/slither/tools/mutator/utils/testing_generated_mutant.py b/slither/tools/mutator/utils/testing_generated_mutant.py index d484ff68f..d5725485b 100644 --- a/slither/tools/mutator/utils/testing_generated_mutant.py +++ b/slither/tools/mutator/utils/testing_generated_mutant.py @@ -109,9 +109,7 @@ def test_patch( # pylint: disable=too-many-arguments create_mutant_file(output_folder, file, generator_name) logger.info( - red( - f"[{generator_name}] Line {patch['line_number']}: '{patch['old_string']}' ==> '{patch['new_string']}' --> UNCAUGHT" - ) + f"[{generator_name}] Line {patch['line_number']}: '{patch['old_string']}' ==> '{patch['new_string']}' --> UNCAUGHT" ) reset_file(file) From 87fb412ea0e87dceeceb7ff8c20a76a556da363a Mon Sep 17 00:00:00 2001 From: bohendo Date: Mon, 27 Jan 2025 15:42:13 -0500 Subject: [PATCH 6/8] fix formatting --- slither/core/source_mapping/source_mapping.py | 6 +++++- slither/tools/mutator/mutators/AOR.py | 2 +- slither/tools/mutator/mutators/BOR.py | 2 +- slither/tools/mutator/mutators/RR.py | 7 +++++-- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/slither/core/source_mapping/source_mapping.py b/slither/core/source_mapping/source_mapping.py index 61545c8f5..59d59ad11 100644 --- a/slither/core/source_mapping/source_mapping.py +++ b/slither/core/source_mapping/source_mapping.py @@ -79,7 +79,11 @@ def content(self) -> str: # If the compilation unit was not initialized, it means that the set_offset was never called # on the corresponding object, which should not happen assert self.compilation_unit - return self.compilation_unit.core.source_code[self.filename.absolute].encode("utf-8")[self.start : self.end].decode("utf-8") + return ( + self.compilation_unit.core.source_code[self.filename.absolute] + .encode("utf-8")[self.start : self.end] + .decode("utf-8") + ) @property def content_hash(self) -> str: diff --git a/slither/tools/mutator/mutators/AOR.py b/slither/tools/mutator/mutators/AOR.py index a9e816f9e..1e9008efe 100644 --- a/slither/tools/mutator/mutators/AOR.py +++ b/slither/tools/mutator/mutators/AOR.py @@ -79,7 +79,7 @@ def _mutate(self) -> Dict: if not line_no[0] in self.dont_mutate_line: halves = old_str.split(ir.type.value) if len(halves) != 2: - continue # skip if assembly + continue # skip if assembly new_str = f"{halves[0]}{op.value}{halves[1]}" create_patch_with_line( result, diff --git a/slither/tools/mutator/mutators/BOR.py b/slither/tools/mutator/mutators/BOR.py index d6638daf8..2926cf1c0 100644 --- a/slither/tools/mutator/mutators/BOR.py +++ b/slither/tools/mutator/mutators/BOR.py @@ -37,7 +37,7 @@ def _mutate(self) -> Dict: # Replace the expression with true halves = old_str.split(ir.type.value) if len(halves) != 2: - continue # skip if assembly + continue # skip if assembly new_str = f"{halves[0]}{op.value}{halves[1]}" create_patch_with_line( result, diff --git a/slither/tools/mutator/mutators/RR.py b/slither/tools/mutator/mutators/RR.py index 174daa671..1bcc12e40 100644 --- a/slither/tools/mutator/mutators/RR.py +++ b/slither/tools/mutator/mutators/RR.py @@ -3,6 +3,7 @@ from slither.tools.mutator.utils.patch import create_patch_with_line from slither.tools.mutator.mutators.abstract_mutator import AbstractMutator + class RR(AbstractMutator): # pylint: disable=too-few-public-methods NAME = "RR" HELP = "Revert Replacement" @@ -25,8 +26,10 @@ def _mutate(self) -> Dict: old_str = node.source_mapping.content line_no = node.source_mapping.lines[0] if not line_no in self.dont_mutate_line: - if node.type == NodeType.RETURN and not old_str.lstrip().startswith("return"): - continue # skip the return declarations in fn signatures + if node.type == NodeType.RETURN and not old_str.lstrip().startswith( + "return" + ): + continue # skip the return declarations in fn signatures if not old_str.lstrip().startswith("revert"): new_str = "revert()" create_patch_with_line( From af8e5cfb05d28a13669e54c9c118fb77c75daf98 Mon Sep 17 00:00:00 2001 From: bohendo Date: Mon, 27 Jan 2025 15:52:29 -0500 Subject: [PATCH 7/8] bugfixes & fix pylint --- slither/tools/mutator/mutators/LIR.py | 4 ++-- slither/tools/mutator/mutators/MVIV.py | 4 ++-- slither/tools/mutator/mutators/abstract_mutator.py | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/slither/tools/mutator/mutators/LIR.py b/slither/tools/mutator/mutators/LIR.py index d2ad3e5b3..46d816e26 100644 --- a/slither/tools/mutator/mutators/LIR.py +++ b/slither/tools/mutator/mutators/LIR.py @@ -36,7 +36,7 @@ def _mutate(self) -> Dict: # pylint: disable=too-many-branches # Get the string start = variable.source_mapping.start stop = start + variable.source_mapping.length - old_str = node.source_mapping.content + old_str = variable.source_mapping.content line_no = variable.node_initialization.source_mapping.lines if not line_no[0] in self.dont_mutate_line: for value in literal_replacements: @@ -67,7 +67,7 @@ def _mutate(self) -> Dict: # pylint: disable=too-many-branches literal_replacements.append("-1") start = variable.source_mapping.start stop = start + variable.source_mapping.length - old_str = node.source_mapping.content + old_str = variable.source_mapping.content line_no = variable.source_mapping.lines if not line_no[0] in self.dont_mutate_line: for new_value in literal_replacements: diff --git a/slither/tools/mutator/mutators/MVIV.py b/slither/tools/mutator/mutators/MVIV.py index d51414a7d..1e14d1177 100644 --- a/slither/tools/mutator/mutators/MVIV.py +++ b/slither/tools/mutator/mutators/MVIV.py @@ -24,7 +24,7 @@ def _mutate(self) -> Dict: # Get the string start = variable.source_mapping.start stop = variable.expression.source_mapping.start - old_str = node.source_mapping.content + old_str = variable.source_mapping.content new_str = old_str[: old_str.find("=")] line_no = variable.node_initialization.source_mapping.lines if not line_no[0] in self.dont_mutate_line: @@ -43,7 +43,7 @@ def _mutate(self) -> Dict: if variable.initialized and isinstance(variable.expression, Literal): start = variable.source_mapping.start stop = variable.expression.source_mapping.start - old_str = node.source_mapping.content + old_str = variable.source_mapping.content new_str = old_str[: old_str.find("=")] line_no = variable.source_mapping.lines if not line_no[0] in self.dont_mutate_line: diff --git a/slither/tools/mutator/mutators/abstract_mutator.py b/slither/tools/mutator/mutators/abstract_mutator.py index 21ce52ebe..1c7274407 100644 --- a/slither/tools/mutator/mutators/abstract_mutator.py +++ b/slither/tools/mutator/mutators/abstract_mutator.py @@ -77,6 +77,7 @@ def _mutate(self) -> Dict: # pylint: disable=too-many-branches def mutate(self) -> Tuple[List[int], List[int], List[int]]: all_patches: Dict = {} + # pylint: disable=broad-exception-caught try: # call _mutate function from different mutators (all_patches) = self._mutate() From 9fbb9aa4c519391667b610091cab17ad10af7724 Mon Sep 17 00:00:00 2001 From: bohendo Date: Wed, 5 Feb 2025 15:20:59 -0500 Subject: [PATCH 8/8] revert byte conversion in Source.content --- slither/core/source_mapping/source_mapping.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/slither/core/source_mapping/source_mapping.py b/slither/core/source_mapping/source_mapping.py index 59d59ad11..355aa5538 100644 --- a/slither/core/source_mapping/source_mapping.py +++ b/slither/core/source_mapping/source_mapping.py @@ -79,11 +79,7 @@ def content(self) -> str: # If the compilation unit was not initialized, it means that the set_offset was never called # on the corresponding object, which should not happen assert self.compilation_unit - return ( - self.compilation_unit.core.source_code[self.filename.absolute] - .encode("utf-8")[self.start : self.end] - .decode("utf-8") - ) + return self.compilation_unit.core.source_code[self.filename.absolute][self.start : self.end] @property def content_hash(self) -> str: