updated quick

pull/2278/head
Vishnuram Rajkumar 9 months ago
parent 96e8adc39b
commit 48b6f6fee2
  1. 22
      slither/tools/mutator/__main__.py
  2. 8
      slither/tools/mutator/mutators/AOR.py
  3. 7
      slither/tools/mutator/mutators/ASOR.py
  4. 7
      slither/tools/mutator/mutators/BOR.py
  5. 5
      slither/tools/mutator/mutators/CR.py
  6. 13
      slither/tools/mutator/mutators/FHR.py
  7. 55
      slither/tools/mutator/mutators/LIR.py
  8. 8
      slither/tools/mutator/mutators/LOR.py
  9. 20
      slither/tools/mutator/mutators/MIA.py
  10. 40
      slither/tools/mutator/mutators/MVIE.py
  11. 38
      slither/tools/mutator/mutators/MVIV.py
  12. 8
      slither/tools/mutator/mutators/MWA.py
  13. 8
      slither/tools/mutator/mutators/ROR.py
  14. 7
      slither/tools/mutator/mutators/RR.py
  15. 28
      slither/tools/mutator/mutators/SBR.py
  16. 35
      slither/tools/mutator/mutators/UOR.py
  17. 14
      slither/tools/mutator/mutators/abstract_mutator.py
  18. 4
      slither/tools/mutator/utils/testing_generated_mutant.py

@ -169,10 +169,17 @@ def main() -> None:
# setting RR mutator as first mutator
mutators_list = _get_mutators(mutators_to_run)
for M in mutators_list:
CR_RR_list = []
duplicate_list = mutators_list.copy()
for M in duplicate_list:
if M.NAME == "RR":
mutators_list.remove(M)
mutators_list.insert(0, M)
CR_RR_list.insert(0,M)
elif M.NAME == "CR":
mutators_list.remove(M)
CR_RR_list.insert(1,M)
mutators_list = CR_RR_list + mutators_list
for filename in sol_file_list:
contract_name = os.path.split(filename)[1].split('.sol')[0]
@ -185,6 +192,7 @@ def main() -> None:
# count of valid mutants
v_count = 0
dont_mutate_lines = []
# mutation
try:
for compilation_unit_of_main_file in sl.compilation_units:
@ -198,13 +206,13 @@ def main() -> None:
logger.error("Can't find the contract")
else:
for M in mutators_list:
m = M(compilation_unit_of_main_file, int(timeout), test_command, test_directory, contract_instance, solc_remappings, verbose, output_folder)
count_valid, count_invalid = m.mutate()
m = M(compilation_unit_of_main_file, int(timeout), test_command, test_directory, contract_instance, solc_remappings, verbose, output_folder, dont_mutate_lines)
(count_valid, count_invalid, lines_list) = m.mutate()
v_count += count_valid
total_count += count_valid + count_invalid
if quick_flag:
if str(m.NAME) == 'RR' and v_count > 0:
break
dont_mutate_lines = lines_list
if not quick_flag:
dont_mutate_lines = []
except Exception as e:
logger.error(e)

@ -19,7 +19,6 @@ class AOR(AbstractMutator): # pylint: disable=too-few-public-methods
def _mutate(self) -> Dict:
result: Dict = {}
for function in self.contract.functions_and_modifiers_declared:
for node in function.nodes:
try:
@ -38,7 +37,8 @@ class AOR(AbstractMutator): # pylint: disable=too-few-public-methods
stop = start + node.source_mapping.length
old_str = self.in_file_str[start:stop]
line_no = node.source_mapping.lines
# Replace the expression with true
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, start, stop, old_str, new_str, line_no[0])
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]}"
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
return result

