From 3db412a7d5b4718a9ff7b22e6971a7cf3e60fd86 Mon Sep 17 00:00:00 2001 From: Josselin Date: Fri, 18 Jan 2019 11:59:16 +0100 Subject: [PATCH] Add gas/value support for internal dynamic call (close #135) --- slither/slithir/convert.py | 9 ++-- .../operations/internal_dynamic_call.py | 41 ++++++++++++++++++- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index c095706e3..38772b26a 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -139,7 +139,7 @@ def propage_type_and_convert_call(result, node): assert ins.get_type() == ArgumentType.CALL call_data.append(ins.argument) - if isinstance(ins, (HighLevelCall, NewContract)): + if isinstance(ins, (HighLevelCall, NewContract, InternalDynamicCall)): if ins.call_id in calls_value: ins.call_value = calls_value[ins.call_id] if ins.call_id in calls_gas: @@ -668,6 +668,11 @@ def remove_unused(result): def extract_tmp_call(ins): 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.variable_left, Contract): 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): 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)) diff --git a/slither/slithir/operations/internal_dynamic_call.py b/slither/slithir/operations/internal_dynamic_call.py index 81a18a6c7..b1c08ca98 100644 --- a/slither/slithir/operations/internal_dynamic_call.py +++ b/slither/slithir/operations/internal_dynamic_call.py @@ -17,6 +17,10 @@ class InternalDynamicCall(Call, OperationWithLValue): self._function_type = function_type self._lvalue = lvalue + self._callid = None # only used if gas/value != 0 + self._call_value = None + self._call_gas = None + @property def read(self): return self._unroll(self.arguments) + [self.function] @@ -29,16 +33,49 @@ class InternalDynamicCall(Call, OperationWithLValue): def function_type(self): 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): + value = '' + gas = '' 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: lvalue = '' elif isinstance(self.lvalue.type, (list,)): lvalue = '{}({}) = '.format(self.lvalue, ','.join(str(x) for x in self.lvalue.type)) else: lvalue = '{}({}) = '.format(self.lvalue, self.lvalue.type) - txt = '{}INTERNAL_DYNAMIC_CALL {}({})' + txt = '{}INTERNAL_DYNAMIC_CALL {}({}) {} {}' return txt.format(lvalue, self.function.name, - ','.join(args)) + ','.join(args), + value, + gas)