Skip to content

Commit

Permalink
Merge branch 'fix-minor-issues-in-generator' into template-generation
Browse files Browse the repository at this point in the history
  • Loading branch information
tuturu-tech committed Mar 27, 2024
2 parents 3f65f70 + a457089 commit b8d1ecd
Show file tree
Hide file tree
Showing 7 changed files with 362 additions and 15 deletions.
23 changes: 21 additions & 2 deletions fuzz_utils/generate/fuzzers/Echidna.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from fuzz_utils.utils.error_handler import handle_exit


# pylint: disable=too-many-instance-attributes
class Echidna:
"""
Handles the generation of Foundry test files from Echidna reproducers
Expand All @@ -33,6 +34,7 @@ def __init__(
self.reproducer_dir = f"{corpus_path}/reproducers"
self.corpus_dirs = [f"{corpus_path}/coverage", self.reproducer_dir]
self.named_inputs = named_inputs
self.declared_variables: set[tuple[str, str]] = set()

def get_target_contract(self) -> Contract:
"""Finds and returns Slither Contract"""
Expand All @@ -51,17 +53,26 @@ def parse_reproducer(self, file_path: str, calls: Any, index: int) -> str:
call_list = []
end = len(calls) - 1
function_name = ""
has_low_level_call: bool = False

# before each test case, we clear the declared variables, as those are locals
self.declared_variables = set()

# 1. For each object in the list process the call object and add it to the call list
for idx, call in enumerate(calls):
call_str, fn_name = self._parse_call_object(call)
call_list.append(call_str)
has_low_level_call = has_low_level_call or ("(success, " in call_str)
if idx == end:
function_name = fn_name + "_" + str(index)

# 2. Generate the test string and return it
template = jinja2.Template(templates["TEST"])
return template.render(
function_name=function_name, call_list=call_list, file_path=file_path
function_name=function_name,
call_list=call_list,
file_path=file_path,
has_low_level_call=has_low_level_call,
)

# pylint: disable=too-many-locals,too-many-branches
Expand Down Expand Up @@ -306,5 +317,13 @@ def _get_memarr(

input_type = input_parameter.type
name = f"dyn{input_type}Arr_{index}"
declaration = f"{input_type}[] memory {name} = new {input_type}[]({length});\n"

# If the variable was already declared, just assign the new value
if (input_type, name) in self.declared_variables:
declaration = f"{name} = new {input_type}[]({length});\n"
else:
declaration = f"{input_type}[] memory {name} = new {input_type}[]({length});\n"

self.declared_variables.add((input_type, name))

return name, declaration
22 changes: 19 additions & 3 deletions fuzz_utils/generate/fuzzers/Medusa.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def __init__(
self.reproducer_dir,
]
self.named_inputs = named_inputs
self.declared_variables: set[tuple[str, str]] = set()

def get_target_contract(self) -> Contract:
"""Finds and returns Slither Contract"""
Expand All @@ -56,15 +57,24 @@ def parse_reproducer(self, file_path: str, calls: Any, index: int) -> str:
call_list = []
end = len(calls) - 1
function_name = ""
has_low_level_call: bool = False

# before each test case, we clear the declared variables, as those are locals
self.declared_variables = set()

for idx, call in enumerate(calls):
call_str, fn_name = self._parse_call_object(call)
call_list.append(call_str)
has_low_level_call = has_low_level_call or ("(success, " in call_str)
if idx == end:
function_name = fn_name + "_" + str(index)

template = jinja2.Template(templates["TEST"])
return template.render(
function_name=function_name, call_list=call_list, file_path=file_path
function_name=function_name,
call_list=call_list,
file_path=file_path,
has_low_level_call=has_low_level_call,
)
# 1. Take a reproducer list and create a test file based on the name of the last function of the list e.g. test_auto_$function_name
# 2. For each object in the list process the call object and add it to the call list
Expand Down Expand Up @@ -192,16 +202,22 @@ def _match_type(self, parameter: Any, values: Any) -> tuple[str, str, str]:
# TODO make it work with multidim dynamic arrays
if values:
dyn_length = len(values)

array_type: str = ""

if isinstance(
parameter.type.type,
(Structure | StructureContract | Enum | EnumContract),
):
array_type = parameter.type.type.name
else:
array_type = parameter.type.type
var_def += f"{array_type}[] memory {parameter.name} = new {parameter.type.type}[]({dyn_length});\n"
# If dynamic array of the same name and type was already declared, reuse it. Else, declare a new one.
if (array_type, parameter.name) in self.declared_variables:
var_def += f"{parameter.name} = new {array_type}[]({dyn_length});\n"
else:
var_def += f"{array_type}[] memory {parameter.name} = new {array_type}[]({dyn_length});\n"

self.declared_variables.add((array_type, parameter.name))

for idx, value in enumerate(values):
_, matched_value, _ = self._match_type(parameter.type, value)
Expand Down
11 changes: 7 additions & 4 deletions fuzz_utils/templates/foundry_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"""