@ -42,7 +42,8 @@ class ASOR(AbstractMutator): # pylint: disable=too-few-public-methods
stop = start + node.source_mapping.length
old_str = self.in_file_str[start:stop]
line_no = node.source_mapping.lines
# Replace the expression with true
new_str = f"{old_str.split(str(ir.expression.type))[0]}{op}{old_str.split(str(ir.expression.type))[1]}"
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
if not line_no[0] in self.dont_mutate_line:
# Replace the expression with true
new_str = f"{old_str.split(str(ir.expression.type))[0]}{op}{old_str.split(str(ir.expression.type))[1]}"
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
return result

@ -31,7 +31,8 @@ class BOR(AbstractMutator): # pylint: disable=too-few-public-methods
stop = start + node.source_mapping.length
old_str = self.in_file_str[start:stop]
line_no = node.source_mapping.lines
# Replace the expression with true
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, start, stop, old_str, new_str, line_no[0])
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]}"
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
return result

@ -20,8 +20,9 @@ class CR(AbstractMutator): # pylint: disable=too-few-public-methods
stop = start + node.source_mapping.length
old_str = self.in_file_str[start:stop]
line_no = node.source_mapping.lines
new_str = "//" + old_str
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
if not line_no[0] in self.dont_mutate_line:
new_str = "//" + old_str
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
return result

@ -24,11 +24,12 @@ class FHR(AbstractMutator): # pylint: disable=too-few-public-methods
stop = start + function.source_mapping.content.find('{')
old_str = self.in_file_str[start:stop]
line_no = function.source_mapping.lines
for value in function_header_replacements:
left_value = value.split(" ==> ")[0]
right_value = value.split(" ==> ")[1]
if re.search(re.compile(left_value), old_str) != None:
new_str = re.sub(re.compile(left_value), right_value, old_str)
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
if not line_no[0] in self.dont_mutate_line:
for value in function_header_replacements:
left_value = value.split(" ==> ")[0]
right_value = value.split(" ==> ")[1]
if re.search(re.compile(left_value), old_str) != None:
new_str = re.sub(re.compile(left_value), right_value, old_str)
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
return result

@ -36,20 +36,20 @@ class LIR(AbstractMutator): # pylint: disable=too-few-public-methods
stop = start + variable.source_mapping.length
old_str = self.in_file_str[start:stop]
line_no = variable.node_initialization.source_mapping.lines
# line_no = [0]
for value in literal_replacements:
old_value = old_str[old_str.find("=")+1:].strip()
if old_value != value:
new_str = f"{old_str.split('=')[0]}= {value}"
create_patch_with_line(
result,
self.in_file,
start,
stop,
old_str,
new_str,
line_no[0]
)
if not line_no[0] in self.dont_mutate_line:
for value in literal_replacements:
old_value = old_str[old_str.find("=")+1:].strip()
if old_value != value:
new_str = f"{old_str.split('=')[0]}= {value}"
create_patch_with_line(
result,
self.in_file,
start,
stop,
old_str,
new_str,
line_no[0]
)
for function in self.contract.functions_and_modifiers_declared:
for variable in function.local_variables:
@ -65,18 +65,19 @@ class LIR(AbstractMutator): # pylint: disable=too-few-public-methods
stop = start + variable.source_mapping.length
old_str = self.in_file_str[start:stop]
line_no = variable.source_mapping.lines
for new_value in literal_replacements:
old_value = old_str[old_str.find("=")+1:].strip()
if old_value != new_value:
new_str = f"{old_str.split('=')[0]}= {new_value}"
create_patch_with_line(
result,
self.in_file,
start,
stop,
old_str,
new_str,
line_no[0]
)
if not line_no[0] in self.dont_mutate_line:
for new_value in literal_replacements:
old_value = old_str[old_str.find("=")+1:].strip()
if old_value != new_value:
new_str = f"{old_str.split('=')[0]}= {new_value}"
create_patch_with_line(
result,
self.in_file,
start,
stop,
old_str,
new_str,
line_no[0]
)
return result

@ -29,8 +29,8 @@ class LOR(AbstractMutator): # pylint: disable=too-few-public-methods
stop = start + node.source_mapping.length
old_str = self.in_file_str[start:stop]
line_no = node.source_mapping.lines
# Replace the expression with true
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, start, stop, old_str, new_str, line_no[0])
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]}"
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
return result

