Merge pull request #2484 from crytic/dev-fix-aor-array

slither-mutate: (AOR) Fix for dynamic array operations
pull/2289/merge
alpharush 4 months ago committed by GitHub
commit 16cfaa7d08
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 39
      slither/tools/mutator/mutators/AOR.py

@ -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

Loading…
Cancel
Save