mirror of https://github.com/crytic/slither
commit
70e0318b90
@ -0,0 +1,104 @@ |
||||
#!/usr/bin/python3 |
||||
|
||||
''' |
||||
the purpose of this file is to sort the json output from the detectors such that |
||||
the order is deterministic |
||||
|
||||
- the keys of a json object are sorted |
||||
- json objects in a list will be sorted based on the values of their keys |
||||
- lists of strings/numbers are sorted |
||||
|
||||
''' |
||||
|
||||
import sys |
||||
import json |
||||
|
||||
raw_json_file = sys.argv[1] |
||||
pretty_json_file = sys.argv[2] |
||||
|
||||
from collections import OrderedDict |
||||
|
||||
def create_property_val_tuple(d, props_info): |
||||
p_names = props_info[0] |
||||
p_types = props_info[1] |
||||
result = [] |
||||
for p in p_names: |
||||
if not p in d: # not all objects have the same keys |
||||
if p_types[p] is 'number': |
||||
result.append(0) # to make sorting work |
||||
if p_types[p] is 'string': |
||||
result.append("") # to make sorting work |
||||
else: |
||||
result.append(d[p]) |
||||
return tuple(result) |
||||
|
||||
def get_props_info(list_of_dicts): |
||||
found_props = set() |
||||
prop_types = dict() |
||||
|
||||
# gather all prop names |
||||
for d in list_of_dicts: |
||||
for p in d: |
||||
found_props.add(p) |
||||
|
||||
# create a copy, since we are gonna possibly remove props |
||||
props_whose_value_we_can_sort_on = set(found_props) |
||||
|
||||
# for each object, loop through list of all found property names, |
||||
# if the object contains that property, check that it's of type string or number |
||||
# if it is, save it's type (used later on for sorting with objects that don't have that property) |
||||
# if it's not of type string/number remove it from list of properties to check |
||||
# since we cannot sort on non-string/number values |
||||
for p in list(found_props): |
||||
if p in props_whose_value_we_can_sort_on: # short circuit |
||||
for d in list_of_dicts: |
||||
if p in props_whose_value_we_can_sort_on: # less shorter short circuit |
||||
if p in d: |
||||
# we ae only gonna sort key values if they are of type string or number |
||||
if not isinstance(d[p], str) and not isinstance(d[p], int): |
||||
props_whose_value_we_can_sort_on.remove(p) |
||||
# we need to store the type of the value because not each object |
||||
# in a list of output objects for 1 detector will have the same |
||||
# keys, so if we want to sort based on the values then if a certain object |
||||
# does not have a key which another object does have we are gonna |
||||
# put in 0 for number and "" for string for that key such that sorting on values |
||||
# still works |
||||
elif isinstance(d[p], str): |
||||
prop_types[p] = 'string' |
||||
elif isinstance(d[p], int): |
||||
prop_types[p] = 'number' |
||||
return (sorted(list(props_whose_value_we_can_sort_on)), prop_types) |
||||
|
||||
def order_by_prop_value(list_of_dicts): |
||||
props_info = get_props_info(list_of_dicts) |
||||
return sorted(list_of_dicts, key=lambda d: create_property_val_tuple(d, props_info)) |
||||
|
||||
def order_dict(d): |
||||
result = OrderedDict() # such that we keep the order |
||||
for k, v in sorted(d.items()): |
||||
if isinstance(v, dict): |
||||
result[k] = order_dict(v) |
||||
elif type(v) is list: |
||||
result[k] = order_list(v) |
||||
else: # string/number |
||||
result[k] = v |
||||
return result |
||||
|
||||
def order_list(l): |
||||
# TODO: sometimes slither detectors return a null value in the json output sourceMapping object array |
||||
# get rid of those values, it will break sorting (some items are an object, some are null?!) |
||||
l = list(filter(None, l)) |
||||
if not l: |
||||
return [] |
||||
if isinstance(l[0], str): # it's a list of string |
||||
return sorted(l) |
||||
elif isinstance(l[0], int): # it's a list of numbers |
||||
return sorted(l) |
||||
elif isinstance(l[0], dict): # it's a list of objects |
||||
ordered_by_key = [order_dict(v) for v in l] |
||||
ordered_by_val = order_by_prop_value(ordered_by_key) |
||||
return ordered_by_val |
||||
|
||||
with open(raw_json_file, 'r') as json_data: |
||||
with open(pretty_json_file, 'w') as out_file: |
||||
out_file.write(json.dumps(order_list(json.load(json_data)), sort_keys=False, indent=4, separators=(',',': '))) |
@ -0,0 +1,38 @@ |
||||
#!/usr/bin/env bash |
||||
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)" |
||||
|
||||
# generate_expected_json file.sol detectors |
||||
generate_expected_json(){ |
||||
# generate output filename |
||||
# e.g. file: uninitialized.sol detector: uninitialized-state |
||||
# ---> uninitialized.uninitialized-state.json |
||||
output_filename="$(basename $1 .sol).$2.json" |
||||
|
||||
# run slither detector on input file and save output as json |
||||
slither "$1" --disable-solc-warnings --detect "$2" --json "$DIR/tmp-gen.json" |
||||
|
||||
# convert json file to pretty print and write to destination folder |
||||
python "$DIR/pretty_print_and_sort_json.py" "$DIR/tmp-gen.json" "$DIR/../tests/expected_json/$output_filename" |
||||
|
||||
# remove the raw un-prettified json file |
||||
rm "$DIR/tmp-gen.json" |
||||
} |
||||
|
||||
generate_expected_json tests/uninitialized.sol "uninitialized-state" |
||||
generate_expected_json tests/backdoor.sol "backdoor" |
||||
generate_expected_json tests/backdoor.sol "suicidal" |
||||
generate_expected_json tests/pragma.0.4.24.sol "pragma" |
||||
generate_expected_json tests/old_solc.sol.json "solc-version" |
||||
generate_expected_json tests/reentrancy.sol "reentrancy" |
||||
generate_expected_json tests/uninitialized_storage_pointer.sol "uninitialized-storage" |
||||
generate_expected_json tests/tx_origin.sol "tx-origin" |
||||
generate_expected_json tests/unused_state.sol "unused-state" |
||||
generate_expected_json tests/locked_ether.sol "locked-ether" |
||||
generate_expected_json tests/arbitrary_send.sol "arbitrary-send" |
||||
generate_expected_json tests/inline_assembly_contract.sol "assembly" |
||||
generate_expected_json tests/inline_assembly_library.sol "assembly" |
||||
generate_expected_json tests/low_level_calls.sol "low-level-calls" |
||||
generate_expected_json tests/const_state_variables.sol "constable-states" |
||||
generate_expected_json tests/external_function.sol "external-function" |
||||
generate_expected_json tests/naming_convention.sol "naming-convention" |
@ -0,0 +1,22 @@ |
||||
[ |
||||
{ |
||||
"calls": [ |
||||
"msg.sender.send(this.balance)" |
||||
], |
||||
"contract": "Test", |
||||
"filename": "tests/arbitrary_send.sol", |
||||
"func": "direct", |
||||
"sourceMapping": [], |
||||
"vuln": "SuicidalFunc" |
||||
}, |
||||
{ |
||||
"calls": [ |
||||
"destination.send(this.balance)" |
||||
], |
||||
"contract": "Test", |
||||
"filename": "tests/arbitrary_send.sol", |
||||
"func": "indirect", |
||||
"sourceMapping": [], |
||||
"vuln": "SuicidalFunc" |
||||
} |
||||
] |
@ -0,0 +1,11 @@ |
||||
[ |
||||
{ |
||||
"contract": "C", |
||||
"sourceMapping": { |
||||
"filename": "tests/backdoor.sol", |
||||
"length": 74, |
||||
"start": 42 |
||||
}, |
||||
"vuln": "backdoor" |
||||
} |
||||
] |
@ -0,0 +1,13 @@ |
||||
[ |
||||
{ |
||||
"contract": "C", |
||||
"filename": "tests/backdoor.sol", |
||||
"func": "i_am_a_backdoor", |
||||
"sourceMapping": { |
||||
"filename": "tests/backdoor.sol", |
||||
"length": 74, |
||||
"start": 42 |
||||
}, |
||||
"vuln": "SuicidalFunc" |
||||
} |
||||
] |
@ -0,0 +1,64 @@ |
||||
[ |
||||
{ |
||||
"contract": "B", |
||||
"filename": "tests/const_state_variables.sol", |
||||
"sourceMapping": [ |
||||
{ |
||||
"filename": "tests/const_state_variables.sol", |
||||
"length": 20, |
||||
"start": 235 |
||||
}, |
||||
{ |
||||
"filename": "tests/const_state_variables.sol", |
||||
"length": 20, |
||||
"start": 331 |
||||
}, |
||||
{ |
||||
"filename": "tests/const_state_variables.sol", |
||||
"length": 76, |
||||
"start": 130 |
||||
}, |
||||
{ |
||||
"filename": "tests/const_state_variables.sol", |
||||
"length": 76, |
||||
"start": 494 |
||||
} |
||||
], |
||||
"unusedVars": [ |
||||
"myFriendsAddress", |
||||
"test", |
||||
"text2" |
||||
], |
||||
"vuln": "ConstStateVariableCandidates" |
||||
}, |
||||
{ |
||||
"contract": "B", |
||||
"filename": "tests/const_state_variables.sol", |
||||
"sourceMapping": [ |
||||
{ |
||||
"filename": "tests/const_state_variables.sol", |
||||
"length": 20, |
||||
"start": 235 |
||||
}, |
||||
{ |
||||
"filename": "tests/const_state_variables.sol", |
||||
"length": 20, |
||||
"start": 331 |
||||
}, |
||||
{ |
||||
"filename": "tests/const_state_variables.sol", |
||||
"length": 76, |
||||
"start": 130 |
||||
}, |
||||
{ |
||||
"filename": "tests/const_state_variables.sol", |
||||
"length": 76, |
||||
"start": 494 |
||||
} |
||||
], |
||||
"unusedVars": [ |
||||
"mySistersAddress" |
||||
], |
||||
"vuln": "ConstStateVariableCandidates" |
||||
} |
||||
] |
@ -0,0 +1,46 @@ |
||||
[ |
||||
{ |
||||
"contract": "ContractWithFunctionNotCalled", |
||||
"filename": "tests/external_function.sol", |
||||
"func": "funcNotCalled", |
||||
"sourceMapping": { |
||||
"filename": "tests/external_function.sol", |
||||
"length": 40, |
||||
"start": 351 |
||||
}, |
||||
"vuln": "ExternalFunc" |
||||
}, |
||||
{ |
||||
"contract": "ContractWithFunctionNotCalled", |
||||
"filename": "tests/external_function.sol", |
||||
"func": "funcNotCalled2", |
||||
"sourceMapping": { |
||||
"filename": "tests/external_function.sol", |
||||
"length": 41, |
||||
"start": 304 |
||||
}, |
||||
"vuln": "ExternalFunc" |
||||
}, |
||||
{ |
||||
"contract": "ContractWithFunctionNotCalled", |
||||
"filename": "tests/external_function.sol", |
||||
"func": "funcNotCalled3", |
||||
"sourceMapping": { |
||||
"filename": "tests/external_function.sol", |
||||
"length": 41, |
||||
"start": 257 |
||||
}, |
||||
"vuln": "ExternalFunc" |
||||
}, |
||||
{ |
||||
"contract": "ContractWithFunctionNotCalled2", |
||||
"filename": "tests/external_function.sol", |
||||
"func": "funcNotCalled", |
||||
"sourceMapping": { |
||||
"filename": "tests/external_function.sol", |
||||
"length": 304, |
||||
"start": 552 |
||||
}, |
||||
"vuln": "ExternalFunc" |
||||
} |
||||
] |
@ -0,0 +1,9 @@ |
||||
[ |
||||
{ |
||||
"contract": "GetCode", |
||||
"filename": "tests/inline_assembly_contract.sol", |
||||
"function_name": "at", |
||||
"sourceMapping": [], |
||||
"vuln": "Assembly" |
||||
} |
||||
] |
@ -0,0 +1,16 @@ |
||||
[ |
||||
{ |
||||
"contract": "VectorSum", |
||||
"filename": "tests/inline_assembly_library.sol", |
||||
"function_name": "sumAsm", |
||||
"sourceMapping": [], |
||||
"vuln": "Assembly" |
||||
}, |
||||
{ |
||||
"contract": "VectorSum", |
||||
"filename": "tests/inline_assembly_library.sol", |
||||
"function_name": "sumPureAsm", |
||||
"sourceMapping": [], |
||||
"vuln": "Assembly" |
||||
} |
||||
] |
@ -0,0 +1,16 @@ |
||||
[ |
||||
{ |
||||
"contract": "OnlyLocked", |
||||
"functions_payable": [ |
||||
"receive" |
||||
], |
||||
"sourceMapping": [ |
||||
{ |
||||
"filename": "tests/locked_ether.sol", |
||||
"length": 72, |
||||
"start": 46 |
||||
} |
||||
], |
||||
"vuln": "LockedEther" |
||||
} |
||||
] |
@ -0,0 +1,9 @@ |
||||
[ |
||||
{ |
||||
"contract": "Sender", |
||||
"filename": "tests/low_level_calls.sol", |
||||
"function_name": "send", |
||||
"sourceMapping": [], |
||||
"vuln": "Low level call" |
||||
} |
||||
] |
@ -0,0 +1,131 @@ |
||||
[ |
||||
{ |
||||
"contract": "T", |
||||
"filename": "tests/naming_convention.sol", |
||||
"sourceMapping": { |
||||
"filename": "tests/naming_convention.sol", |
||||
"length": 17, |
||||
"start": 695 |
||||
}, |
||||
"variable": "_myPublicVar", |
||||
"vuln": "NamingConvention" |
||||
}, |
||||
{ |
||||
"contract": "naming", |
||||
"filename": "tests/naming_convention.sol", |
||||
"sourceMapping": { |
||||
"filename": "tests/naming_convention.sol", |
||||
"length": 598, |
||||
"start": 26 |
||||
}, |
||||
"vuln": "NamingConvention" |
||||
}, |
||||
{ |
||||
"contract": "naming", |
||||
"filename": "tests/naming_convention.sol", |
||||
"sourceMapping": { |
||||
"filename": "tests/naming_convention.sol", |
||||
"length": 16, |
||||
"start": 183 |
||||
}, |
||||
"variable": "Var_One", |
||||
"vuln": "NamingConvention" |
||||
}, |
||||
{ |
||||
"contract": "naming", |
||||
"filename": "tests/naming_convention.sol", |
||||
"sourceMapping": { |
||||
"filename": "tests/naming_convention.sol", |
||||
"length": 20, |
||||
"start": 227 |
||||
}, |
||||
"struct": "test", |
||||
"vuln": "NamingConvention" |
||||
}, |
||||
{ |
||||
"contract": "naming", |
||||
"filename": "tests/naming_convention.sol", |
||||
"modifier": "CantDo", |
||||
"sourceMapping": { |
||||
"filename": "tests/naming_convention.sol", |
||||
"length": 36, |
||||
"start": 545 |
||||
}, |
||||
"vuln": "NamingConvention" |
||||
}, |
||||
{ |
||||
"contract": "naming", |
||||
"filename": "tests/naming_convention.sol", |
||||
"function": "GetOne", |
||||
"sourceMapping": { |
||||
"filename": "tests/naming_convention.sol", |
||||
"length": 71, |
||||
"start": 405 |
||||
}, |
||||
"vuln": "NamingConvention" |
||||
}, |
||||
{ |
||||
"contract": "naming", |
||||
"event": "event_", |
||||
"filename": "tests/naming_convention.sol", |
||||
"sourceMapping": null, |
||||
"vuln": "NamingConvention" |
||||
}, |
||||
{ |
||||
"contract": "naming", |
||||
"enum": "numbers", |
||||
"filename": "tests/naming_convention.sol", |
||||
"sourceMapping": { |
||||
"filename": "tests/naming_convention.sol", |
||||
"length": 23, |
||||
"start": 77 |
||||
}, |
||||
"vuln": "NamingConvention" |
||||
}, |
||||
{ |
||||
"constant": "MY_other_CONSTANT", |
||||
"contract": "naming", |
||||
"filename": "tests/naming_convention.sol", |
||||
"sourceMapping": { |
||||
"filename": "tests/naming_convention.sol", |
||||
"length": 35, |
||||
"start": 141 |
||||
}, |
||||
"vuln": "NamingConvention" |
||||
}, |
||||
{ |
||||
"constant": "l", |
||||
"contract": "T", |
||||
"filename": "tests/naming_convention.sol", |
||||
"sourceMapping": { |
||||
"filename": "tests/naming_convention.sol", |
||||
"length": 10, |
||||
"start": 847 |
||||
}, |
||||
"vuln": "NamingConvention" |
||||
}, |
||||
{ |
||||
"argument": "Number2", |
||||
"contract": "naming", |
||||
"filename": "tests/naming_convention.sol", |
||||
"function": "setInt", |
||||
"sourceMapping": { |
||||
"filename": "tests/naming_convention.sol", |
||||
"length": 12, |
||||
"start": 512 |
||||
}, |
||||
"vuln": "NamingConvention" |
||||
}, |
||||
{ |
||||
"argument": "_used", |
||||
"contract": "T", |
||||
"filename": "tests/naming_convention.sol", |
||||
"function": "test", |
||||
"sourceMapping": { |
||||
"filename": "tests/naming_convention.sol", |
||||
"length": 10, |
||||
"start": 748 |
||||
}, |
||||
"vuln": "NamingConvention" |
||||
} |
||||
] |
@ -0,0 +1,15 @@ |
||||
[ |
||||
{ |
||||
"pragma": [ |
||||
"0.4.21" |
||||
], |
||||
"sourceMapping": [ |
||||
{ |
||||
"filename": "old_solc.sol", |
||||
"length": 23, |
||||
"start": 0 |
||||
} |
||||
], |
||||
"vuln": "OldPragma" |
||||
} |
||||
] |
@ -0,0 +1,21 @@ |
||||
[ |
||||
{ |
||||
"sourceMapping": [ |
||||
{ |
||||
"filename": "tests/pragma.0.4.23.sol", |
||||
"length": 24, |
||||
"start": 0 |
||||
}, |
||||
{ |
||||
"filename": "tests/pragma.0.4.24.sol", |
||||
"length": 23, |
||||
"start": 0 |
||||
} |
||||
], |
||||
"versions": [ |
||||
"0.4.24", |
||||
"^0.4.23" |
||||
], |
||||
"vuln": "ConstantPragma" |
||||
} |
||||
] |
@ -0,0 +1,24 @@ |
||||
[ |
||||
{ |
||||
"calls": [ |
||||
"! (msg.sender.call.value(userBalance[msg.sender])())" |
||||
], |
||||
"contract": "Reentrancy", |
||||
"filename": "tests/reentrancy.sol", |
||||
"function_name": "withdrawBalance()", |
||||
"send_eth": [ |
||||
"! (msg.sender.call.value(userBalance[msg.sender])())" |
||||
], |
||||
"sourceMapping": [ |
||||
{ |
||||
"filename": "tests/reentrancy.sol", |
||||
"length": 37, |
||||
"start": 52 |
||||
} |
||||
], |
||||
"varsWritten": [ |
||||
"userBalance" |
||||
], |
||||
"vuln": "Reentrancy" |
||||
} |
||||
] |
@ -0,0 +1,16 @@ |
||||
[ |
||||
{ |
||||
"contract": "TxOrigin", |
||||
"filename": "tests/tx_origin.sol", |
||||
"function_name": "bug0", |
||||
"sourceMapping": [], |
||||
"vuln": "TxOrigin" |
||||
}, |
||||
{ |
||||
"contract": "TxOrigin", |
||||
"filename": "tests/tx_origin.sol", |
||||
"function_name": "bug2", |
||||
"sourceMapping": [], |
||||
"vuln": "TxOrigin" |
||||
} |
||||
] |
@ -0,0 +1,86 @@ |
||||
[ |
||||
{ |
||||
"contract": "Test", |
||||
"filename": "tests/uninitialized.sol", |
||||
"functions": [ |
||||
"use" |
||||
], |
||||
"sourceMapping": [ |
||||
{ |
||||
"filename": "tests/uninitialized.sol", |
||||
"length": 34, |
||||
"start": 189 |
||||
}, |
||||
{ |
||||
"filename": "tests/uninitialized.sol", |
||||
"length": 143, |
||||
"start": 356 |
||||
} |
||||
], |
||||
"variable": "balances", |
||||
"vuln": "UninitializedStateVars" |
||||
}, |
||||
{ |
||||
"contract": "Test2", |
||||
"filename": "tests/uninitialized.sol", |
||||
"functions": [ |
||||
"use" |
||||
], |
||||
"sourceMapping": [ |
||||
{ |
||||
"filename": "tests/uninitialized.sol", |
||||
"length": 15, |
||||
"start": 695 |
||||
}, |
||||
{ |
||||
"filename": "tests/uninitialized.sol", |
||||
"length": 117, |
||||
"start": 875 |
||||
} |
||||
], |
||||
"variable": "st", |
||||
"vuln": "UninitializedStateVars" |
||||
}, |
||||
{ |
||||
"contract": "Test2", |
||||
"filename": "tests/uninitialized.sol", |
||||
"functions": [ |
||||
"init" |
||||
], |
||||
"sourceMapping": [ |
||||
{ |
||||
"filename": "tests/uninitialized.sol", |
||||
"length": 6, |
||||
"start": 748 |
||||
}, |
||||
{ |
||||
"filename": "tests/uninitialized.sol", |
||||
"length": 52, |
||||
"start": 817 |
||||
} |
||||
], |
||||
"variable": "v", |
||||
"vuln": "UninitializedStateVars" |
||||
}, |
||||
{ |
||||
"contract": "Uninitialized", |
||||
"filename": "tests/uninitialized.sol", |
||||
"functions": [ |
||||
"transfer" |
||||
], |
||||
"sourceMapping": [ |
||||
{ |
||||
"filename": "tests/uninitialized.sol", |
||||
"length": 19, |
||||
"start": 55 |
||||
}, |
||||
{ |
||||
"filename": "tests/uninitialized.sol", |
||||
"length": 82, |
||||
"start": 81 |
||||
} |
||||
], |
||||
"variable": "destination", |
||||
"vuln": "UninitializedStateVars" |
||||
} |
||||
] |
@ -0,0 +1,21 @@ |
||||
[ |
||||
{ |
||||
"contract": "Uninitialized", |
||||
"filename": "tests/uninitialized_storage_pointer.sol", |
||||
"function": "func", |
||||
"sourceMapping": [ |
||||
{ |
||||
"filename": "tests/uninitialized_storage_pointer.sol", |
||||
"length": 9, |
||||
"start": 171 |
||||
}, |
||||
{ |
||||
"filename": "tests/uninitialized_storage_pointer.sol", |
||||
"length": 138, |
||||
"start": 67 |
||||
} |
||||
], |
||||
"variable": "st_bug", |
||||
"vuln": "UninitializedStorageVars" |
||||
} |
||||
] |
@ -0,0 +1,17 @@ |
||||
[ |
||||
{ |
||||
"contract": "B", |
||||
"filename": "tests/unused_state.sol", |
||||
"sourceMapping": [ |
||||
{ |
||||
"filename": "tests/unused_state.sol", |
||||
"length": 14, |
||||
"start": 41 |
||||
} |
||||
], |
||||
"unusedVars": [ |
||||
"unused" |
||||
], |
||||
"vuln": "unusedStateVars" |
||||
} |
||||
] |
Loading…
Reference in new issue