|
|
@ -2,7 +2,12 @@ from typing import Dict |
|
|
|
from slither.slithir.operations import Binary, BinaryType |
|
|
|
from slither.slithir.operations import Binary, BinaryType |
|
|
|
from slither.tools.mutator.utils.patch import create_patch_with_line |
|
|
|
from slither.tools.mutator.utils.patch import create_patch_with_line |
|
|
|
from slither.tools.mutator.mutators.abstract_mutator import AbstractMutator |
|
|
|
from slither.tools.mutator.mutators.abstract_mutator import AbstractMutator |
|
|
|
|
|
|
|
from slither.core.variables.variable import Variable |
|
|
|
from slither.core.expressions.unary_operation import UnaryOperation |
|
|
|
from slither.core.expressions.unary_operation import UnaryOperation |
|
|
|
|
|
|
|
from slither.core.expressions.call_expression import CallExpression |
|
|
|
|
|
|
|
from slither.core.expressions.member_access import MemberAccess |
|
|
|
|
|
|
|
from slither.core.expressions.identifier import Identifier |
|
|
|
|
|
|
|
from slither.core.solidity_types.array_type import ArrayType |
|
|
|
|
|
|
|
|
|
|
|
arithmetic_operators = [ |
|
|
|
arithmetic_operators = [ |
|
|
|
BinaryType.ADDITION, |
|
|
|
BinaryType.ADDITION, |
|
|
@ -27,7 +32,39 @@ class AOR(AbstractMutator): # pylint: disable=too-few-public-methods |
|
|
|
ir_expression = node.expression |
|
|
|
ir_expression = node.expression |
|
|
|
except: # pylint: disable=bare-except |
|
|
|
except: # pylint: disable=bare-except |
|
|
|
continue |
|
|
|
continue |
|
|
|
for ir in node.irs: |
|
|
|
|
|
|
|
|
|
|
|
# Special cases handling .push and .pop on dynamic arrays. |
|
|
|
|
|
|
|
# The IR for these operations has a binary operation due to internal conversion |
|
|
|
|
|
|
|
# (see convert_to_push and convert_to_pop in slithir/convert.py) |
|
|
|
|
|
|
|
# however it's not present in the source code and should not be mutated. |
|
|
|
|
|
|
|
# pylint: disable=too-many-boolean-expressions |
|
|
|
|
|
|
|
if ( |
|
|
|
|
|
|
|
isinstance(ir_expression, CallExpression) |
|
|
|
|
|
|
|
and isinstance(ir_expression.called, MemberAccess) |
|
|
|
|
|
|
|
and ir_expression.called.member_name == "pop" |
|
|
|
|
|
|
|
and isinstance(ir_expression.called.expression, Identifier) |
|
|
|
|
|
|
|
and isinstance(ir_expression.called.expression.value, Variable) |
|
|
|
|
|
|
|
and isinstance(ir_expression.called.expression.value.type, ArrayType) |
|
|
|
|
|
|
|
): |
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# For a .push instruction we skip the last 6 IR operations |
|
|
|
|
|
|
|
# because they are fixed based on the internal conversion to the IR |
|
|
|
|
|
|
|
# while we need to look at the preceding instructions because |
|
|
|
|
|
|
|
# they might contain Binary IR to be mutated. |
|
|
|
|
|
|
|
# For example for a.push(3+x) it's correct to mutate 3+x. |
|
|
|
|
|
|
|
irs = ( |
|
|
|
|
|
|
|
node.irs[:-6] |
|
|
|
|
|
|
|
if isinstance(ir_expression, CallExpression) |
|
|
|
|
|
|
|
and isinstance(ir_expression.called, MemberAccess) |
|
|
|
|
|
|
|
and ir_expression.called.member_name == "push" |
|
|
|
|
|
|
|
and isinstance(ir_expression.called.expression, Identifier) |
|
|
|
|
|
|
|
and isinstance(ir_expression.called.expression.value, Variable) |
|
|
|
|
|
|
|
and isinstance(ir_expression.called.expression.value.type, ArrayType) |
|
|
|
|
|
|
|
else node.irs |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for ir in irs: |
|
|
|
if isinstance(ir, Binary) and ir.type in arithmetic_operators: |
|
|
|
if isinstance(ir, Binary) and ir.type in arithmetic_operators: |
|
|
|
if isinstance(ir_expression, UnaryOperation): |
|
|
|
if isinstance(ir_expression, UnaryOperation): |
|
|
|
continue |
|
|
|
continue |
|
|
|