__CALL_TEMPLATE: str = """
{%- if has_delay -%}
{%- if has_delay %}
vm.warp(block.timestamp + {{time_delay}});
vm.roll(block.number + {{block_delay}});
{%- endif %}
Expand All @@ -41,12 +41,12 @@
"""

__TRANSFER__TEMPLATE: str = """
{%- if has_delay -%}
{%- if has_delay %}
vm.warp(block.timestamp + {{time_delay}});
vm.roll(block.number + {{block_delay}});
{%- endif %}
vm.prank({{caller}});
(bool success, ) = payable(address(target)).call{value: {{value}}}("");
(success, ) = payable(address(target)).call{value: {{value}}}("");
require(success, "Low level call failed.");
"""

Expand All @@ -58,7 +58,10 @@

__TEST_TEMPLATE: str = """
// Reproduced from: {{file_path}}
function test_auto_{{function_name}}() public { {% for call in call_list %}
function test_auto_{{function_name}}() public {
{%- if has_low_level_call %}
bool success;
{%- endif %} {% for call in call_list %}
{{call}}{% endfor %}
}"""

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
[
{
"call": {
"contents": [
"addIntArr",
[
{
"contents": [
{
"contents": 256,
"tag": "AbiIntType"
},
[
{
"contents": [
256,
"3"
],
"tag": "AbiInt"
}
]
],
"tag": "AbiArrayDynamic"
}
]
],
"tag": "SolCall"
},
"delay": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000"
],
"dst": "0x00a329c0648769A73afAc7F9381E08FB43dBEA72",
"gas": 12500000,
"gasprice": "0x0000000000000000000000000000000000000000000000000000000000000000",
"src": "0x0000000000000000000000000000000000010000",
"value": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
{
"call": {
"contents": [
"addIntArr",
[
{
"contents": [
{
"contents": 256,
"tag": "AbiIntType"
},
[
{
"contents": [
256,
"3"
],
"tag": "AbiInt"
}
]
],
"tag": "AbiArrayDynamic"
}
]
],
"tag": "SolCall"
},
"delay": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000"
],
"dst": "0x00a329c0648769A73afAc7F9381E08FB43dBEA72",
"gas": 12500000,
"gasprice": "0x0000000000000000000000000000000000000000000000000000000000000000",
"src": "0x0000000000000000000000000000000000010000",
"value": "0x0000000000000000000000000000000000000000000000000000000000000000"
},
{
"call": {
"contents": [
"check_intDynArr",
[]
],
"tag": "SolCall"
},
"delay": [
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000000000000000000000000000000000000000000000"
],
"dst": "0x00a329c0648769A73afAc7F9381E08FB43dBEA72",
"gas": 12500000,
"gasprice": "0x0000000000000000000000000000000000000000000000000000000000000000",
"src": "0x0000000000000000000000000000000000010000",
"value": "0x0000000000000000000000000000000000000000000000000000000000000000"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
[
{
"call": {
"from": "0x0000000000000000000000000000000000010000",
"to": "0xa647ff3c36cfab592509e13860ab8c4f28781a66",
"nonce": 0,
"value": "0x0",
"gasLimit": 12500000,
"gasPrice": "0x1",
"gasFeeCap": "0x0",
"gasTipCap": "0x0",
"data": "0x9b8da3b70000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
"dataAbiValues": {
"methodName": "addBoolArr",
"inputValues": [
[
true,
true,
true,
false,
false,
false,
true,
false,
true,
true,
true,
false,
false,
true
]
]
},
"AccessList": null,
"SkipAccountChecks": false
},
"blockNumberDelay": 23884,
"blockTimestampDelay": 320182
},
{
"call": {
"from": "0x0000000000000000000000000000000000010000",
"to": "0xa647ff3c36cfab592509e13860ab8c4f28781a66",
"nonce": 1,
"value": "0x0",
"gasLimit": 12500000,
"gasPrice": "0x1",
"gasFeeCap": "0x0",
"gasTipCap": "0x0",
"data": "0x9b8da3b70000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
"dataAbiValues": {
"methodName": "addBoolArr",
"inputValues": [
[
true,
true,
true,
false,
false,
false,
true,
false,
true,
true,
true,
false,
false,
true
]
]
},
"AccessList": null,
"SkipAccountChecks": false
},
"blockNumberDelay": 23884,
"blockTimestampDelay": 320182
},
{
"call": {
"from": "0x0000000000000000000000000000000000010000",
"to": "0xa647ff3c36cfab592509e13860ab8c4f28781a66",
"nonce": 2,
"value": "0x0",
"gasLimit": 12500000,
"gasPrice": "0x1",
"gasFeeCap": "0x0",
"gasTipCap": "0x0",
"data": "0xfe08f9cd",
"dataAbiValues": {
"methodName": "check_boolArr",
"inputValues": []
},
"AccessList": null,
"SkipAccountChecks": false
},
"blockNumberDelay": 47114,
"blockTimestampDelay": 360622
}
]
Loading

0 comments on commit b8d1ecd

Please sign in to comment.