Add gas/value support for internal dynamic call (close #135)

pull/132/head
Josselin 6 years ago
parent 889edd2952
commit 3db412a7d5
  1. 9
      slither/slithir/convert.py
  2. 41
      slither/slithir/operations/internal_dynamic_call.py

@ -139,7 +139,7 @@ def propage_type_and_convert_call(result, node):
assert ins.get_type() == ArgumentType.CALL assert ins.get_type() == ArgumentType.CALL
call_data.append(ins.argument) call_data.append(ins.argument)
if isinstance(ins, (HighLevelCall, NewContract)): if isinstance(ins, (HighLevelCall, NewContract, InternalDynamicCall)):
if ins.call_id in calls_value: if ins.call_id in calls_value:
ins.call_value = calls_value[ins.call_id] ins.call_value = calls_value[ins.call_id]
if ins.call_id in calls_gas: if ins.call_id in calls_gas:
@ -668,6 +668,11 @@ def remove_unused(result):
def extract_tmp_call(ins): def extract_tmp_call(ins):
assert isinstance(ins, TmpCall) assert isinstance(ins, TmpCall)
if isinstance(ins.called, Variable) and isinstance(ins.called.type, FunctionType):
call = InternalDynamicCall(ins.lvalue, ins.called, ins.called.type)
call.call_id = ins.call_id
return call
if isinstance(ins.ori, Member): if isinstance(ins.ori, Member):
if isinstance(ins.ori.variable_left, Contract): if isinstance(ins.ori.variable_left, Contract):
st = ins.ori.variable_left.get_structure_from_name(ins.ori.variable_right) st = ins.ori.variable_left.get_structure_from_name(ins.ori.variable_right)
@ -713,8 +718,6 @@ def extract_tmp_call(ins):
if isinstance(ins.called, Event): if isinstance(ins.called, Event):
return EventCall(ins.called.name) return EventCall(ins.called.name)
if isinstance(ins.called, Variable) and isinstance(ins.called.type, FunctionType):
return InternalDynamicCall(ins.lvalue, ins.called, ins.called.type)
raise Exception('Not extracted {} {}'.format(type(ins.called), ins)) raise Exception('Not extracted {} {}'.format(type(ins.called), ins))

@ -17,6 +17,10 @@ class InternalDynamicCall(Call, OperationWithLValue):
self._function_type = function_type self._function_type = function_type
self._lvalue = lvalue self._lvalue = lvalue
self._callid = None # only used if gas/value != 0
self._call_value = None
self._call_gas = None
@property @property
def read(self): def read(self):
return self._unroll(self.arguments) + [self.function] return self._unroll(self.arguments) + [self.function]
@ -29,16 +33,49 @@ class InternalDynamicCall(Call, OperationWithLValue):
def function_type(self): def function_type(self):
return self._function_type return self._function_type
@property
def call_value(self):
return self._call_value
@call_value.setter
def call_value(self, v):
self._call_value = v
@property
def call_gas(self):
return self._call_gas
@call_gas.setter
def call_gas(self, v):
self._call_gas = v
@property
def call_id(self):
return self._callid
@call_id.setter
def call_id(self, c):
self._callid = c
def __str__(self): def __str__(self):
value = ''
gas = ''
args = [str(a) for a in self.arguments] args = [str(a) for a in self.arguments]
if self.call_value:
value = 'value:{}'.format(self.call_value)
if self.call_gas:
gas = 'gas:{}'.format(self.call_gas)
if not self.lvalue: if not self.lvalue:
lvalue = '' lvalue = ''
elif isinstance(self.lvalue.type, (list,)): elif isinstance(self.lvalue.type, (list,)):
lvalue = '{}({}) = '.format(self.lvalue, ','.join(str(x) for x in self.lvalue.type)) lvalue = '{}({}) = '.format(self.lvalue, ','.join(str(x) for x in self.lvalue.type))
else: else:
lvalue = '{}({}) = '.format(self.lvalue, self.lvalue.type) lvalue = '{}({}) = '.format(self.lvalue, self.lvalue.type)
txt = '{}INTERNAL_DYNAMIC_CALL {}({})' txt = '{}INTERNAL_DYNAMIC_CALL {}({}) {} {}'
return txt.format(lvalue, return txt.format(lvalue,
self.function.name, self.function.name,
','.join(args)) ','.join(args),
value,
gas)

Loading…
Cancel
Save