mirror of https://github.com/crytic/slither
parent
37c23e11ce
commit
36eda1b3cb
@ -0,0 +1,47 @@ |
||||
from typing import Dict |
||||
from slither.slithir.operations import Binary, BinaryType |
||||
from slither.formatters.utils.patches import create_patch |
||||
from slither.tools.mutator.mutators.abstract_mutator import AbstractMutator, FaultNature, FaultClass |
||||
|
||||
logical_operators = [ |
||||
BinaryType.OROR, |
||||
BinaryType.ANDAND, |
||||
] |
||||
|
||||
class LOR(AbstractMutator): # pylint: disable=too-few-public-methods |
||||
NAME = "LOR" |
||||
HELP = "Logical operator replacement" |
||||
FAULTCLASS = FaultClass.Checking |
||||
FAULTNATURE = FaultNature.Missing |
||||
|
||||
def _mutate(self) -> Dict: |
||||
|
||||
result: Dict = {} |
||||
|
||||
contract = self.contract |
||||
|
||||
# Retrieve the file |
||||
in_file = contract.source_mapping.filename.absolute |
||||
# Retrieve the source code |
||||
in_file_str = contract.compilation_unit.core.source_code[in_file] |
||||
for function in contract.functions_and_modifiers_declared: |
||||
|
||||
for node in function.nodes: |
||||
for ir in node.irs: |
||||
if isinstance(ir, Binary) and ir.type in logical_operators: |
||||
alternative_ops = logical_operators[:] |
||||
alternative_ops.remove(ir.type) |
||||
|
||||
for op in alternative_ops: |
||||
|
||||
# Get the string |
||||
start = node.source_mapping.start |
||||
stop = start + node.source_mapping.length |
||||
old_str = in_file_str[start:stop] |
||||
line_no = node.source_mapping.lines |
||||
# Replace the expression with true |
||||
# new_str = f"{ir.variable_left} {op.value} {ir.variable_right}" |
||||
new_str = f"{old_str.split(ir.type.value)[0]} {op.value} {old_str.split(ir.type.value)[1]}" |
||||
|
||||
create_patch(result, in_file, start, stop, old_str, new_str, line_no[0]) |
||||
return result |
@ -1,43 +1,35 @@ |
||||
from typing import Dict, Tuple |
||||
from typing import Dict |
||||
|
||||
from slither.core.expressions import Literal |
||||
from slither.core.variables.variable import Variable |
||||
from slither.tools.mutator.mutators.abstract_mutator import AbstractMutator, FaultNature, FaultClass |
||||
from slither.tools.mutator.utils.generic_patching import remove_assignement |
||||
from slither.tools.mutator.utils.file_handling import create_mutant_file |
||||
|
||||
class MVIE(AbstractMutator): # pylint: disable=too-few-public-methods |
||||
NAME = "MVIE" |
||||
HELP = "variable initialization using an expression" |
||||
FAULTCLASS = FaultClass.Assignement |
||||
FAULTNATURE = FaultNature.Missing |
||||
VALID_MUTANTS_COUNT = 0 |
||||
INVALID_MUTANTS_COUNT = 0 |
||||
|
||||
def _mutate(self, test_cmd: str, test_dir: str, contract_name: str) -> Tuple[(Dict, int, int)]: |
||||
def _mutate(self) -> Dict: |
||||
|
||||
result: Dict = {} |
||||
variable: Variable |
||||
for contract in self.slither.contracts: |
||||
# if not contract.is_library: |
||||
# if not contract.is_interface: |
||||
if contract_name == str(contract.name): |
||||
# Create fault for state variables declaration |
||||
for variable in contract.state_variables_declared: |
||||
if variable.initialized: |
||||
# Cannot remove the initialization of constant variables |
||||
if variable.is_constant: |
||||
continue |
||||
|
||||
if not isinstance(variable.expression, Literal): |
||||
if(remove_assignement(variable, contract, result, test_cmd, test_dir)): |
||||
create_mutant_file(contract.source_mapping.filename.absolute, self.VALID_MUTANTS_COUNT, self.NAME) |
||||
|
||||
for function in contract.functions_declared + list(contract.modifiers_declared): |
||||
for variable in function.local_variables: |
||||
if variable.initialized and not isinstance(variable.expression, Literal): |
||||
if(remove_assignement(variable, contract, result, test_cmd, test_dir)): |
||||
create_mutant_file(contract.source_mapping.filename.absolute, self.VALID_MUTANTS_COUNT, self.NAME) |
||||
|
||||
|
||||
return (result, self.VALID_MUTANTS_COUNT, self.INVALID_MUTANTS_COUNT) |
||||
contract = self.contract |
||||
|
||||
# Create fault for state variables declaration |
||||
for variable in contract.state_variables_declared: |
||||
if variable.initialized: |
||||
# Cannot remove the initialization of constant variables |
||||
if variable.is_constant: |
||||
continue |
||||
|
||||
if not isinstance(variable.expression, Literal): |
||||
remove_assignement(variable, contract, result) |
||||
|
||||
for function in contract.functions_declared + list(contract.modifiers_declared): |
||||
for variable in function.local_variables: |
||||
if variable.initialized and not isinstance(variable.expression, Literal): |
||||
remove_assignement(variable, contract, result) |
||||
|
||||
return result |
||||
|
@ -0,0 +1,53 @@ |
||||
from typing import Dict |
||||
from collections import defaultdict |
||||
from slither.slithir.operations import Binary, BinaryType |
||||
from slither.formatters.utils.patches import create_patch |
||||
from slither.tools.mutator.mutators.abstract_mutator import AbstractMutator, FaultNature, FaultClass |
||||
|
||||
|
||||
relational_operators = [ |
||||
BinaryType.LESS, |
||||
BinaryType.GREATER, |
||||
BinaryType.LESS_EQUAL, |
||||
BinaryType.GREATER_EQUAL, |
||||
BinaryType.EQUAL, |
||||
BinaryType.NOT_EQUAL, |
||||
] |
||||
|
||||
|
||||
class ROR(AbstractMutator): # pylint: disable=too-few-public-methods |
||||
NAME = "ROR" |
||||
HELP = "Relational operator replacement" |
||||
FAULTCLASS = FaultClass.Checking |
||||
FAULTNATURE = FaultNature.Missing |
||||
|
||||
def _mutate(self) -> Dict: |
||||
|
||||
result: Dict = {} |
||||
# result["patches"] = defaultdict(list) |
||||
contract = self.contract |
||||
|
||||
for function in contract.functions_and_modifiers_declared: |
||||
for node in function.nodes: |
||||
for ir in node.irs: |
||||
# Retrieve the file |
||||
in_file = self.contract.source_mapping.filename.absolute |
||||
# Retrieve the source code |
||||
in_file_str = self.contract.compilation_unit.core.source_code[in_file] |
||||
|
||||
if isinstance(ir, Binary) and ir.type in relational_operators: |
||||
alternative_ops = relational_operators[:] |
||||
alternative_ops.remove(ir.type) |
||||
|
||||
for op in alternative_ops: |
||||
# Get the string |
||||
start = node.source_mapping.start |
||||
stop = start + node.source_mapping.length |
||||
old_str = 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(result, in_file, start, stop, old_str, new_str, line_no[0]) |
||||
|
||||
return result |
@ -0,0 +1,94 @@ |
||||
from typing import Dict |
||||
from slither.core.cfg.node import NodeType |
||||
from slither.formatters.utils.patches import create_patch |
||||
from slither.tools.mutator.mutators.abstract_mutator import AbstractMutator, FaultNature, FaultClass |
||||
import re |
||||
|
||||
solidity_rules = [ |
||||
"abi\.encode\( ==> abi.encodePacked(", |
||||
"abi\.encodePacked\( ==> abi.encode(", |
||||
"\.call([({]) ==> .delegatecall\\1", |
||||
"\.call([({]) ==> .staticcall\\1", |
||||
"\.delegatecall([({]) ==> .call\\1", |
||||
"\.delegatecall([({]) ==> .staticcall\\1", |
||||
"\.staticcall([({]) ==> .delegatecall\\1", |
||||
"\.staticcall([({]) ==> .call\\1", |
||||
"^now$ ==> 0", |
||||
"block.timestamp ==> 0", |
||||
"msg.value ==> 0", |
||||
"msg.value ==> 1", |
||||
"(\s)(wei|gwei) ==> \\1ether", |
||||
"(\s)(ether|gwei) ==> \\1wei", |
||||
"(\s)(wei|ether) ==> \\1gwei", |
||||
"(\s)(minutes|days|hours|weeks) ==> \\1seconds", |
||||
"(\s)(seconds|days|hours|weeks) ==> \\1minutes", |
||||
"(\s)(seconds|minutes|hours|weeks) ==> \\1days", |
||||
"(\s)(seconds|minutes|days|weeks) ==> \\1hours", |
||||
"(\s)(seconds|minutes|days|hours) ==> \\1weeks", |
||||
"(\s)(memory) ==> \\1storage", |
||||
"(\s)(storage) ==> \\1memory", |
||||
"(\s)(constant) ==> \\1immutable", |
||||
"addmod ==> mulmod", |
||||
"mulmod ==> addmod", |
||||
"msg.sender ==> tx.origin", |
||||
"tx.origin ==> msg.sender", |
||||
"([^u])fixed ==> \\1ufixed", |
||||
"ufixed ==> fixed", |
||||
"(u?)int16 ==> \\1int8", |
||||
"(u?)int32 ==> \\1int16", |
||||
"(u?)int64 ==> \\1int32", |
||||
"(u?)int128 ==> \\1int64", |
||||
"(u?)int256 ==> \\1int128" |
||||
] |
||||
|
||||
|
||||
class SBR(AbstractMutator): # pylint: disable=too-few-public-methods |
||||
NAME = "SBR" |
||||
HELP = 'Solidity Based Replacements' |
||||
FAULTCLASS = FaultClass.Checking |
||||
FAULTNATURE = FaultNature.Missing |
||||
|
||||
def _mutate(self) -> Dict: |
||||
|
||||
result: Dict = {} |
||||
contract = self.contract |
||||
# Retrieve the file |
||||
in_file = contract.source_mapping.filename.absolute |
||||
# Retrieve the source code |
||||
in_file_str = contract.compilation_unit.core.source_code[in_file] |
||||
|
||||
for function in contract.functions_and_modifiers_declared: |
||||
for node in function.nodes: |
||||
if node.type != NodeType.ENTRYPOINT: |
||||
# Get the string |
||||
start = node.source_mapping.start |
||||
stop = start + node.source_mapping.length |
||||
old_str = 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(result, in_file, start, stop, old_str, new_str, line_no[0]) |
||||
|
||||
for variable in contract.state_variables_declared: |
||||
node = variable.node_initialization |
||||
if node: |
||||
start = node.source_mapping.start |
||||
stop = start + node.source_mapping.length |
||||
old_str = 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(result, in_file, start, stop, old_str, new_str, line_no[0]) |
||||
return result |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,56 @@ |
||||
from typing import Dict |
||||
import re |
||||
from slither.core.expressions.unary_operation import UnaryOperationType |
||||
from slither.slithir.variables import Constant |
||||
from slither.core.variables.local_variable import LocalVariable |
||||
from slither.core.expressions.expression import Expression |
||||
from slither.formatters.utils.patches import create_patch |
||||
from slither.tools.mutator.mutators.abstract_mutator import AbstractMutator, FaultNature, FaultClass |
||||
from slither.core.cfg.node import NodeType |
||||
|
||||
|
||||
unary_operators = [ |
||||
UnaryOperationType.PLUSPLUS_PRE, |
||||
UnaryOperationType.MINUSMINUS_PRE, |
||||
UnaryOperationType.PLUSPLUS_POST, |
||||
UnaryOperationType.MINUSMINUS_POST, |
||||
UnaryOperationType.MINUS_PRE, |
||||
] |
||||
|
||||
|
||||
class UOI(AbstractMutator): # pylint: disable=too-few-public-methods |
||||
NAME = "UOI" |
||||
HELP = "Unary operator insertion" |
||||
FAULTCLASS = FaultClass.Checking |
||||
FAULTNATURE = FaultNature.Missing |
||||
|
||||
def _mutate(self) -> Dict: |
||||
|
||||
result: Dict = {} |
||||
|
||||
contract = self.contract |
||||
|
||||
# Retrieve the file |
||||
in_file = contract.source_mapping.filename.absolute |
||||
# Retrieve the source code |
||||
in_file_str = contract.compilation_unit.core.source_code[in_file] |
||||
|
||||
for function in contract.functions_and_modifiers_declared: |
||||
for node in function.nodes: |
||||
if (node.type == NodeType.EXPRESSION): |
||||
for op in unary_operators: |
||||
if str(op) in str(node.expression): |
||||
for i in node.variables_written: |
||||
print(i) |
||||
# Get the string |
||||
start = node.source_mapping.start |
||||
stop = start + node.source_mapping.length |
||||
old_str = in_file_str[start:stop] |
||||
# print(old_str) |
||||
# Replace the expression with true |
||||
# new_str = old_str.replace(str(operand), f"{str(op)}{operand}") |
||||
# new_str = re.sub(r'(\w+)\+\+', r'++\1', text) |
||||
# print(new_str) |
||||
# create_patch(result, in_file, start, stop, old_str, new_str) |
||||
print(result) |
||||
return result |
@ -1,4 +1,9 @@ |
||||
# pylint: disable=unused-import |
||||
# from slither.tools.mutator.mutators.MVIV import MVIV |
||||
# from slither.tools.mutator.mutators.MVIE import MVIE |
||||
from slither.tools.mutator.mutators.MIA import MIA |
||||
# from slither.tools.mutator.mutators.MIA import MIA |
||||
from slither.tools.mutator.mutators.ROR import ROR |
||||
# from slither.tools.mutator.mutators.LOR import LOR |
||||
# from slither.tools.mutator.mutators.UOI import UOI |
||||
# from slither.tools.mutator.mutators.SBR import SBR |
||||
|
||||
|
Loading…
Reference in new issue