@ -20,16 +20,14 @@ class MIA(AbstractMutator): # pylint: disable=too-few-public-methods
stop = start + node.expression.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:
# Replace the expression with true and false
for value in ["true", "false"]:
new_str = value
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
if not isinstance(node.expression, UnaryOperation):
new_str = str(UnaryOperationType.BANG) + '(' + old_str + ')'
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
# Replace the expression with true and false
for value in ["true", "false"]:
new_str = value
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
if not isinstance(node.expression, UnaryOperation):
new_str = str(UnaryOperationType.BANG) + '(' + old_str + ')'
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
print(node.expression)
return result

@ -25,18 +25,18 @@ class MVIE(AbstractMutator): # pylint: disable=too-few-public-methods
start = variable.source_mapping.start
stop = variable.expression.source_mapping.start
old_str = self.in_file_str[start:stop]
new_str = old_str[: old_str.find("=")]
line_no = variable.node_initialization.source_mapping.lines
create_patch_with_line(
result,
self.in_file,
start,
stop + variable.expression.source_mapping.length,
old_str,
new_str,
line_no[0]
)
if not line_no[0] in self.dont_mutate_line:
create_patch_with_line(
result,
self.in_file,
start,
stop + variable.expression.source_mapping.length,
old_str,
new_str,
line_no[0]
)
for function in self.contract.functions_and_modifiers_declared:
for variable in function.local_variables:
@ -45,17 +45,17 @@ class MVIE(AbstractMutator): # pylint: disable=too-few-public-methods
start = variable.source_mapping.start
stop = variable.expression.source_mapping.start
old_str = self.in_file_str[start:stop]
new_str = old_str[: old_str.find("=")]
line_no = variable.source_mapping.lines
create_patch_with_line(
result,
self.in_file,
start,
stop + variable.expression.source_mapping.length,
old_str,
new_str,
line_no[0]
)
if not line_no[0] in self.dont_mutate_line:
create_patch_with_line(
result,
self.in_file,
start,
stop + variable.expression.source_mapping.length,
old_str,
new_str,
line_no[0]
)
return result

@ -27,15 +27,16 @@ class MVIV(AbstractMutator): # pylint: disable=too-few-public-methods
old_str = self.in_file_str[start:stop]
new_str = old_str[: old_str.find("=")]
line_no = variable.node_initialization.source_mapping.lines
create_patch_with_line(
result,
self.in_file,
start,
stop + variable.expression.source_mapping.length,
old_str,
new_str,
line_no[0]
)
if not line_no[0] in self.dont_mutate_line:
create_patch_with_line(
result,
self.in_file,
start,
stop + variable.expression.source_mapping.length,
old_str,
new_str,
line_no[0]
)
for function in self.contract.functions_and_modifiers_declared:
for variable in function.local_variables:
@ -45,14 +46,15 @@ class MVIV(AbstractMutator): # pylint: disable=too-few-public-methods
old_str = self.in_file_str[start:stop]
new_str = old_str[: old_str.find("=")]
line_no = variable.source_mapping.lines
create_patch_with_line(
result,
self.in_file,
start,
stop + variable.expression.source_mapping.length,
old_str,
new_str,
line_no[0]
)
if not line_no[0] in self.dont_mutate_line:
create_patch_with_line(
result,
self.in_file,
start,
stop + variable.expression.source_mapping.length,
old_str,
new_str,
line_no[0]
)
return result

@ -20,8 +20,8 @@ class MWA(AbstractMutator): # pylint: disable=too-few-public-methods
stop = start + node.source_mapping.length
old_str = self.in_file_str[start:stop]
line_no = node.source_mapping.lines
if not isinstance(node.expression, UnaryOperation):
new_str = str(UnaryOperationType.BANG) + '(' + old_str + ')'
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
if not line_no[0] in self.dont_mutate_line:
if not isinstance(node.expression, UnaryOperation):
new_str = str(UnaryOperationType.BANG) + '(' + old_str + ')'
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
return result

