Merge pull request #498 from crytic/dev-new-call-syntax

Add support for new C{value:1} syntax
pull/512/head
Feist Josselin 5 years ago committed by GitHub
commit 8c86c8a260
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 19
      slither/core/expressions/call_expression.py
  2. 21
      slither/core/expressions/new_contract.py
  3. 4
      slither/slithir/convert.py
  4. 17
      slither/slithir/operations/new_contract.py
  5. 9
      slither/slithir/tmp_operations/tmp_call.py
  6. 18
      slither/slithir/tmp_operations/tmp_new_contract.py
  7. 2
      slither/slithir/utils/ssa.py
  8. 8
      slither/solc_parsing/expressions/expression_parsing.py
  9. 2
      slither/visitors/expression/expression.py
  10. 10
      slither/visitors/slithir/expression_to_slithir.py

@ -14,6 +14,7 @@ class CallExpression(Expression):
# And converted later to the correct info (convert.py)
self._gas = None
self._value = None
self._salt = None
@property
def call_value(self):
@ -31,6 +32,14 @@ class CallExpression(Expression):
def call_gas(self, gas):
self._gas = gas
@property
def call_salt(self):
return self._salt
@call_salt.setter
def call_salt(self, salt):
self._salt = salt
@property
def called(self):
return self._called
@ -48,10 +57,8 @@ class CallExpression(Expression):
if self.call_gas or self.call_value:
gas = f'gas: {self.call_gas}' if self.call_gas else ''
value = f'value: {self.call_value}' if self.call_value else ''
if gas and value:
txt += '{' + f'{gas}, {value}' + '}'
elif gas:
txt += '{' + f'{gas}' + '}'
else:
txt += '{' + f'{value}' + '}'
salt = f'salt: {self.call_salt}' if self.call_salt else ''
if gas or value or salt:
options = [gas, value, salt]
txt += '{' + ','.join([o for o in options if o != '']) + '}'
return txt + '(' + ','.join([str(a) for a in self._arguments]) + ')'

@ -5,11 +5,32 @@ class NewContract(Expression):
def __init__(self, contract_name):
super(NewContract, self).__init__()
self._contract_name = contract_name
self._gas = None
self._value = None
self._salt = None
@property
def contract_name(self):
return self._contract_name
@property
def call_value(self):
return self._value
@call_value.setter
def call_value(self, v):
self._value = v
@property
def call_salt(self):
return self._salt
@call_salt.setter
def call_salt(self, salt):
self._salt = salt
def __str__(self):
return 'new ' + str(self._contract_name)

@ -668,6 +668,10 @@ def extract_tmp_call(ins, contract):
op = NewContract(Constant(ins.ori.contract_name), ins.lvalue)
op.set_expression(ins.expression)
op.call_id = ins.call_id
if ins.call_value:
op.call_value = ins.call_value
if ins.call_salt:
op.call_salt = ins.call_salt
return op
if isinstance(ins.ori, TmpNewArray):

@ -14,6 +14,7 @@ class NewContract(Call, OperationWithLValue):
self._lvalue = lvalue
self._callid = None # only used if gas/value != 0
self._call_value = None
self._call_salt = None
@property
def call_value(self):
@ -31,6 +32,14 @@ class NewContract(Call, OperationWithLValue):
def call_id(self, c):
self._callid = c
@property
def call_salt(self):
return self._call_salt
@call_salt.setter
def call_salt(self, s):
self._call_salt = s
@property
def contract_name(self):
return self._contract_name
@ -78,8 +87,10 @@ class NewContract(Call, OperationWithLValue):
# endregion
def __str__(self):
value = ''
options = ''
if self.call_value:
value = 'value:{}'.format(self.call_value)
options = 'value:{} '.format(self.call_value)
if self.call_salt:
options += 'salt:{} '.format(self.call_salt)
args = [str(a) for a in self.arguments]
return '{} = new {}({}) {}'.format(self.lvalue, self.contract_name, ','.join(args), value)
return '{} = new {}({}) {}'.format(self.lvalue, self.contract_name, ','.join(args), options)

