|
|
@ -1,9 +1,20 @@ |
|
|
|
import os |
|
|
|
import os |
|
|
|
import json |
|
|
|
import json |
|
|
|
import logging |
|
|
|
import logging |
|
|
|
|
|
|
|
from collections import OrderedDict |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from slither.core.source_mapping.source_mapping import SourceMapping |
|
|
|
from slither.utils.colors import yellow |
|
|
|
from slither.utils.colors import yellow |
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger("Slither") |
|
|
|
logger = logging.getLogger("Slither") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
# region Output |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
def output_json(filename, error, results): |
|
|
|
def output_json(filename, error, results): |
|
|
|
""" |
|
|
|
""" |
|
|
|
|
|
|
|
|
|
|
@ -34,3 +45,293 @@ def output_json(filename, error, results): |
|
|
|
else: |
|
|
|
else: |
|
|
|
with open(filename, 'w', encoding='utf8') as f: |
|
|
|
with open(filename, 'w', encoding='utf8') as f: |
|
|
|
json.dump(json_result, f, indent=2) |
|
|
|
json.dump(json_result, f, indent=2) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# endregion |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
# region Json generation |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def generate_json_result(info, additional_fields=None): |
|
|
|
|
|
|
|
if additional_fields is None: |
|
|
|
|
|
|
|
additional_fields = {} |
|
|
|
|
|
|
|
d = OrderedDict() |
|
|
|
|
|
|
|
d['elements'] = [] |
|
|
|
|
|
|
|
d['description'] = info |
|
|
|
|
|
|
|
if additional_fields: |
|
|
|
|
|
|
|
d['additional_fields'] = additional_fields |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return d |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# endregion |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
# region Internal functions |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _create_base_element(type, name, source_mapping, type_specific_fields=None, additional_fields=None): |
|
|
|
|
|
|
|
if additional_fields is None: |
|
|
|
|
|
|
|
additional_fields = {} |
|
|
|
|
|
|
|
if type_specific_fields is None: |
|
|
|
|
|
|
|
type_specific_fields = {} |
|
|
|
|
|
|
|
element = {'type': type, |
|
|
|
|
|
|
|
'name': name, |
|
|
|
|
|
|
|
'source_mapping': source_mapping} |
|
|
|
|
|
|
|
if type_specific_fields: |
|
|
|
|
|
|
|
element['type_specific_fields'] = type_specific_fields |
|
|
|
|
|
|
|
if additional_fields: |
|
|
|
|
|
|
|
element['additional_fields'] = additional_fields |
|
|
|
|
|
|
|
return element |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _create_parent_element(element): |
|
|
|
|
|
|
|
from slither.core.children.child_contract import ChildContract |
|
|
|
|
|
|
|
from slither.core.children.child_function import ChildFunction |
|
|
|
|
|
|
|
from slither.core.children.child_inheritance import ChildInheritance |
|
|
|
|
|
|
|
if isinstance(element, ChildInheritance): |
|
|
|
|
|
|
|
if element.contract_declarer: |
|
|
|
|
|
|
|
contract = {'elements': []} |
|
|
|
|
|
|
|
add_contract_to_json(element.contract_declarer, contract) |
|
|
|
|
|
|
|
return contract['elements'][0] |
|
|
|
|
|
|
|
elif isinstance(element, ChildContract): |
|
|
|
|
|
|
|
if element.contract: |
|
|
|
|
|
|
|
contract = {'elements': []} |
|
|
|
|
|
|
|
add_contract_to_json(element.contract, contract) |
|
|
|
|
|
|
|
return contract['elements'][0] |
|
|
|
|
|
|
|
elif isinstance(element, ChildFunction): |
|
|
|
|
|
|
|
if element.function: |
|
|
|
|
|
|
|
function = {'elements': []} |
|
|
|
|
|
|
|
add_function_to_json(element.function, function) |
|
|
|
|
|
|
|
return function['elements'][0] |
|
|
|
|
|
|
|
return None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# endregion |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
# region Variables |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_variable_to_json(variable, d, additional_fields=None): |
|
|
|
|
|
|
|
if additional_fields is None: |
|
|
|
|
|
|
|
additional_fields = {} |
|
|
|
|
|
|
|
type_specific_fields = { |
|
|
|
|
|
|
|
'parent': _create_parent_element(variable) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
element = _create_base_element('variable', |
|
|
|
|
|
|
|
variable.name, |
|
|
|
|
|
|
|
variable.source_mapping, |
|
|
|
|
|
|
|
type_specific_fields, |
|
|
|
|
|
|
|
additional_fields) |
|
|
|
|
|
|
|
d['elements'].append(element) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_variables_to_json(variables, d): |
|
|
|
|
|
|
|
for variable in sorted(variables, key=lambda x: x.name): |
|
|
|
|
|
|
|
add_variable_to_json(variable, d) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# endregion |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
# region Contract |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_contract_to_json(contract, d, additional_fields=None): |
|
|
|
|
|
|
|
if additional_fields is None: |
|
|
|
|
|
|
|
additional_fields = {} |
|
|
|
|
|
|
|
element = _create_base_element('contract', |
|
|
|
|
|
|
|
contract.name, |
|
|
|
|
|
|
|
contract.source_mapping, |
|
|
|
|
|
|
|
{}, |
|
|
|
|
|
|
|
additional_fields) |
|
|
|
|
|
|
|
d['elements'].append(element) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# endregion |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
# region Functions |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_function_to_json(function, d, additional_fields=None): |
|
|
|
|
|
|
|
if additional_fields is None: |
|
|
|
|
|
|
|
additional_fields = {} |
|
|
|
|
|
|
|
type_specific_fields = { |
|
|
|
|
|
|
|
'parent': _create_parent_element(function), |
|
|
|
|
|
|
|
'signature': function.full_name |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
element = _create_base_element('function', |
|
|
|
|
|
|
|
function.name, |
|
|
|
|
|
|
|
function.source_mapping, |
|
|
|
|
|
|
|
type_specific_fields, |
|
|
|
|
|
|
|
additional_fields) |
|
|
|
|
|
|
|
d['elements'].append(element) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_functions_to_json(functions, d, additional_fields=None): |
|
|
|
|
|
|
|
if additional_fields is None: |
|
|
|
|
|
|
|
additional_fields = {} |
|
|
|
|
|
|
|
for function in sorted(functions, key=lambda x: x.name): |
|
|
|
|
|
|
|
add_function_to_json(function, d, additional_fields) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# endregion |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
# region Enum |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_enum_to_json(enum, d, additional_fields=None): |
|
|
|
|
|
|
|
if additional_fields is None: |
|
|
|
|
|
|
|
additional_fields = {} |
|
|
|
|
|
|
|
type_specific_fields = { |
|
|
|
|
|
|
|
'parent': _create_parent_element(enum) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
element = _create_base_element('enum', |
|
|
|
|
|
|
|
enum.name, |
|
|
|
|
|
|
|
enum.source_mapping, |
|
|
|
|
|
|
|
type_specific_fields, |
|
|
|
|
|
|
|
additional_fields) |
|
|
|
|
|
|
|
d['elements'].append(element) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# endregion |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
# region Structures |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_struct_to_json(struct, d, additional_fields=None): |
|
|
|
|
|
|
|
if additional_fields is None: |
|
|
|
|
|
|
|
additional_fields = {} |
|
|
|
|
|
|
|
type_specific_fields = { |
|
|
|
|
|
|
|
'parent': _create_parent_element(struct) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
element = _create_base_element('struct', |
|
|
|
|
|
|
|
struct.name, |
|
|
|
|
|
|
|
struct.source_mapping, |
|
|
|
|
|
|
|
type_specific_fields, |
|
|
|
|
|
|
|
additional_fields) |
|
|
|
|
|
|
|
d['elements'].append(element) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# endregion |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
# region Events |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_event_to_json(event, d, additional_fields=None): |
|
|
|
|
|
|
|
if additional_fields is None: |
|
|
|
|
|
|
|
additional_fields = {} |
|
|
|
|
|
|
|
type_specific_fields = { |
|
|
|
|
|
|
|
'parent': _create_parent_element(event), |
|
|
|
|
|
|
|
'signature': event.full_name |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
element = _create_base_element('event', |
|
|
|
|
|
|
|
event.name, |
|
|
|
|
|
|
|
event.source_mapping, |
|
|
|
|
|
|
|
type_specific_fields, |
|
|
|
|
|
|
|
additional_fields) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
d['elements'].append(element) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# endregion |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
# region Nodes |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_node_to_json(node, d, additional_fields=None): |
|
|
|
|
|
|
|
if additional_fields is None: |
|
|
|
|
|
|
|
additional_fields = {} |
|
|
|
|
|
|
|
type_specific_fields = { |
|
|
|
|
|
|
|
'parent': _create_parent_element(node), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
node_name = str(node.expression) if node.expression else "" |
|
|
|
|
|
|
|
element = _create_base_element('node', |
|
|
|
|
|
|
|
node_name, |
|
|
|
|
|
|
|
node.source_mapping, |
|
|
|
|
|
|
|
type_specific_fields, |
|
|
|
|
|
|
|
additional_fields) |
|
|
|
|
|
|
|
d['elements'].append(element) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_nodes_to_json(nodes, d): |
|
|
|
|
|
|
|
for node in sorted(nodes, key=lambda x: x.node_id): |
|
|
|
|
|
|
|
add_node_to_json(node, d) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# endregion |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
# region Pragma |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_pragma_to_json(pragma, d, additional_fields=None): |
|
|
|
|
|
|
|
if additional_fields is None: |
|
|
|
|
|
|
|
additional_fields = {} |
|
|
|
|
|
|
|
type_specific_fields = { |
|
|
|
|
|
|
|
'directive': pragma.directive |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
element = _create_base_element('pragma', |
|
|
|
|
|
|
|
pragma.version, |
|
|
|
|
|
|
|
pragma.source_mapping, |
|
|
|
|
|
|
|
type_specific_fields, |
|
|
|
|
|
|
|
additional_fields) |
|
|
|
|
|
|
|
d['elements'].append(element) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# endregion |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
# region Others |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def add_other_to_json(name, source_mapping, d, slither, additional_fields=None): |
|
|
|
|
|
|
|
# If this a tuple with (filename, start, end), convert it to a source mapping. |
|
|
|
|
|
|
|
if additional_fields is None: |
|
|
|
|
|
|
|
additional_fields = {} |
|
|
|
|
|
|
|
if isinstance(source_mapping, tuple): |
|
|
|
|
|
|
|
# Parse the source id |
|
|
|
|
|
|
|
(filename, start, end) = source_mapping |
|
|
|
|
|
|
|
source_id = next( |
|
|
|
|
|
|
|
(source_unit_id for (source_unit_id, source_unit_filename) in slither.source_units.items() if |
|
|
|
|
|
|
|
source_unit_filename == filename), -1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Convert to a source mapping string |
|
|
|
|
|
|
|
source_mapping = f"{start}:{end}:{source_id}" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# If this is a source mapping string, parse it. |
|
|
|
|
|
|
|
if isinstance(source_mapping, str): |
|
|
|
|
|
|
|
source_mapping_str = source_mapping |
|
|
|
|
|
|
|
source_mapping = SourceMapping() |
|
|
|
|
|
|
|
source_mapping.set_offset(source_mapping_str, slither) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# If this is a source mapping object, get the underlying source mapping dictionary |
|
|
|
|
|
|
|
if isinstance(source_mapping, SourceMapping): |
|
|
|
|
|
|
|
source_mapping = source_mapping.source_mapping |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Create the underlying element and add it to our resulting json |
|
|
|
|
|
|
|
element = _create_base_element('other', |
|
|
|
|
|
|
|
name, |
|
|
|
|
|
|
|
source_mapping, |
|
|
|
|
|
|
|
{}, |
|
|
|
|
|
|
|
additional_fields) |
|
|
|
|
|
|
|
d['elements'].append(element) |
|
|
|