IR: create ChildExpression, and assign the expression to each IR

pull/238/head
Josselin 5 years ago
parent a4428211a3
commit 04480e6d38
  1. 12
      slither/core/children/child_expression.py
  2. 68
      slither/slithir/convert.py
  3. 3
      slither/slithir/operations/operation.py
  4. 6
      slither/slithir/operations/phi.py
  5. 2
      slither/slithir/utils/ssa.py
  6. 25
      slither/visitors/slithir/expression_to_slithir.py
  7. 0
      utils/slither_format/utils/usages.py

@ -0,0 +1,12 @@
class ChildExpression:
def __init__(self):
super(ChildExpression, self).__init__()
self._expression = None
def set_expression(self, expression):
self._expression = expression
@property
def expression(self):
return self._expression

@ -45,10 +45,14 @@ def convert_expression(expression, node):
if isinstance(expression, Literal) and node.type in [NodeType.IF, NodeType.IFLOOP]:
cst = Constant(expression.value, expression.type)
result = [Condition(cst)]
cond = Condition(cst)
cond.set_expression(expression)
result = [cond]
return result
if isinstance(expression, Identifier) and node.type in [NodeType.IF, NodeType.IFLOOP]:
result = [Condition(expression.value)]
cond = Condition(expression.value)
cond.set_expression(expression)
result = [cond]
return result
@ -60,11 +64,15 @@ def convert_expression(expression, node):
if result:
if node.type in [NodeType.IF, NodeType.IFLOOP]:
assert isinstance(result[-1], (OperationWithLValue))
result.append(Condition(result[-1].lvalue))
cond = Condition(result[-1].lvalue)
cond.set_expression(expression)
result.append(cond)
elif node.type == NodeType.RETURN:
# May return None
if isinstance(result[-1], (OperationWithLValue)):
result.append(Return(result[-1].lvalue))
r = Return(result[-1].lvalue)
r.set_expression(expression)
result.append(r)
return result
@ -326,6 +334,7 @@ def _convert_type_contract(ir, slither):
assignment = Assignment(ir.lvalue,
Constant(str(bytecode)),
ElementaryType('bytes'))
assignment.set_expression(ir.expression)
assignment.lvalue.set_type(ElementaryType('bytes'))
return assignment
if ir.variable_right == 'runtimeCode':
@ -338,12 +347,14 @@ def _convert_type_contract(ir, slither):
assignment = Assignment(ir.lvalue,
Constant(str(bytecode)),
ElementaryType('bytes'))
assignment.set_expression(ir.expression)
assignment.lvalue.set_type(ElementaryType('bytes'))
return assignment
if ir.variable_right == 'name':
assignment = Assignment(ir.lvalue,
Constant(contract.name),
ElementaryType('string'))
assignment.set_expression(ir.expression)
assignment.lvalue.set_type(ElementaryType('string'))
return assignment
@ -441,14 +452,18 @@ def propagate_types(ir, node):
# TODO we should convert the reference to a temporary if the member is a length or a balance
if ir.variable_right == 'length' and not isinstance(ir.variable_left, Contract) and isinstance(ir.variable_left.type, (ElementaryType, ArrayType)):
length = Length(ir.variable_left, ir.lvalue)
length.set_expression(ir.expression)
length.lvalue.points_to = ir.variable_left
return length
if ir.variable_right == 'balance'and not isinstance(ir.variable_left, Contract) and isinstance(ir.variable_left.type, ElementaryType):
return Balance(ir.variable_left, ir.lvalue)
b = Balance(ir.variable_left, ir.lvalue)
b.set_expression(ir.expression)
return b
if ir.variable_right == 'selector' and isinstance(ir.variable_left.type, Function):
assignment = Assignment(ir.lvalue,
Constant(str(get_function_id(ir.variable_left.type.full_name))),
ElementaryType('bytes4'))
assignment.set_expression(ir.expression)
assignment.lvalue.set_type(ElementaryType('bytes4'))
return assignment
if isinstance(ir.variable_left, TemporaryVariable) and isinstance(ir.variable_left.type, TypeInformation):
@ -529,6 +544,7 @@ def extract_tmp_call(ins, contract):
if isinstance(ins.called, Variable) and isinstance(ins.called.type, FunctionType):
call = InternalDynamicCall(ins.lvalue, ins.called, ins.called.type)
call.set_expression(ins.expression)
call.call_id = ins.call_id
return call
if isinstance(ins.ori, Member):
@ -536,23 +552,28 @@ def extract_tmp_call(ins, contract):
if ins.ori.variable_left in contract.inheritance + [contract]:
if str(ins.ori.variable_right) in [f.name for f in contract.functions]:
internalcall = InternalCall((ins.ori.variable_right, ins.ori.variable_left.name), ins.nbr_arguments, ins.lvalue, ins.type_call)
internalcall.set_expression(ins.expression)
internalcall.call_id = ins.call_id
return internalcall
if str(ins.ori.variable_right) in [f.name for f in contract.events]:
eventcall = EventCall(ins.ori.variable_right)
eventcall.set_expression(ins.expression)
eventcall.call_id = ins.call_id
return eventcall
if isinstance(ins.ori.variable_left, Contract):
st = ins.ori.variable_left.get_structure_from_name(ins.ori.variable_right)
if st:
op = NewStructure(st, ins.lvalue)
op.set_expression(ins.expression)
op.call_id = ins.call_id
return op
libcall = LibraryCall(ins.ori.variable_left, ins.ori.variable_right, ins.nbr_arguments, ins.lvalue, ins.type_call)
libcall.set_expression(ins.expression)
libcall.call_id = ins.call_id
return libcall
msgcall = HighLevelCall(ins.ori.variable_left, ins.ori.variable_right, ins.nbr_arguments, ins.lvalue, ins.type_call)
msgcall.call_id = ins.call_id
msgcall.set_expression(ins.expression)
return msgcall
if isinstance(ins.ori, TmpCall):
@ -562,29 +583,42 @@ def extract_tmp_call(ins, contract):
if str(ins.called) == 'block.blockhash':
ins.called = SolidityFunction('blockhash(uint256)')
elif str(ins.called) == 'this.balance':
return SolidityCall(SolidityFunction('this.balance()'), ins.nbr_arguments, ins.lvalue, ins.type_call)
s = SolidityCall(SolidityFunction('this.balance()'), ins.nbr_arguments, ins.lvalue, ins.type_call)
s.set_expression(ins.expression)
return s
if isinstance(ins.called, SolidityFunction):
return SolidityCall(ins.called, ins.nbr_arguments, ins.lvalue, ins.type_call)
s = SolidityCall(ins.called, ins.nbr_arguments, ins.lvalue, ins.type_call)
s.set_expression(ins.expression)
return s
if isinstance(ins.ori, TmpNewElementaryType):
return NewElementaryType(ins.ori.type, ins.lvalue)
n = NewElementaryType(ins.ori.type, ins.lvalue)
n.set_expression(ins.expression)
return n
if isinstance(ins.ori, TmpNewContract):
op = NewContract(Constant(ins.ori.contract_name), ins.lvalue)
op.set_expression(ins.expression)
op.call_id = ins.call_id
return op
if isinstance(ins.ori, TmpNewArray):
return NewArray(ins.ori.depth, ins.ori.array_type, ins.lvalue)
n = NewArray(ins.ori.depth, ins.ori.array_type, ins.lvalue)
n.set_expression(ins.expression)
return n
if isinstance(ins.called, Structure):
op = NewStructure(ins.called, ins.lvalue)
op.set_expression(ins.expression)
op.call_id = ins.call_id
op.set_expression(ins.expression)
return op
if isinstance(ins.called, Event):
return EventCall(ins.called.name)
e = EventCall(ins.called.name)
e.set_expression(ins.expression)
return e
raise Exception('Not extracted {} {}'.format(type(ins.called), ins))
@ -606,11 +640,15 @@ def convert_to_low_level(ir):
"""
if ir.function_name == 'transfer':
assert len(ir.arguments) == 1
prev_ir = ir
ir = Transfer(ir.destination, ir.arguments[0])
ir.set_expression(prev_ir.expression)
return ir
elif ir.function_name == 'send':
assert len(ir.arguments) == 1
prev_ir = ir
ir = Send(ir.destination, ir.arguments[0], ir.lvalue)
ir.set_expression(prev_ir.expression)
ir.lvalue.set_type(ElementaryType('bool'))
return ir
elif ir.destination.name == 'abi' and ir.function_name in ['encode',
@ -622,6 +660,7 @@ def convert_to_low_level(ir):
call = SolidityFunction('abi.{}()'.format(ir.function_name))
new_ir = SolidityCall(call, ir.nbr_arguments, ir.lvalue, ir.type_call)
new_ir.arguments = ir.arguments
new_ir.set_expression(ir.expression)
if isinstance(call.return_type, list) and len(call.return_type) == 1:
new_ir.lvalue.set_type(call.return_type[0])
else:
@ -640,6 +679,7 @@ def convert_to_low_level(ir):
new_ir.call_value = ir.call_value
new_ir.arguments = ir.arguments
new_ir.lvalue.set_type(ElementaryType('bool'))
new_ir.set_expression(ir.expression)
return new_ir
raise SlithIRError('Incorrect conversion to low level {}'.format(ir))
@ -662,9 +702,12 @@ def convert_to_push(ir, node):
val = TemporaryVariable(node)
operation = InitArray(ir.arguments[0], val)
operation.set_expression(ir.expression)
ret.append(operation)
prev_ir = ir
ir = Push(ir.destination, val)
ir.set_expression(prev_ir.expression)
length = Literal(len(operation.init_values), 'uint256')
t = operation.init_values[0].type
@ -674,18 +717,22 @@ def convert_to_push(ir, node):
if lvalue:
length = Length(ir.array, lvalue)
length.set_expression(ir.expression)
length.lvalue.points_to = ir.lvalue
ret.append(length)
return ret
prev_ir = ir
ir = Push(ir.destination, ir.arguments[0])
ir.set_expression(prev_ir.expression)
if lvalue:
ret = []
ret.append(ir)
length = Length(ir.array, lvalue)
length.set_expression(ir.expression)
length.lvalue.points_to = ir.lvalue
ret.append(length)
return ret
@ -701,6 +748,7 @@ def look_for_library(contract, ir, node, using_for, t):
ir.nbr_arguments,
ir.lvalue,
ir.type_call)
lib_call.set_expression(ir.expression)
lib_call.call_gas = ir.call_gas
lib_call.arguments = [ir.destination] + ir.arguments
new_ir = convert_type_library_call(lib_call, lib_contract)

@ -1,5 +1,6 @@
import abc
from slither.core.context.context import Context
from slither.core.children.child_expression import ChildExpression
from slither.core.children.child_node import ChildNode
from slither.utils.utils import unroll
@ -21,7 +22,7 @@ class AbstractOperation(abc.ABC):
"""
pass
class Operation(Context, ChildNode, AbstractOperation):
class Operation(Context, ChildExpression, ChildNode, AbstractOperation):
@property
def used(self):