@ -33,9 +33,9 @@ class ROR(AbstractMutator): # pylint: disable=too-few-public-methods
stop = start + ir.expression.source_mapping.length
old_str = self.in_file_str[start:stop]
line_no = node.source_mapping.lines
# Replace the expression with true
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, start, stop, old_str, new_str, line_no[0])
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]}"
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
return result

@ -20,9 +20,10 @@ class RR(AbstractMutator): # pylint: disable=too-few-public-methods
stop = start + node.source_mapping.length
old_str = self.in_file_str[start:stop]
line_no = node.source_mapping.lines
if old_str != 'revert()':
new_str = 'revert()'
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
if not line_no[0] in self.dont_mutate_line:
if old_str != 'revert()':
new_str = 'revert()'
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
return result

@ -56,18 +56,19 @@ class SBR(AbstractMutator): # pylint: disable=too-few-public-methods
for function in self.contract.functions_and_modifiers_declared:
for node in function.nodes:
if node.type != NodeType.ENTRYPOINT:
if node.type != NodeType.ENTRYPOINT and node.type != NodeType.ENDIF and node.type != NodeType.ENDLOOP:
# 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
for value in solidity_rules:
left_value = value.split(" ==> ")[0]
right_value = value.split(" ==> ")[1]
if re.search(re.compile(left_value), old_str) != None:
new_str = re.sub(re.compile(left_value), right_value, old_str)
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
if not line_no[0] in self.dont_mutate_line:
for value in solidity_rules:
left_value = value.split(" ==> ")[0]
right_value = value.split(" ==> ")[1]
if re.search(re.compile(left_value), old_str) != None:
new_str = re.sub(re.compile(left_value), right_value, old_str)
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
for variable in self.contract.state_variables_declared:
node = variable.node_initialization
@ -76,12 +77,13 @@ class SBR(AbstractMutator): # pylint: disable=too-few-public-methods
stop = start + node.source_mapping.length
old_str = self.in_file_str[start:stop]
line_no = node.source_mapping.lines
for value in solidity_rules:
left_value = value.split(" ==> ")[0]
right_value = value.split(" ==> ")[1]
if re.search(re.compile(left_value), old_str) != None:
new_str = re.sub(re.compile(left_value), right_value, old_str)
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
if not line_no[0] in self.dont_mutate_line:
for value in solidity_rules:
left_value = value.split(" ==> ")[0]
right_value = value.split(" ==> ")[1]
if re.search(re.compile(left_value), old_str) != None:
new_str = re.sub(re.compile(left_value), right_value, old_str)
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
return result

@ -29,23 +29,24 @@ class UOR(AbstractMutator): # pylint: disable=too-few-public-methods
stop = start + node.source_mapping.length
old_str = self.in_file_str[start:stop]
line_no = node.source_mapping.lines
if isinstance(ir_expression, UnaryOperation) and ir_expression.type in unary_operators:
for op in unary_operators:
if not node.expression.is_prefix:
if node.expression.type != op:
variable_read = node.variables_read[0]
new_str = str(variable_read) + str(op)
if new_str != old_str and str(op) != '-':
if not line_no[0] in self.dont_mutate_line:
if isinstance(ir_expression, UnaryOperation) and ir_expression.type in unary_operators:
for op in unary_operators:
if not node.expression.is_prefix:
if node.expression.type != op:
variable_read = node.variables_read[0]
new_str = str(variable_read) + str(op)
if new_str != old_str and str(op) != '-':
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
new_str = str(op) + str(variable_read)
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
new_str = str(op) + str(variable_read)
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
else:
if node.expression.type != op:
variable_read = node.variables_read[0]
new_str = str(op) + str(variable_read)
if new_str != old_str and str(op) != '-':
else:
if node.expression.type != op:
variable_read = node.variables_read[0]
new_str = str(op) + str(variable_read)
if new_str != old_str and str(op) != '-':
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
new_str = str(variable_read) + str(op)
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
new_str = str(variable_read) + str(op)
create_patch_with_line(result, self.in_file, start, stop, old_str, new_str, line_no[0])
return result

