Merge branch 'dev' into dev-immediate-inheritance

pull/132/head
Josselin 6 years ago
commit 96106d56af
  1. 4
      scripts/json_diff.py
  2. 4
      slither/__main__.py
  3. 6
      slither/core/declarations/function.py
  4. 3
      slither/core/solidity_types/array_type.py
  5. 2
      slither/printers/call/call_graph.py
  6. 2
      slither/printers/inheritance/inheritance_graph.py
  7. 2
      slither/slither.py
  8. 9
      slither/slithir/convert.py
  9. 41
      slither/slithir/operations/internal_dynamic_call.py
  10. 11
      slither/solc_parsing/declarations/function.py
  11. 3
      slither/solc_parsing/declarations/modifier.py
  12. 7
      slither/solc_parsing/expressions/expression_parsing.py
  13. 6
      slither/solc_parsing/slitherSolc.py
  14. 8
      slither/visitors/slithir/expression_to_slithir.py

@ -7,10 +7,10 @@ if len(sys.argv) !=3:
print('Usage: python json_diff.py 1.json 2.json')
exit(-1)
with open(sys.argv[1]) as f:
with open(sys.argv[1], encoding='utf8') as f:
d1 = json.load(f)
with open(sys.argv[2]) as f:
with open(sys.argv[2], encoding='utf8') as f:
d2 = json.load(f)

@ -84,7 +84,7 @@ def process_files(filenames, args, detector_classes, printer_classes):
all_contracts = []
for filename in filenames:
with open(filename) as f:
with open(filename, encoding='utf8') as f:
contract_loaded = json.load(f)
all_contracts.append(contract_loaded['ast'])
@ -93,7 +93,7 @@ def process_files(filenames, args, detector_classes, printer_classes):
def output_json(results, filename):
with open(filename, 'w') as f:
with open(filename, 'w', encoding='utf8') as f:
json.dump(results, f)

@ -654,7 +654,7 @@ class Function(ChildContract, SourceMapping):
Args:
filename (str)
"""
with open(filename, 'w') as f:
with open(filename, 'w', encoding='utf8') as f:
f.write('digraph{\n')
for node in self.nodes:
f.write('{}[label="{}"];\n'.format(node.node_id, str(node)))
@ -670,7 +670,7 @@ class Function(ChildContract, SourceMapping):
filename (str)
"""
from slither.core.cfg.node import NodeType
with open(filename, 'w') as f:
with open(filename, 'w', encoding='utf8') as f:
f.write('digraph{\n')
for node in self.nodes:
label = 'Node Type: {} {}\n'.format(NodeType.str(node.type), node.node_id)
@ -696,7 +696,7 @@ class Function(ChildContract, SourceMapping):
if node.dominance_frontier:
desc += '\ndominance frontier: {}'.format([n.node_id for n in node.dominance_frontier])
return desc
with open(filename, 'w') as f:
with open(filename, 'w', encoding='utf8') as f:
f.write('digraph{\n')
for node in self.nodes:
f.write('{}[label="{}"];\n'.format(node.node_id, description(node)))

@ -1,12 +1,15 @@
from slither.core.variables.variable import Variable
from slither.core.solidity_types.type import Type
from slither.core.expressions.expression import Expression
from slither.core.expressions import Literal
class ArrayType(Type):
def __init__(self, t, length):
assert isinstance(t, Type)
if length:
if isinstance(length, int):
length = Literal(length)
assert isinstance(length, Expression)
super(ArrayType, self).__init__()
self._type = t