@ -21,6 +21,7 @@ class TmpCall(OperationWithLValue):
self._callid = None
self._gas = None
self._value = None
self._salt = None
@property
def call_value(self):
@ -38,6 +39,14 @@ class TmpCall(OperationWithLValue):
def call_gas(self, gas):
self._gas = gas
@property
def call_salt(self):
return self._salt
@call_salt.setter
def call_salt(self, salt):
self._salt = salt
@property
def call_id(self):
return self._callid

@ -6,11 +6,29 @@ class TmpNewContract(OperationWithLValue):
super(TmpNewContract, self).__init__()
self._contract_name = contract_name
self._lvalue = lvalue
self._call_value = None
self._call_salt = None
@property
def contract_name(self):
return self._contract_name
@property
def call_value(self):
return self._call_value
@call_value.setter
def call_value(self, v):
self._call_value = v
@property
def call_salt(self):
return self._call_salt
@call_salt.setter
def call_salt(self, s):
self._call_salt = s
@property
def read(self):
return []

@ -613,6 +613,8 @@ def copy_ir(ir, *instances):
lvalue = get_variable(ir, lambda x: x.lvalue, *instances)
new_ir = NewContract(contract_name, lvalue)
new_ir.arguments = get_arguments(ir, *instances)
new_ir.call_value = get_variable(ir, lambda x: x.call_value, *instances)
new_ir.call_salt = get_variable(ir, lambda x: x.call_salt, *instances)
return new_ir
elif isinstance(ir, NewStructure):
structure = ir.structure

@ -267,9 +267,9 @@ def parse_call(expression, caller_context):
call_gas = None
call_value = None
call_salt = None
if caller_context.is_compact_ast:
called = parse_expression(expression['expression'], caller_context)
# If the next expression is a FunctionCallOptions
# We can here the gas/value information
# This is only available if the syntax is {gas: , value: }
@ -283,7 +283,8 @@ def parse_call(expression, caller_context):
call_value = option
if name == 'gas':
call_gas = option
if name == 'salt':
call_salt = option
arguments = []
if expression['arguments']:
arguments = [parse_expression(a, caller_context) for a in expression['arguments']]
@ -302,6 +303,7 @@ def parse_call(expression, caller_context):
# Only available if the syntax {gas:, value:} was used
call_expression.call_gas = call_gas
call_expression.call_value = call_value
call_expression.call_salt = call_salt
return call_expression
@ -419,7 +421,7 @@ def parse_expression(expression, caller_context):
elif name == 'FunctionCallOptions':
# call/gas info are handled in parse_call
called = parse_expression(expression['expression'], caller_context)
assert isinstance(called, MemberAccess)
assert isinstance(called, (MemberAccess, NewContract))
return called
elif name == 'TupleExpression':

@ -111,6 +111,8 @@ class ExpressionVisitor:
self._visit_expression(expression.call_value)
if expression.call_gas:
self._visit_expression(expression.call_gas)
if expression.call_salt:
self._visit_expression(expression.call_salt)
def _visit_conditional_expression(self, expression):
self._visit_expression(expression.if_expression)

@ -160,6 +160,9 @@ class ExpressionToSlithIR(ExpressionVisitor):
if expression.call_value:
call_value = get(expression.call_value)
message_call.call_value = call_value
if expression.call_salt:
call_salt = get(expression.call_salt)
message_call.call_salt = call_salt
self._result.append(message_call)
set_val(expression, val)
@ -221,6 +224,13 @@ class ExpressionToSlithIR(ExpressionVisitor):
val = TemporaryVariable(self._node)
operation = TmpNewContract(expression.contract_name, val)
operation.set_expression(expression)
if expression.call_value:
call_value = get(expression.call_value)
operation.call_value = call_value
if expression.call_salt:
call_salt = get(expression.call_salt)
operation.call_salt = call_salt
self._result.append(operation)
set_val(expression, val)

Loading…
Cancel
Save