@ -1,10 +1,6 @@
import logging
from slither.slithir.operations.lvalue import OperationWithLValue
from slither.core.variables.variable import Variable
from slither.slithir.variables import TupleVariable
from slither.core.declarations.function import Function
from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue
from slither.slithir.utils.utils import is_valid_lvalue
class Phi(OperationWithLValue):

@ -181,6 +181,8 @@ def generate_ssa_irs(node, local_variables_instances, all_local_variables_instan
tuple_variables_instances,
all_local_variables_instances)
new_ir.set_expression(ir.expression)
update_lvalue(new_ir,
node,
local_variables_instances,

@ -83,6 +83,7 @@ class ExpressionToSlithIR(ExpressionVisitor):
for idx in range(len(left)):
if not left[idx] is None:
operation = convert_assignment(left[idx], right[idx], expression.type, expression.expression_return_type)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, None)
else:
@ -90,6 +91,7 @@ class ExpressionToSlithIR(ExpressionVisitor):
for idx in range(len(left)):
if not left[idx] is None:
operation = Unpack(left[idx], right, idx)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, None)
else:
@ -97,10 +99,12 @@ class ExpressionToSlithIR(ExpressionVisitor):
# uint8[2] var = [1,2];
if isinstance(right, list):
operation = InitArray(right, left)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, left)
else:
operation = convert_assignment(left, right, expression.type, expression.expression_return_type)
operation.set_expression(expression)
self._result.append(operation)
# Return left to handle
# a = b = 1;
@ -112,6 +116,7 @@ class ExpressionToSlithIR(ExpressionVisitor):
val = TemporaryVariable(self._node)
operation = Binary(val, left, right, expression.type)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, val)
@ -130,11 +135,10 @@ class ExpressionToSlithIR(ExpressionVisitor):
else:
val = TemporaryVariable(self._node)
internal_call = InternalCall(called, len(args), val, expression.type_call)
internal_call.set_expression(expression)
self._result.append(internal_call)
set_val(expression, val)
else:
val = TemporaryVariable(self._node)
# If tuple
if expression.type_call.startswith('tuple(') and expression.type_call != 'tuple()':
val = TupleVariable(self._node)
@ -142,6 +146,7 @@ class ExpressionToSlithIR(ExpressionVisitor):
val = TemporaryVariable(self._node)
message_call = TmpCall(called, len(args), val, expression.type_call)
message_call.set_expression(expression)
self._result.append(message_call)
set_val(expression, val)
@ -165,8 +170,10 @@ class ExpressionToSlithIR(ExpressionVisitor):
init_array_right = left
left = init_array_val
operation = InitArray(init_array_right, init_array_val)
operation.set_expression(expression)
self._result.append(operation)
operation = Index(val, left, right, expression.type)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, val)
@ -178,18 +185,21 @@ class ExpressionToSlithIR(ExpressionVisitor):
expr = get(expression.expression)
val = ReferenceVariable(self._node)
member = Member(expr, Constant(expression.member_name), val)
member.set_expression(expression)
self._result.append(member)
set_val(expression, val)
def _post_new_array(self, expression):
val = TemporaryVariable(self._node)
operation = TmpNewArray(expression.depth, expression.array_type, val)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, val)
def _post_new_contract(self, expression):
val = TemporaryVariable(self._node)
operation = TmpNewContract(expression.contract_name, val)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, val)
@ -197,6 +207,7 @@ class ExpressionToSlithIR(ExpressionVisitor):
# TODO unclear if this is ever used?
val = TemporaryVariable(self._node)
operation = TmpNewElementaryType(expression.type, val)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, val)
@ -212,6 +223,7 @@ class ExpressionToSlithIR(ExpressionVisitor):
expr = get(expression.expression)
val = TemporaryVariable(self._node)
operation = TypeConversion(val, expr, expression.type)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, val)
@ -220,32 +232,40 @@ class ExpressionToSlithIR(ExpressionVisitor):
if expression.type in [UnaryOperationType.BANG, UnaryOperationType.TILD]:
lvalue = TemporaryVariable(self._node)
operation = Unary(lvalue, value, expression.type)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, lvalue)
elif expression.type in [UnaryOperationType.DELETE]:
operation = Delete(value, value)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, value)
elif expression.type in [UnaryOperationType.PLUSPLUS_PRE]:
operation = Binary(value, value, Constant("1"), BinaryType.ADDITION)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, value)
elif expression.type in [UnaryOperationType.MINUSMINUS_PRE]:
operation = Binary(value, value, Constant("1"), BinaryType.SUBTRACTION)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, value)
elif expression.type in [UnaryOperationType.PLUSPLUS_POST]:
lvalue = TemporaryVariable(self._node)
operation = Assignment(lvalue, value, value.type)
operation.set_expression(expression)
self._result.append(operation)
operation = Binary(value, value, Constant("1"), BinaryType.ADDITION)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, lvalue)
elif expression.type in [UnaryOperationType.MINUSMINUS_POST]:
lvalue = TemporaryVariable(self._node)
operation = Assignment(lvalue, value, value.type)
operation.set_expression(expression)
self._result.append(operation)
operation = Binary(value, value, Constant("1"), BinaryType.SUBTRACTION)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, lvalue)
elif expression.type in [UnaryOperationType.PLUS_PRE]:
@ -253,6 +273,7 @@ class ExpressionToSlithIR(ExpressionVisitor):
elif expression.type in [UnaryOperationType.MINUS_PRE]:
lvalue = TemporaryVariable(self._node)
operation = Binary(lvalue, Constant("0"), value, BinaryType.SUBTRACTION)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, lvalue)
else:

Loading…
Cancel
Save