@ -145,7 +145,7 @@ class PrinterCallGraph(AbstractPrinter):
self.info(f'Call Graph: {filename}')
with open(filename, 'w') as f:
with open(filename, 'w', encoding='utf8') as f:
f.write('\n'.join([
'strict digraph {',
self._render_internal_calls(),

@ -117,7 +117,7 @@ class PrinterInheritanceGraph(AbstractPrinter):
filename += ".dot"
info = 'Inheritance Graph: ' + filename
self.info(info)
with open(filename, 'w') as f:
with open(filename, 'w', encoding='utf8') as f:
f.write('digraph{\n')
for c in self.contracts:
f.write(self._summary(c))

@ -117,7 +117,7 @@ class Slither(SlitherSolc):
raise Exception('Incorrect file format')
if is_ast_file:
with open(filename) as astFile:
with open(filename, encoding='utf8') as astFile:
stdout = astFile.read()
if not stdout:
logger.info('Empty AST file: %s', filename)

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

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

@ -314,7 +314,11 @@ class FunctionSolc(Function):
node_endDoWhile = self._new_node(NodeType.ENDLOOP, doWhilestatement['src'])
link_nodes(node, node_startDoWhile)
link_nodes(node_startDoWhile, node_condition.sons[0])
# empty block, loop from the start to the condition
if not node_condition.sons:
link_nodes(node_startDoWhile, node_condition)
else:
link_nodes(node_startDoWhile, node_condition.sons[0])
link_nodes(statement, node_condition)
link_nodes(node_condition, node_endDoWhile)
return node_endDoWhile
@ -834,6 +838,10 @@ class FunctionSolc(Function):
for node in self.nodes:
node.analyze_expressions(self)
self._filter_ternary()
self._remove_alone_endif()
def _filter_ternary(self):
ternary_found = True
while ternary_found:
ternary_found = False
@ -848,7 +856,6 @@ class FunctionSolc(Function):
self.split_ternary_node(node, condition, true_expr, false_expr)
ternary_found = True
break
self._remove_alone_endif()
def get_last_ssa_state_variables_instances(self):
if not self.is_implemented:

@ -59,6 +59,9 @@ class ModifierSolc(Modifier, FunctionSolc):
for node in self.nodes:
node.analyze_expressions(self)
self._filter_ternary()
self._remove_alone_endif()
self._analyze_read_write()
self._analyze_calls()

@ -241,7 +241,10 @@ def convert_subdenomination(value, sub):
if sub is None:
return value
# to allow 0.1 ether conversion
value = float(value)
if value[0:2] == "0x":
value = float(int(value, 16))
else:
value = float(value)
if sub == 'wei':
return int(value)
if sub == 'szabo':
@ -548,6 +551,8 @@ def parse_expression(expression, caller_context):
array_type = parse_type(UnknownType(type_name['name']), caller_context)
else:
array_type = parse_type(UnknownType(type_name['attributes']['name']), caller_context)
elif type_name[caller_context.get_key()] == 'FunctionTypeName':
array_type = parse_type(type_name, caller_context)
else:
logger.error('Incorrect type array {}'.format(type_name))
exit(-1)

@ -63,7 +63,7 @@ class SlitherSolc(Slither):
if 'sourcePaths' in data_loaded:
for sourcePath in data_loaded['sourcePaths']:
if os.path.isfile(sourcePath):
with open(sourcePath) as f:
with open(sourcePath, encoding='utf8') as f:
source_code = f.read()
self.source_code[sourcePath] = source_code
@ -126,13 +126,13 @@ class SlitherSolc(Slither):
self._source_units[sourceUnit] = name
if os.path.isfile(name) and not name in self.source_code:
with open(name) as f:
with open(name, encoding='utf8') as f:
source_code = f.read()
self.source_code[name] = source_code
else:
lib_name = os.path.join('node_modules', name)
if os.path.isfile(lib_name) and not name in self.source_code:
with open(lib_name) as f:
with open(lib_name, encoding='utf8') as f:
source_code = f.read()
self.source_code[name] = source_code

@ -160,6 +160,14 @@ class ExpressionToSlithIR(ExpressionVisitor):
left = get(expression.expression_left)
right = get(expression.expression_right)
val = ReferenceVariable(self._node)
# access to anonymous array
# such as [0,1][x]
if isinstance(left, list):
init_array_val = TemporaryVariable(self._node)
init_array_right = left
left = init_array_val
operation = InitArray(init_array_right, init_array_val)
self._result.append(operation)
operation = Index(val, left, right, expression.type)
self._result.append(operation)
set_val(expression, val)

Loading…
Cancel
Save