@ -1,7 +1,7 @@
import abc
import logging
from enum import Enum
from typing import Optional, Dict, Tuple
from typing import Optional, Dict, Tuple, List
from slither.core.compilation_unit import SlitherCompilationUnit
# from slither.tools.doctor.utils import snip_section
from slither.formatters.utils.patches import apply_patch, create_diff
@ -41,6 +41,7 @@ class AbstractMutator(metaclass=abc.ABCMeta): # pylint: disable=too-few-public-
solc_remappings: str | None,
verbose: bool,
output_folder: str,
dont_mutate_line: List[int],
rate: int = 10,
seed: Optional[int] = None
) -> None:
@ -57,6 +58,7 @@ class AbstractMutator(metaclass=abc.ABCMeta): # pylint: disable=too-few-public-
self.contract = contract_instance
self.in_file = self.contract.source_mapping.filename.absolute
self.in_file_str = self.contract.compilation_unit.core.source_code[self.in_file]
self.dont_mutate_line = dont_mutate_line
if not self.NAME:
raise IncorrectMutatorInitialization(
@ -83,13 +85,12 @@ class AbstractMutator(metaclass=abc.ABCMeta): # pylint: disable=too-few-public-
"""TODO Documentation"""
return {}
def mutate(self) -> Tuple[int, int]:
def mutate(self) -> Tuple[int, int, List[int]]:
# call _mutate function from different mutators
(all_patches) = self._mutate()
if "patches" not in all_patches:
logger.debug(f"No patches found by {self.NAME}")
return (0,0)
return (0,0,self.dont_mutate_line)
for file in all_patches["patches"]:
original_txt = self.slither.source_code[file].encode("utf8")
@ -99,6 +100,8 @@ class AbstractMutator(metaclass=abc.ABCMeta): # pylint: disable=too-few-public-
for patch in patches:
# test the patch
flag = test_patch(file, patch, self.test_command, self.VALID_MUTANTS_COUNT, self.NAME, self.timeout, self.solc_remappings, self.verbose)
if (self.NAME == 'RR' or self.NAME == 'CR') and flag:
self.dont_mutate_line.append(patch['line_number'])
# count the valid and invalid mutants
if not flag:
self.INVALID_MUTANTS_COUNT += 1
@ -112,8 +115,7 @@ class AbstractMutator(metaclass=abc.ABCMeta): # pylint: disable=too-few-public-
# add valid mutant patches to a output file
with open(self.output_folder + "/patches_file.txt", 'a') as patches_file:
patches_file.write(diff + '\n')
return (self.VALID_MUTANTS_COUNT, self.INVALID_MUTANTS_COUNT)
return (self.VALID_MUTANTS_COUNT, self.INVALID_MUTANTS_COUNT, self.dont_mutate_line)

@ -9,7 +9,7 @@ from slither.tools.mutator.utils.file_handling import create_mutant_file, reset_
from slither.utils.colors import green, red
logger = logging.getLogger("Slither-Mutate")
# dont_mutate_line = {}
# function to compile the generated mutant
def compile_generated_mutant(file_path: str, mappings: str) -> bool:
try:
@ -58,8 +58,6 @@ def test_patch(file: str, patch: Dict, command: str, index: int, generator_name:
if(run_test_cmd(command, file, timeout)):
create_mutant_file(file, index, generator_name)
logger.info(green(f"String '{patch['old_string']}' replaced with '{patch['new_string']}' at line no. '{patch['line_number']}' ---> VALID\n"))
# if generator_name == 'RR':
# dont_mutate_line[patch['line_number']] = True
return True
reset_file(file)

Loading…
Cancel
Save