-
-
-
diff --git a/tests/testdata/outputs_expected/calls.sol.o.graph.html b/tests/testdata/outputs_expected/calls.sol.o.graph.html
index 665a8a65..0ae74c2d 100644
--- a/tests/testdata/outputs_expected/calls.sol.o.graph.html
+++ b/tests/testdata/outputs_expected/calls.sol.o.graph.html
@@ -18,8 +18,8 @@
diff --git a/tests/testdata/outputs_expected/calls.sol.o.json b/tests/testdata/outputs_expected/calls.sol.o.json
index 58bebb0b..3a93166f 100644
--- a/tests/testdata/outputs_expected/calls.sol.o.json
+++ b/tests/testdata/outputs_expected/calls.sol.o.json
@@ -1,86 +1 @@
-{
- "success": true,
- "error": null,
- "issues": [
- {
- "title": "Message call to external contract",
- "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.",
- "function": "_function_0x5a6814ec",
- "type": "Informational",
- "address": 661,
- "debug": ""
- },
- {
- "title": "Message call to external contract",
- "description": "This contract executes a message call to an address found at storage slot 1. This storage slot can be written to by calling the function `_function_0x2776b163`. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.",
- "function": "_function_0xd24b08cc",
- "type": "Warning",
- "address": 779,
- "debug": ""
- },
- {
- "title": "Message call to external contract",
- "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.",
- "function": "_function_0xe11f493e",
- "type": "Informational",
- "address": 858,
- "debug": ""
- },
- {
- "title": "State change after external call",
- "description": "The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities.",
- "function": "_function_0xe11f493e",
- "type": "Warning",
- "address": 869,
- "debug": ""
- },
- {
- "title": "Message call to external contract",
- "description": "This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.",
- "function": "_function_0xe1d10f79",
- "type": "Warning",
- "address": 912,
- "debug": ""
- },
- {
- "title": "Transaction order dependence",
- "description": "A possible transaction order independence vulnerability exists in function _function_0xd24b08cc. The value or direction of the call statement is determined from a tainted storage location",
- "function": "_function_0xd24b08cc",
- "type": "Warning",
- "address": 779,
- "debug": ""
- },
- {
- "title": "Unchecked CALL return value",
- "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
- "function": "_function_0x5a6814ec",
- "type": "Informational",
- "address": 661,
- "debug": ""
- },
- {
- "title": "Unchecked CALL return value",
- "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
- "function": "_function_0xd24b08cc",
- "type": "Informational",
- "address": 779,
- "debug": ""
- },
- {
- "title": "Unchecked CALL return value",
- "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
- "function": "_function_0xe11f493e",
- "type": "Informational",
- "address": 858,
- "debug": ""
- },
- {
- "title": "Unchecked CALL return value",
- "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
- "function": "_function_0xe1d10f79",
- "type": "Informational",
- "address": 912,
- "debug": ""
- }
- ]
-}
\ No newline at end of file
+{"error": null, "issues": [{"address": 661, "debug": "", "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", "function": "_function_0x5a6814ec", "title": "Message call to external contract", "type": "Informational"}, {"address": 666, "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0x5a6814ec", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 779, "debug": "", "description": "This contract executes a message call to an address found at storage slot 1. This storage slot can be written to by calling the function `_function_0x2776b163`. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.", "function": "_function_0xd24b08cc", "title": "Message call to external contract", "type": "Warning"}, {"address": 779, "debug": "", "description": "A possible transaction order independence vulnerability exists in function _function_0xd24b08cc. The value or direction of the call statement is determined from a tainted storage location", "function": "_function_0xd24b08cc", "title": "Transaction order dependence", "type": "Warning"}, {"address": 784, "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xd24b08cc", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 858, "debug": "", "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", "function": "_function_0xe11f493e", "title": "Message call to external contract", "type": "Informational"}, {"address": 869, "debug": "", "description": "The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities.", "function": "_function_0xe11f493e", "title": "State change after external call", "type": "Warning"}, {"address": 871, "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xe11f493e", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 912, "debug": "", "description": "This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.", "function": "_function_0xe1d10f79", "title": "Message call to external contract", "type": "Warning"}, {"address": 918, "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xe1d10f79", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/calls.sol.o.markdown b/tests/testdata/outputs_expected/calls.sol.o.markdown
index 02e69173..b5f5990e 100644
--- a/tests/testdata/outputs_expected/calls.sol.o.markdown
+++ b/tests/testdata/outputs_expected/calls.sol.o.markdown
@@ -16,7 +16,7 @@ This contract executes a message call to to another contract. Make sure that the
- Type: Informational
- Contract: Unknown
- Function name: `_function_0x5a6814ec`
-- PC address: 661
+- PC address: 666
### Description
@@ -49,7 +49,7 @@ A possible transaction order independence vulnerability exists in function _func
- Type: Informational
- Contract: Unknown
- Function name: `_function_0xd24b08cc`
-- PC address: 779
+- PC address: 784
### Description
@@ -66,27 +66,27 @@ The return value of an external call is not checked. Note that execution continu
This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.
-## Unchecked CALL return value
+## State change after external call
-- Type: Informational
+- Type: Warning
- Contract: Unknown
- Function name: `_function_0xe11f493e`
-- PC address: 858
+- PC address: 869
### Description
-The return value of an external call is not checked. Note that execution continue even if the called contract throws.
+The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities.
-## State change after external call
+## Unchecked CALL return value
-- Type: Warning
+- Type: Informational
- Contract: Unknown
- Function name: `_function_0xe11f493e`
-- PC address: 869
+- PC address: 871
### Description
-The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities.
+The return value of an external call is not checked. Note that execution continue even if the called contract throws.
## Message call to external contract
@@ -104,7 +104,7 @@ This contract executes a message call to an address provided as a function argum
- Type: Informational
- Contract: Unknown
- Function name: `_function_0xe1d10f79`
-- PC address: 912
+- PC address: 918
### Description
diff --git a/tests/testdata/outputs_expected/calls.sol.o.text b/tests/testdata/outputs_expected/calls.sol.o.text
index efdfd1e4..f126ddb5 100644
--- a/tests/testdata/outputs_expected/calls.sol.o.text
+++ b/tests/testdata/outputs_expected/calls.sol.o.text
@@ -10,7 +10,7 @@ This contract executes a message call to to another contract. Make sure that the
Type: Informational
Contract: Unknown
Function name: _function_0x5a6814ec
-PC address: 661
+PC address: 666
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
--------------------
@@ -34,7 +34,7 @@ A possible transaction order independence vulnerability exists in function _func
Type: Informational
Contract: Unknown
Function name: _function_0xd24b08cc
-PC address: 779
+PC address: 784
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
--------------------
@@ -46,14 +46,6 @@ PC address: 858
This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.
--------------------
-==== Unchecked CALL return value ====
-Type: Informational
-Contract: Unknown
-Function name: _function_0xe11f493e
-PC address: 858
-The return value of an external call is not checked. Note that execution continue even if the called contract throws.
---------------------
-
==== State change after external call ====
Type: Warning
Contract: Unknown
@@ -62,6 +54,14 @@ PC address: 869
The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities.
--------------------
+==== Unchecked CALL return value ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0xe11f493e
+PC address: 871
+The return value of an external call is not checked. Note that execution continue even if the called contract throws.
+--------------------
+
==== Message call to external contract ====
Type: Warning
Contract: Unknown
@@ -74,7 +74,7 @@ This contract executes a message call to an address provided as a function argum
Type: Informational
Contract: Unknown
Function name: _function_0xe1d10f79
-PC address: 912
+PC address: 918
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
--------------------
diff --git a/tests/testdata/outputs_expected/ether_send.sol.json b/tests/testdata/outputs_expected/ether_send.sol.json
deleted file mode 100644
index 08a5012c..00000000
--- a/tests/testdata/outputs_expected/ether_send.sol.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "success": true,
- "error": null,
- "issues": [
- {
- "title": "Ether send",
- "description": "In the function `withdrawfunds()` a non-zero amount of Ether is sent to msg.sender.\n\nThere is a check on storage index 1. This storage slot can be written to by calling the function `crowdfunding()`.",
- "function": "withdrawfunds()",
- "type": "Warning",
- "address": 816,
- "debug": "",
- "filename": "/inputs/ether_send.sol",
- "lineno": 18,
- "code": "msg.sender.transfer(this.balance)"
- },
- {
- "title": "Integer Overflow",
- "description": "A possible integer overflow exists in the function `invest()`.\nThe addition or multiplication may result in a value higher than the maximum representable integer.",
- "function": "invest()",
- "type": "Warning",
- "address": 483,
- "debug": "",
- "filename": "/inputs/ether_send.sol",
- "lineno": 24,
- "code": "balances[msg.sender] += msg.value"
- }
- ]
-}
diff --git a/tests/testdata/outputs_expected/ether_send.sol.o.graph.html b/tests/testdata/outputs_expected/ether_send.sol.o.graph.html
index 089d010f..bdb8c6bb 100644
--- a/tests/testdata/outputs_expected/ether_send.sol.o.graph.html
+++ b/tests/testdata/outputs_expected/ether_send.sol.o.graph.html
@@ -18,8 +18,8 @@
diff --git a/tests/testdata/outputs_expected/exceptions.sol.graph.html b/tests/testdata/outputs_expected/exceptions.sol.graph.html
deleted file mode 100644
index 403c896d..00000000
--- a/tests/testdata/outputs_expected/exceptions.sol.graph.html
+++ /dev/null
@@ -1,252 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
Mythril / LASER Symbolic VM
-
-
-
-
diff --git a/tests/testdata/outputs_expected/exceptions.sol.o.graph.html b/tests/testdata/outputs_expected/exceptions.sol.o.graph.html
index 2ac1b798..24ba3f52 100644
--- a/tests/testdata/outputs_expected/exceptions.sol.o.graph.html
+++ b/tests/testdata/outputs_expected/exceptions.sol.o.graph.html
@@ -18,8 +18,8 @@
diff --git a/tests/testdata/outputs_expected/exceptions.sol.o.json b/tests/testdata/outputs_expected/exceptions.sol.o.json
index 53ef733d..4434c91f 100644
--- a/tests/testdata/outputs_expected/exceptions.sol.o.json
+++ b/tests/testdata/outputs_expected/exceptions.sol.o.json
@@ -1,38 +1 @@
-{
- "success": true,
- "error": null,
- "issues": [
- {
- "title": "Exception state",
- "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ",
- "function": "_function_0x546455b5",
- "type": "Informational",
- "address": 446,
- "debug": ""
- },
- {
- "title": "Exception state",
- "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ",
- "function": "_function_0x92dd38ea",
- "type": "Informational",
- "address": 484,
- "debug": ""
- },
- {
- "title": "Exception state",
- "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ",
- "function": "_function_0xa08299f1",
- "type": "Informational",
- "address": 506,
- "debug": ""
- },
- {
- "title": "Exception state",
- "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ",
- "function": "_function_0xb34c3610",
- "type": "Informational",
- "address": 531,
- "debug": ""
- }
- ]
-}
\ No newline at end of file
+{"error": null, "issues": [{"address": 446, "debug": "", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ", "function": "_function_0x546455b5", "title": "Exception state", "type": "Informational"}, {"address": 484, "debug": "", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ", "function": "_function_0x92dd38ea", "title": "Exception state", "type": "Informational"}, {"address": 506, "debug": "", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ", "function": "_function_0xa08299f1", "title": "Exception state", "type": "Informational"}, {"address": 531, "debug": "", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ", "function": "_function_0xb34c3610", "title": "Exception state", "type": "Informational"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/kinds_of_calls.sol.graph.html b/tests/testdata/outputs_expected/kinds_of_calls.sol.graph.html
deleted file mode 100644
index 5f161388..00000000
--- a/tests/testdata/outputs_expected/kinds_of_calls.sol.graph.html
+++ /dev/null
@@ -1,178 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
Mythril / LASER Symbolic VM
-
-
-
-
diff --git a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.graph.html b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.graph.html
index ae421675..82078538 100644
--- a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.graph.html
+++ b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.graph.html
@@ -18,8 +18,8 @@
diff --git a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.json b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.json
index edc77d48..747f1118 100644
--- a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.json
+++ b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.json
@@ -1,22 +1 @@
-{
- "success": true,
- "error": null,
- "issues": [
- {
- "title": "Message call to external contract",
- "description": "This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.",
- "function": "_function_0xeea4c864",
- "type": "Warning",
- "address": 1038,
- "debug": ""
- },
- {
- "title": "Unchecked CALL return value",
- "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
- "function": "_function_0xeea4c864",
- "type": "Informational",
- "address": 1038,
- "debug": ""
- }
- ]
-}
\ No newline at end of file
+{"error": null, "issues": [{"address": 626, "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0x141f32ff", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 857, "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0x9b58bc26", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 1038, "debug": "", "description": "This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.", "function": "_function_0xeea4c864", "title": "Message call to external contract", "type": "Warning"}, {"address": 1046, "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xeea4c864", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.markdown b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.markdown
index 3a6b4073..40003ab4 100644
--- a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.markdown
+++ b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.markdown
@@ -1,5 +1,27 @@
# Analysis results for test-filename.sol
+## Unchecked CALL return value
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `_function_0x141f32ff`
+- PC address: 626
+
+### Description
+
+The return value of an external call is not checked. Note that execution continue even if the called contract throws.
+
+## Unchecked CALL return value
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `_function_0x9b58bc26`
+- PC address: 857
+
+### Description
+
+The return value of an external call is not checked. Note that execution continue even if the called contract throws.
+
## Message call to external contract
- Type: Warning
@@ -16,7 +38,7 @@ This contract executes a message call to an address provided as a function argum
- Type: Informational
- Contract: Unknown
- Function name: `_function_0xeea4c864`
-- PC address: 1038
+- PC address: 1046
### Description
diff --git a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.text b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.text
index 98deddc9..e08de551 100644
--- a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.text
+++ b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.text
@@ -1,3 +1,19 @@
+==== Unchecked CALL return value ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0x141f32ff
+PC address: 626
+The return value of an external call is not checked. Note that execution continue even if the called contract throws.
+--------------------
+
+==== Unchecked CALL return value ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0x9b58bc26
+PC address: 857
+The return value of an external call is not checked. Note that execution continue even if the called contract throws.
+--------------------
+
==== Message call to external contract ====
Type: Warning
Contract: Unknown
@@ -10,7 +26,7 @@ This contract executes a message call to an address provided as a function argum
Type: Informational
Contract: Unknown
Function name: _function_0xeea4c864
-PC address: 1038
+PC address: 1046
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
--------------------
diff --git a/tests/testdata/outputs_expected/metacoin.sol.graph.html b/tests/testdata/outputs_expected/metacoin.sol.graph.html
deleted file mode 100644
index e5617724..00000000
--- a/tests/testdata/outputs_expected/metacoin.sol.graph.html
+++ /dev/null
@@ -1,150 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tests/testdata/outputs_expected/multi_contracts.sol.json b/tests/testdata/outputs_expected/multi_contracts.sol.json
deleted file mode 100644
index af046a44..00000000
--- a/tests/testdata/outputs_expected/multi_contracts.sol.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "success": true,
- "error": null,
- "issues": [
- {
- "title": "Ether send",
- "description": "In the function `_function_0x8a4068dd` a non-zero amount of Ether is sent to msg.sender.\nIt seems that this function can be called without restrictions.",
- "function": "_function_0x8a4068dd",
- "type": "Warning",
- "address": 142,
- "debug": "",
- "filename": "/inputs/multi_contracts.sol",
- "lineno": 14,
- "code": "msg.sender.transfer(2 ether)"
- }
- ]
-}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/multi_contracts.sol.markdown b/tests/testdata/outputs_expected/multi_contracts.sol.markdown
deleted file mode 100644
index ff7421aa..00000000
--- a/tests/testdata/outputs_expected/multi_contracts.sol.markdown
+++ /dev/null
@@ -1,18 +0,0 @@
-# Analysis results for /inputs/multi_contracts.sol
-
-## Ether send
-
-- Type: Warning
-- Contract: Transfer2
-- Function name: `_function_0x8a4068dd`
-- PC address: 142
-
-### Description
-
-In the function `_function_0x8a4068dd` a non-zero amount of Ether is sent to msg.sender.
-It seems that this function can be called without restrictions.
-In */inputs/multi_contracts.sol:14*
-
-```
-msg.sender.transfer(2 ether)
-```
diff --git a/tests/testdata/outputs_expected/multi_contracts.sol.o.graph.html b/tests/testdata/outputs_expected/multi_contracts.sol.o.graph.html
index 94a77a08..fda47d74 100644
--- a/tests/testdata/outputs_expected/multi_contracts.sol.o.graph.html
+++ b/tests/testdata/outputs_expected/multi_contracts.sol.o.graph.html
@@ -18,8 +18,8 @@
diff --git a/tests/testdata/outputs_expected/multi_contracts.sol.o.json b/tests/testdata/outputs_expected/multi_contracts.sol.o.json
index ce4d6465..ff019037 100644
--- a/tests/testdata/outputs_expected/multi_contracts.sol.o.json
+++ b/tests/testdata/outputs_expected/multi_contracts.sol.o.json
@@ -1,14 +1 @@
-{
- "success": true,
- "error": null,
- "issues": [
- {
- "title": "Ether send",
- "description": "In the function `_function_0x8a4068dd` a non-zero amount of Ether is sent to msg.sender.\nIt seems that this function can be called without restrictions.",
- "function": "_function_0x8a4068dd",
- "type": "Warning",
- "address": 142,
- "debug": ""
- }
- ]
-}
\ No newline at end of file
+{"error": null, "issues": [{"address": 142, "debug": "", "description": "In the function `_function_0x8a4068dd` a non-zero amount of Ether is sent to msg.sender.\nIt seems that this function can be called without restrictions.", "function": "_function_0x8a4068dd", "title": "Ether send", "type": "Warning"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/multi_contracts.sol.text b/tests/testdata/outputs_expected/multi_contracts.sol.text
deleted file mode 100644
index 55ed6152..00000000
--- a/tests/testdata/outputs_expected/multi_contracts.sol.text
+++ /dev/null
@@ -1,14 +0,0 @@
-==== Ether send ====
-Type: Warning
-Contract: Transfer2
-Function name: _function_0x8a4068dd
-PC address: 142
-In the function `_function_0x8a4068dd` a non-zero amount of Ether is sent to msg.sender.
-It seems that this function can be called without restrictions.
---------------------
-In file: /inputs/multi_contracts.sol:14
-
-msg.sender.transfer(2 ether)
-
---------------------
-
diff --git a/tests/testdata/outputs_expected/nonascii.sol.o.graph.html b/tests/testdata/outputs_expected/nonascii.sol.o.graph.html
index 51ce8e60..ea28a136 100644
--- a/tests/testdata/outputs_expected/nonascii.sol.o.graph.html
+++ b/tests/testdata/outputs_expected/nonascii.sol.o.graph.html
@@ -18,8 +18,8 @@
diff --git a/tests/testdata/outputs_expected/origin.sol.o.graph.html b/tests/testdata/outputs_expected/origin.sol.o.graph.html
index 181ceb02..a7da8330 100644
--- a/tests/testdata/outputs_expected/origin.sol.o.graph.html
+++ b/tests/testdata/outputs_expected/origin.sol.o.graph.html
@@ -18,8 +18,8 @@
diff --git a/tests/testdata/outputs_expected/origin.sol.o.json b/tests/testdata/outputs_expected/origin.sol.o.json
index 5dac16d6..2024d492 100644
--- a/tests/testdata/outputs_expected/origin.sol.o.json
+++ b/tests/testdata/outputs_expected/origin.sol.o.json
@@ -1,14 +1 @@
-{
- "success": true,
- "error": null,
- "issues": [
- {
- "title": "Use of tx.origin",
- "description": "Function transferOwnership(address) retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.\nSee also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin",
- "function": "transferOwnership(address)",
- "type": "Warning",
- "address": 317,
- "debug": ""
- }
- ]
-}
\ No newline at end of file
+{"error": null, "issues": [{"address": 317, "debug": "", "description": "Function transferOwnership(address) retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.\nSee also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin", "function": "transferOwnership(address)", "title": "Use of tx.origin", "type": "Warning"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/overflow.sol.json b/tests/testdata/outputs_expected/overflow.sol.json
deleted file mode 100644
index 92a56005..00000000
--- a/tests/testdata/outputs_expected/overflow.sol.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "success": true,
- "error": null,
- "issues": [
- {
- "title": "Integer Underflow",
- "description": "A possible integer underflow exists in the function `sendeth(address,uint256)`.\nThe subtraction may result in a value < 0.",
- "function": "sendeth(address,uint256)",
- "type": "Warning",
- "address": 649,
- "debug": "",
- "filename": "/inputs/overflow.sol",
- "lineno": 12,
- "code": "balances[msg.sender] -= _value"
- },
- {
- "title": "Integer Overflow",
- "description": "A possible integer overflow exists in the function `sendeth(address,uint256)`.\nThe addition or multiplication may result in a value higher than the maximum representable integer.",
- "function": "sendeth(address,uint256)",
- "type": "Warning",
- "address": 725,
- "debug": "",
- "filename": "/inputs/overflow.sol",
- "lineno": 13,
- "code": "balances[_to] += _value"
- },
- {
- "title": "Integer Underflow",
- "description": "A possible integer underflow exists in the function `sendeth(address,uint256)`.\nThe subtraction may result in a value < 0.",
- "function": "sendeth(address,uint256)",
- "type": "Warning",
- "address": 567,
- "debug": "",
- "filename": "/inputs/overflow.sol",
- "lineno": 11,
- "code": "balances[msg.sender] - _value"
- }
- ]
-}
diff --git a/tests/testdata/outputs_expected/overflow.sol.markdown b/tests/testdata/outputs_expected/overflow.sol.markdown
deleted file mode 100644
index d6d4a49c..00000000
--- a/tests/testdata/outputs_expected/overflow.sol.markdown
+++ /dev/null
@@ -1,52 +0,0 @@
-# Analysis results for /inputs/overflow.sol
-
-## Integer Underflow
-
-- Type: Warning
-- Contract: Over
-- Function name: `sendeth(address,uint256)`
-- PC address: 649
-
-### Description
-
-A possible integer underflow exists in the function `sendeth(address,uint256)`.
-The subtraction may result in a value < 0.
-In */inputs/overflow.sol:12*
-
-```
-balances[msg.sender] -= _value
-```
-
-## Integer Overflow
-
-- Type: Warning
-- Contract: Over
-- Function name: `sendeth(address,uint256)`
-- PC address: 725
-
-### Description
-
-A possible integer overflow exists in the function `sendeth(address,uint256)`.
-The addition or multiplication may result in a value higher than the maximum representable integer.
-In */inputs/overflow.sol:13*
-
-```
-balances[_to] += _value
-```
-
-## Integer Underflow
-
-- Type: Warning
-- Contract: Over
-- Function name: `sendeth(address,uint256)`
-- PC address: 567
-
-### Description
-
-A possible integer underflow exists in the function `sendeth(address,uint256)`.
-The subtraction may result in a value < 0.
-In */inputs/overflow.sol:11*
-
-```
-balances[msg.sender] - _value
-```
diff --git a/tests/testdata/outputs_expected/overflow.sol.o.graph.html b/tests/testdata/outputs_expected/overflow.sol.o.graph.html
index e16ddfbb..e605ca06 100644
--- a/tests/testdata/outputs_expected/overflow.sol.o.graph.html
+++ b/tests/testdata/outputs_expected/overflow.sol.o.graph.html
@@ -18,8 +18,8 @@
diff --git a/tests/testdata/outputs_expected/overflow.sol.text b/tests/testdata/outputs_expected/overflow.sol.text
deleted file mode 100644
index 64b072ca..00000000
--- a/tests/testdata/outputs_expected/overflow.sol.text
+++ /dev/null
@@ -1,42 +0,0 @@
-==== Integer Underflow ====
-Type: Warning
-Contract: Over
-Function name: sendeth(address,uint256)
-PC address: 649
-A possible integer underflow exists in the function `sendeth(address,uint256)`.
-The subtraction may result in a value < 0.
---------------------
-In file: /inputs/overflow.sol:12
-
-balances[msg.sender] -= _value
-
---------------------
-
-==== Integer Overflow ====
-Type: Warning
-Contract: Over
-Function name: sendeth(address,uint256)
-PC address: 725
-A possible integer overflow exists in the function `sendeth(address,uint256)`.
-The addition or multiplication may result in a value higher than the maximum representable integer.
---------------------
-In file: /inputs/overflow.sol:13
-
-balances[_to] += _value
-
---------------------
-
-==== Integer Underflow ====
-Type: Warning
-Contract: Over
-Function name: sendeth(address,uint256)
-PC address: 567
-A possible integer underflow exists in the function `sendeth(address,uint256)`.
-The subtraction may result in a value < 0.
---------------------
-In file: /inputs/overflow.sol:11
-
-balances[msg.sender] - _value
-
---------------------
-
diff --git a/tests/testdata/outputs_expected/returnvalue.sol.graph.html b/tests/testdata/outputs_expected/returnvalue.sol.graph.html
deleted file mode 100644
index 33184917..00000000
--- a/tests/testdata/outputs_expected/returnvalue.sol.graph.html
+++ /dev/null
@@ -1,146 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
Mythril / LASER Symbolic VM
-
-
-
-
diff --git a/tests/testdata/outputs_expected/returnvalue.sol.o.graph.html b/tests/testdata/outputs_expected/returnvalue.sol.o.graph.html
index b58e1899..1e09f932 100644
--- a/tests/testdata/outputs_expected/returnvalue.sol.o.graph.html
+++ b/tests/testdata/outputs_expected/returnvalue.sol.o.graph.html
@@ -18,8 +18,8 @@
diff --git a/tests/testdata/outputs_expected/returnvalue.sol.o.json b/tests/testdata/outputs_expected/returnvalue.sol.o.json
index 89972e27..a3fe1e4c 100644
--- a/tests/testdata/outputs_expected/returnvalue.sol.o.json
+++ b/tests/testdata/outputs_expected/returnvalue.sol.o.json
@@ -1,30 +1 @@
-{
- "success": true,
- "error": null,
- "issues": [
- {
- "title": "Message call to external contract",
- "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.",
- "function": "_function_0x633ab5e0",
- "type": "Informational",
- "address": 196,
- "debug": ""
- },
- {
- "title": "Message call to external contract",
- "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.",
- "function": "_function_0xe3bea282",
- "type": "Informational",
- "address": 285,
- "debug": ""
- },
- {
- "title": "Unchecked CALL return value",
- "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
- "function": "_function_0xe3bea282",
- "type": "Informational",
- "address": 285,
- "debug": ""
- }
- ]
-}
\ No newline at end of file
+{"error": null, "issues": [{"address": 196, "debug": "", "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", "function": "_function_0x633ab5e0", "title": "Message call to external contract", "type": "Informational"}, {"address": 285, "debug": "", "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", "function": "_function_0xe3bea282", "title": "Message call to external contract", "type": "Informational"}, {"address": 290, "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xe3bea282", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/returnvalue.sol.o.markdown b/tests/testdata/outputs_expected/returnvalue.sol.o.markdown
index c8120dcd..3d12c700 100644
--- a/tests/testdata/outputs_expected/returnvalue.sol.o.markdown
+++ b/tests/testdata/outputs_expected/returnvalue.sol.o.markdown
@@ -27,7 +27,7 @@ This contract executes a message call to to another contract. Make sure that the
- Type: Informational
- Contract: Unknown
- Function name: `_function_0xe3bea282`
-- PC address: 285
+- PC address: 290
### Description
diff --git a/tests/testdata/outputs_expected/returnvalue.sol.o.text b/tests/testdata/outputs_expected/returnvalue.sol.o.text
index 00510eba..c7a67ecb 100644
--- a/tests/testdata/outputs_expected/returnvalue.sol.o.text
+++ b/tests/testdata/outputs_expected/returnvalue.sol.o.text
@@ -18,7 +18,7 @@ This contract executes a message call to to another contract. Make sure that the
Type: Informational
Contract: Unknown
Function name: _function_0xe3bea282
-PC address: 285
+PC address: 290
The return value of an external call is not checked. Note that execution continue even if the called contract throws.
--------------------
diff --git a/tests/testdata/outputs_expected/rubixi.sol.o.json b/tests/testdata/outputs_expected/rubixi.sol.o.json
new file mode 100644
index 00000000..d328ade0
--- /dev/null
+++ b/tests/testdata/outputs_expected/rubixi.sol.o.json
@@ -0,0 +1,166 @@
+{
+ "success": true,
+ "error": null,
+ "issues": [
+ {
+ "title": "Ether send",
+ "description": "In the function `_function_0x4229616d` a non-zero amount of Ether is sent to an address taken from storage slot 5.\nThere is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.\n\nThere is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.\nThere is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.",
+ "function": "_function_0x4229616d",
+ "type": "Warning",
+ "address": 1599,
+ "debug": ""
+ },
+ {
+ "title": "Ether send",
+ "description": "In the function `_function_0xb4022950` a non-zero amount of Ether is sent to an address taken from storage slot 5.\nThere is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.\n\nThere is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.\nThere is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.\nThere is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.\nThere is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.",
+ "function": "_function_0xb4022950",
+ "type": "Warning",
+ "address": 1940,
+ "debug": ""
+ },
+ {
+ "title": "Ether send",
+ "description": "In the function `_function_0xb4022950` a non-zero amount of Ether is sent to an address taken from storage slot 5.\nThere is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.\n\nThere is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.\nThere is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.\nThere is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.\nThere is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.\nThere is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.",
+ "function": "_function_0xb4022950",
+ "type": "Warning",
+ "address": 2582,
+ "debug": ""
+ },
+ {
+ "title": "Exception state",
+ "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ",
+ "function": "_function_0x57d4021b",
+ "type": "Informational",
+ "address": 1653,
+ "debug": ""
+ },
+ {
+ "title": "Exception state",
+ "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ",
+ "function": "_function_0x9dbc4f9b",
+ "type": "Informational",
+ "address": 2085,
+ "debug": ""
+ },
+ {
+ "title": "Invariant branch condition",
+ "description": "Found a conditional jump which always follows the same branch",
+ "function": "fallback",
+ "type": "Informational",
+ "address": 3111,
+ "debug": ""
+ },
+ {
+ "title": "Invariant branch condition",
+ "description": "Found a conditional jump which always follows the same branch",
+ "function": "fallback",
+ "type": "Informational",
+ "address": 3140,
+ "debug": ""
+ },
+ {
+ "title": "Invariant branch condition",
+ "description": "Found a conditional jump which always follows the same branch",
+ "function": "fallback",
+ "type": "Informational",
+ "address": 2950,
+ "debug": ""
+ },
+ {
+ "title": "Invariant branch condition",
+ "description": "Found a conditional jump which always follows the same branch",
+ "function": "fallback",
+ "type": "Informational",
+ "address": 1268,
+ "debug": ""
+ },
+ {
+ "title": "Invariant branch condition",
+ "description": "Found a conditional jump which always follows the same branch",
+ "function": "_function_0x09dfdc71",
+ "type": "Informational",
+ "address": 310,
+ "debug": ""
+ },
+ {
+ "title": "Invariant branch condition",
+ "description": "Found a conditional jump which always follows the same branch",
+ "function": "_function_0x09dfdc71",
+ "type": "Informational",
+ "address": 1316,
+ "debug": ""
+ },
+ {
+ "title": "Invariant branch condition",
+ "description": "Found a conditional jump which always follows the same branch",
+ "function": "_function_0x253459e3",
+ "type": "Informational",
+ "address": 1375,
+ "debug": ""
+ },
+ {
+ "title": "Invariant branch condition",
+ "description": "Found a conditional jump which always follows the same branch",
+ "function": "_function_0x4229616d",
+ "type": "Informational",
+ "address": 1511,
+ "debug": ""
+ },
+ {
+ "title": "Invariant branch condition",
+ "description": "Found a conditional jump which always follows the same branch",
+ "function": "_function_0x57d4021b",
+ "type": "Informational",
+ "address": 1679,
+ "debug": ""
+ },
+ {
+ "title": "Invariant branch condition",
+ "description": "Found a conditional jump which always follows the same branch",
+ "function": "_function_0x6fbaaa1e",
+ "type": "Informational",
+ "address": 618,
+ "debug": ""
+ },
+ {
+ "title": "Invariant branch condition",
+ "description": "Found a conditional jump which always follows the same branch",
+ "function": "_function_0x8a5fb3ca",
+ "type": "Informational",
+ "address": 805,
+ "debug": ""
+ },
+ {
+ "title": "Invariant branch condition",
+ "description": "Found a conditional jump which always follows the same branch",
+ "function": "_function_0x9dbc4f9b",
+ "type": "Informational",
+ "address": 2187,
+ "debug": ""
+ },
+ {
+ "title": "Unchecked CALL return value",
+ "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
+ "function": "_function_0x4229616d",
+ "type": "Informational",
+ "address": 1599,
+ "debug": ""
+ },
+ {
+ "title": "Unchecked CALL return value",
+ "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
+ "function": "_function_0xb4022950",
+ "type": "Informational",
+ "address": 1940,
+ "debug": ""
+ },
+ {
+ "title": "Unchecked CALL return value",
+ "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.",
+ "function": "_function_0xb4022950",
+ "type": "Informational",
+ "address": 2582,
+ "debug": ""
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/rubixi.sol.o.markdown b/tests/testdata/outputs_expected/rubixi.sol.o.markdown
new file mode 100644
index 00000000..ba755c49
--- /dev/null
+++ b/tests/testdata/outputs_expected/rubixi.sol.o.markdown
@@ -0,0 +1,238 @@
+# Analysis results for test-filename.sol
+
+## Ether send
+
+- Type: Warning
+- Contract: Unknown
+- Function name: `_function_0x4229616d`
+- PC address: 1599
+
+### Description
+
+In the function `_function_0x4229616d` a non-zero amount of Ether is sent to an address taken from storage slot 5.
+There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
+
+There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
+There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
+
+## Ether send
+
+- Type: Warning
+- Contract: Unknown
+- Function name: `_function_0xb4022950`
+- PC address: 1940
+
+### Description
+
+In the function `_function_0xb4022950` a non-zero amount of Ether is sent to an address taken from storage slot 5.
+There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
+
+There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
+There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
+There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
+There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
+
+## Ether send
+
+- Type: Warning
+- Contract: Unknown
+- Function name: `_function_0xb4022950`
+- PC address: 2582
+
+### Description
+
+In the function `_function_0xb4022950` a non-zero amount of Ether is sent to an address taken from storage slot 5.
+There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
+
+There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
+There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
+There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
+There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
+There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
+
+## Exception state
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `_function_0x57d4021b`
+- PC address: 1653
+
+### Description
+
+A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking.
+
+## Exception state
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `_function_0x9dbc4f9b`
+- PC address: 2085
+
+### Description
+
+A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking.
+
+## Tautology
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `fallback`
+- PC address: 3111
+
+### Description
+
+Found a conditional jump which always follows the same branch, value: True
+
+## Tautology
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `fallback`
+- PC address: 3140
+
+### Description
+
+Found a conditional jump which always follows the same branch, value: True
+
+## Tautology
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `fallback`
+- PC address: 2950
+
+### Description
+
+Found a conditional jump which always follows the same branch, value: True
+
+## Tautology
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `fallback`
+- PC address: 1268
+
+### Description
+
+Found a conditional jump which always follows the same branch, value: True
+
+## Tautology
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `_function_0x09dfdc71`
+- PC address: 310
+
+### Description
+
+Found a conditional jump which always follows the same branch, value: False
+
+## Tautology
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `_function_0x09dfdc71`
+- PC address: 1316
+
+### Description
+
+Found a conditional jump which always follows the same branch, value: True
+
+## Tautology
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `_function_0x253459e3`
+- PC address: 1375
+
+### Description
+
+Found a conditional jump which always follows the same branch, value: True
+
+## Tautology
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `_function_0x4229616d`
+- PC address: 1511
+
+### Description
+
+Found a conditional jump which always follows the same branch, value: True
+
+## Tautology
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `_function_0x57d4021b`
+- PC address: 1679
+
+### Description
+
+Found a conditional jump which always follows the same branch, value: True
+
+## Tautology
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `_function_0x6fbaaa1e`
+- PC address: 618
+
+### Description
+
+Found a conditional jump which always follows the same branch, value: False
+
+## Tautology
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `_function_0x8a5fb3ca`
+- PC address: 805
+
+### Description
+
+Found a conditional jump which always follows the same branch, value: False
+
+## Tautology
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `_function_0x9dbc4f9b`
+- PC address: 2187
+
+### Description
+
+Found a conditional jump which always follows the same branch, value: True
+
+## Unchecked CALL return value
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `_function_0x4229616d`
+- PC address: 1599
+
+### Description
+
+The return value of an external call is not checked. Note that execution continue even if the called contract throws.
+
+## Unchecked CALL return value
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `_function_0xb4022950`
+- PC address: 1940
+
+### Description
+
+The return value of an external call is not checked. Note that execution continue even if the called contract throws.
+
+## Unchecked CALL return value
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `_function_0xb4022950`
+- PC address: 2582
+
+### Description
+
+The return value of an external call is not checked. Note that execution continue even if the called contract throws.
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/rubixi.sol.o.text b/tests/testdata/outputs_expected/rubixi.sol.o.text
new file mode 100644
index 00000000..80a40a7f
--- /dev/null
+++ b/tests/testdata/outputs_expected/rubixi.sol.o.text
@@ -0,0 +1,177 @@
+==== Ether send ====
+Type: Warning
+Contract: Unknown
+Function name: _function_0x4229616d
+PC address: 1599
+In the function `_function_0x4229616d` a non-zero amount of Ether is sent to an address taken from storage slot 5.
+There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
+
+There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
+There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
+--------------------
+
+==== Ether send ====
+Type: Warning
+Contract: Unknown
+Function name: _function_0xb4022950
+PC address: 1940
+In the function `_function_0xb4022950` a non-zero amount of Ether is sent to an address taken from storage slot 5.
+There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
+
+There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
+There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
+There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
+There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
+--------------------
+
+==== Ether send ====
+Type: Warning
+Contract: Unknown
+Function name: _function_0xb4022950
+PC address: 2582
+In the function `_function_0xb4022950` a non-zero amount of Ether is sent to an address taken from storage slot 5.
+There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
+
+There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
+There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
+There is a check on storage index 5. This storage slot can be written to by calling the function `_function_0x67f809e9`.
+There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
+There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
+--------------------
+
+==== Exception state ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0x57d4021b
+PC address: 1653
+A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking.
+--------------------
+
+==== Exception state ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0x9dbc4f9b
+PC address: 2085
+A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking.
+--------------------
+
+==== Tautology ====
+Type: Informational
+Contract: Unknown
+Function name: fallback
+PC address: 3111
+Found a conditional jump which always follows the same branch, value: True
+--------------------
+
+==== Tautology ====
+Type: Informational
+Contract: Unknown
+Function name: fallback
+PC address: 3140
+Found a conditional jump which always follows the same branch, value: True
+--------------------
+
+==== Tautology ====
+Type: Informational
+Contract: Unknown
+Function name: fallback
+PC address: 2950
+Found a conditional jump which always follows the same branch, value: True
+--------------------
+
+==== Tautology ====
+Type: Informational
+Contract: Unknown
+Function name: fallback
+PC address: 1268
+Found a conditional jump which always follows the same branch, value: True
+--------------------
+
+==== Tautology ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0x09dfdc71
+PC address: 310
+Found a conditional jump which always follows the same branch, value: False
+--------------------
+
+==== Tautology ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0x09dfdc71
+PC address: 1316
+Found a conditional jump which always follows the same branch, value: True
+--------------------
+
+==== Tautology ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0x253459e3
+PC address: 1375
+Found a conditional jump which always follows the same branch, value: True
+--------------------
+
+==== Tautology ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0x4229616d
+PC address: 1511
+Found a conditional jump which always follows the same branch, value: True
+--------------------
+
+==== Tautology ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0x57d4021b
+PC address: 1679
+Found a conditional jump which always follows the same branch, value: True
+--------------------
+
+==== Tautology ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0x6fbaaa1e
+PC address: 618
+Found a conditional jump which always follows the same branch, value: False
+--------------------
+
+==== Tautology ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0x8a5fb3ca
+PC address: 805
+Found a conditional jump which always follows the same branch, value: False
+--------------------
+
+==== Tautology ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0x9dbc4f9b
+PC address: 2187
+Found a conditional jump which always follows the same branch, value: True
+--------------------
+
+==== Unchecked CALL return value ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0x4229616d
+PC address: 1599
+The return value of an external call is not checked. Note that execution continue even if the called contract throws.
+--------------------
+
+==== Unchecked CALL return value ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0xb4022950
+PC address: 1940
+The return value of an external call is not checked. Note that execution continue even if the called contract throws.
+--------------------
+
+==== Unchecked CALL return value ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0xb4022950
+PC address: 2582
+The return value of an external call is not checked. Note that execution continue even if the called contract throws.
+--------------------
+
diff --git a/tests/testdata/outputs_expected/suicide.sol.json b/tests/testdata/outputs_expected/suicide.sol.json
deleted file mode 100644
index 8b13e751..00000000
--- a/tests/testdata/outputs_expected/suicide.sol.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "success": true,
- "error": null,
- "issues": [
- {
- "title": "Unchecked SUICIDE",
- "description": "The function `_function_0xcbf0b0c0` executes the SUICIDE instruction. The remaining Ether is sent to an address provided as a function argument.\n\nIt seems that this function can be called without restrictions.",
- "function": "_function_0xcbf0b0c0",
- "type": "Warning",
- "address": 146,
- "debug": "",
- "filename": "/inputs/suicide.sol",
- "lineno": 4,
- "code": "selfdestruct(addr)"
- }
- ]
-}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/suicide.sol.markdown b/tests/testdata/outputs_expected/suicide.sol.markdown
deleted file mode 100644
index 78556327..00000000
--- a/tests/testdata/outputs_expected/suicide.sol.markdown
+++ /dev/null
@@ -1,19 +0,0 @@
-# Analysis results for /inputs/suicide.sol
-
-## Unchecked SUICIDE
-
-- Type: Warning
-- Contract: Suicide
-- Function name: `_function_0xcbf0b0c0`
-- PC address: 146
-
-### Description
-
-The function `_function_0xcbf0b0c0` executes the SUICIDE instruction. The remaining Ether is sent to an address provided as a function argument.
-
-It seems that this function can be called without restrictions.
-In */inputs/suicide.sol:4*
-
-```
-selfdestruct(addr)
-```
diff --git a/tests/testdata/outputs_expected/suicide.sol.o.graph.html b/tests/testdata/outputs_expected/suicide.sol.o.graph.html
index de3aacee..a005c53e 100644
--- a/tests/testdata/outputs_expected/suicide.sol.o.graph.html
+++ b/tests/testdata/outputs_expected/suicide.sol.o.graph.html
@@ -18,8 +18,8 @@
diff --git a/tests/testdata/outputs_expected/suicide.sol.o.json b/tests/testdata/outputs_expected/suicide.sol.o.json
index d2316b3a..a8a189b9 100644
--- a/tests/testdata/outputs_expected/suicide.sol.o.json
+++ b/tests/testdata/outputs_expected/suicide.sol.o.json
@@ -1,14 +1 @@
-{
- "success": true,
- "error": null,
- "issues": [
- {
- "title": "Unchecked SUICIDE",
- "description": "The function `_function_0xcbf0b0c0` executes the SUICIDE instruction. The remaining Ether is sent to an address provided as a function argument.\n\nIt seems that this function can be called without restrictions.",
- "function": "_function_0xcbf0b0c0",
- "type": "Warning",
- "address": 146,
- "debug": ""
- }
- ]
-}
\ No newline at end of file
+{"error": null, "issues": [{"address": 146, "debug": "", "description": "The function `_function_0xcbf0b0c0` executes the SUICIDE instruction. The remaining Ether is sent to an address provided as a function argument.\n\nIt seems that this function can be called without restrictions.", "function": "_function_0xcbf0b0c0", "title": "Unchecked SUICIDE", "type": "Warning"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/suicide.sol.text b/tests/testdata/outputs_expected/suicide.sol.text
deleted file mode 100644
index 245c5d18..00000000
--- a/tests/testdata/outputs_expected/suicide.sol.text
+++ /dev/null
@@ -1,15 +0,0 @@
-==== Unchecked SUICIDE ====
-Type: Warning
-Contract: Suicide
-Function name: _function_0xcbf0b0c0
-PC address: 146
-The function `_function_0xcbf0b0c0` executes the SUICIDE instruction. The remaining Ether is sent to an address provided as a function argument.
-
-It seems that this function can be called without restrictions.
---------------------
-In file: /inputs/suicide.sol:4
-
-selfdestruct(addr)
-
---------------------
-
diff --git a/tests/testdata/outputs_expected/underflow.sol.graph.html b/tests/testdata/outputs_expected/underflow.sol.graph.html
deleted file mode 100644
index 59a46e2b..00000000
--- a/tests/testdata/outputs_expected/underflow.sol.graph.html
+++ /dev/null
@@ -1,168 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
Mythril / LASER Symbolic VM
-
-
-
-
diff --git a/tests/testdata/outputs_expected/underflow.sol.json b/tests/testdata/outputs_expected/underflow.sol.json
deleted file mode 100644
index 3a2fbd91..00000000
--- a/tests/testdata/outputs_expected/underflow.sol.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "success": true,
- "error": null,
- "issues": [
- {
- "title": "Integer Underflow",
- "description": "A possible integer underflow exists in the function `sendeth(address,uint256)`.\nThe subtraction may result in a value < 0.",
- "function": "sendeth(address,uint256)",
- "type": "Warning",
- "address": 649,
- "debug": "",
- "filename": "/inputs/underflow.sol",
- "lineno": 12,
- "code": "balances[msg.sender] -= _value"
- },
- {
- "title": "Integer Overflow",
- "description": "A possible integer overflow exists in the function `sendeth(address,uint256)`.\nThe addition or multiplication may result in a value higher than the maximum representable integer.",
- "function": "sendeth(address,uint256)",
- "type": "Warning",
- "address": 725,
- "debug": "",
- "filename": "/inputs/underflow.sol",
- "lineno": 13,
- "code": "balances[_to] += _value"
- },
- {
- "title": "Integer Underflow",
- "description": "A possible integer underflow exists in the function `sendeth(address,uint256)`.\nThe subtraction may result in a value < 0.",
- "function": "sendeth(address,uint256)",
- "type": "Warning",
- "address": 567,
- "debug": "",
- "filename": "/inputs/underflow.sol",
- "lineno": 11,
- "code": "balances[msg.sender] - _value"
- }
- ]
-}
diff --git a/tests/testdata/outputs_expected/underflow.sol.markdown b/tests/testdata/outputs_expected/underflow.sol.markdown
deleted file mode 100644
index b41efee7..00000000
--- a/tests/testdata/outputs_expected/underflow.sol.markdown
+++ /dev/null
@@ -1,52 +0,0 @@
-# Analysis results for /inputs/underflow.sol
-
-## Integer Underflow
-
-- Type: Warning
-- Contract: Under
-- Function name: `sendeth(address,uint256)`
-- PC address: 649
-
-### Description
-
-A possible integer underflow exists in the function `sendeth(address,uint256)`.
-The subtraction may result in a value < 0.
-In */inputs/underflow.sol:12*
-
-```
-balances[msg.sender] -= _value
-```
-
-## Integer Overflow
-
-- Type: Warning
-- Contract: Under
-- Function name: `sendeth(address,uint256)`
-- PC address: 725
-
-### Description
-
-A possible integer overflow exists in the function `sendeth(address,uint256)`.
-The addition or multiplication may result in a value higher than the maximum representable integer.
-In */inputs/underflow.sol:13*
-
-```
-balances[_to] += _value
-```
-
-## Integer Underflow
-
-- Type: Warning
-- Contract: Under
-- Function name: `sendeth(address,uint256)`
-- PC address: 567
-
-### Description
-
-A possible integer underflow exists in the function `sendeth(address,uint256)`.
-The subtraction may result in a value < 0.
-In */inputs/underflow.sol:11*
-
-```
-balances[msg.sender] - _value
-```
diff --git a/tests/testdata/outputs_expected/underflow.sol.o.graph.html b/tests/testdata/outputs_expected/underflow.sol.o.graph.html
index 0c60f7e1..72b54f9e 100644
--- a/tests/testdata/outputs_expected/underflow.sol.o.graph.html
+++ b/tests/testdata/outputs_expected/underflow.sol.o.graph.html
@@ -18,8 +18,8 @@
diff --git a/tests/testdata/outputs_expected/underflow.sol.text b/tests/testdata/outputs_expected/underflow.sol.text
deleted file mode 100644
index a3409ad1..00000000
--- a/tests/testdata/outputs_expected/underflow.sol.text
+++ /dev/null
@@ -1,42 +0,0 @@
-==== Integer Underflow ====
-Type: Warning
-Contract: Under
-Function name: sendeth(address,uint256)
-PC address: 649
-A possible integer underflow exists in the function `sendeth(address,uint256)`.
-The subtraction may result in a value < 0.
---------------------
-In file: /inputs/underflow.sol:12
-
-balances[msg.sender] -= _value
-
---------------------
-
-==== Integer Overflow ====
-Type: Warning
-Contract: Under
-Function name: sendeth(address,uint256)
-PC address: 725
-A possible integer overflow exists in the function `sendeth(address,uint256)`.
-The addition or multiplication may result in a value higher than the maximum representable integer.
---------------------
-In file: /inputs/underflow.sol:13
-
-balances[_to] += _value
-
---------------------
-
-==== Integer Underflow ====
-Type: Warning
-Contract: Under
-Function name: sendeth(address,uint256)
-PC address: 567
-A possible integer underflow exists in the function `sendeth(address,uint256)`.
-The subtraction may result in a value < 0.
---------------------
-In file: /inputs/underflow.sol:11
-
-balances[msg.sender] - _value
-
---------------------
-
diff --git a/tests/testdata/outputs_expected/weak_random.sol.o.json b/tests/testdata/outputs_expected/weak_random.sol.o.json
new file mode 100644
index 00000000..2338b178
--- /dev/null
+++ b/tests/testdata/outputs_expected/weak_random.sol.o.json
@@ -0,0 +1,46 @@
+{
+ "success": true,
+ "error": null,
+ "issues": [
+ {
+ "title": "Dependence on predictable environment variable",
+ "description": "In the function `_function_0xe9874106` the following predictable state variables are used to determine Ether recipient:\n- block.coinbase\n",
+ "function": "_function_0xe9874106",
+ "type": "Warning",
+ "address": 1285,
+ "debug": ""
+ },
+ {
+ "title": "Ether send",
+ "description": "In the function `_function_0xe9874106` a non-zero amount of Ether is sent to an address taken from storage slot 0.\nThere is a check on storage index 0. This storage slot can be written to by calling the function `fallback`.\n\nThere is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.\nThere is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.",
+ "function": "_function_0xe9874106",
+ "type": "Warning",
+ "address": 1285,
+ "debug": ""
+ },
+ {
+ "title": "Exception state",
+ "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ",
+ "function": "fallback",
+ "type": "Informational",
+ "address": 356,
+ "debug": ""
+ },
+ {
+ "title": "Exception state",
+ "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ",
+ "function": "_function_0xe9874106",
+ "type": "Informational",
+ "address": 146,
+ "debug": ""
+ },
+ {
+ "title": "Transaction order dependence",
+ "description": "A possible transaction order independence vulnerability exists in function _function_0xe9874106. The value or direction of the call statement is determined from a tainted storage location",
+ "function": "_function_0xe9874106",
+ "type": "Warning",
+ "address": 1285,
+ "debug": ""
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/weak_random.sol.o.markdown b/tests/testdata/outputs_expected/weak_random.sol.o.markdown
new file mode 100644
index 00000000..b5744566
--- /dev/null
+++ b/tests/testdata/outputs_expected/weak_random.sol.o.markdown
@@ -0,0 +1,62 @@
+# Analysis results for test-filename.sol
+
+## Dependence on predictable environment variable
+
+- Type: Warning
+- Contract: Unknown
+- Function name: `_function_0xe9874106`
+- PC address: 1285
+
+### Description
+
+In the function `_function_0xe9874106` the following predictable state variables are used to determine Ether recipient:
+- block.coinbase
+
+
+## Ether send
+
+- Type: Warning
+- Contract: Unknown
+- Function name: `_function_0xe9874106`
+- PC address: 1285
+
+### Description
+
+In the function `_function_0xe9874106` a non-zero amount of Ether is sent to an address taken from storage slot 0.
+There is a check on storage index 0. This storage slot can be written to by calling the function `fallback`.
+
+There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
+There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
+
+## Exception state
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `fallback`
+- PC address: 356
+
+### Description
+
+A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking.
+
+## Exception state
+
+- Type: Informational
+- Contract: Unknown
+- Function name: `_function_0xe9874106`
+- PC address: 146
+
+### Description
+
+A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking.
+
+## Transaction order dependence
+
+- Type: Warning
+- Contract: Unknown
+- Function name: `_function_0xe9874106`
+- PC address: 1285
+
+### Description
+
+A possible transaction order independence vulnerability exists in function _function_0xe9874106. The value or direction of the call statement is determined from a tainted storage location
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/weak_random.sol.o.text b/tests/testdata/outputs_expected/weak_random.sol.o.text
new file mode 100644
index 00000000..9e105cfe
--- /dev/null
+++ b/tests/testdata/outputs_expected/weak_random.sol.o.text
@@ -0,0 +1,46 @@
+==== Dependence on predictable environment variable ====
+Type: Warning
+Contract: Unknown
+Function name: _function_0xe9874106
+PC address: 1285
+In the function `_function_0xe9874106` the following predictable state variables are used to determine Ether recipient:
+- block.coinbase
+
+--------------------
+
+==== Ether send ====
+Type: Warning
+Contract: Unknown
+Function name: _function_0xe9874106
+PC address: 1285
+In the function `_function_0xe9874106` a non-zero amount of Ether is sent to an address taken from storage slot 0.
+There is a check on storage index 0. This storage slot can be written to by calling the function `fallback`.
+
+There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
+There is a check on storage index 1. This storage slot can be written to by calling the function `fallback`.
+--------------------
+
+==== Exception state ====
+Type: Informational
+Contract: Unknown
+Function name: fallback
+PC address: 356
+A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking.
+--------------------
+
+==== Exception state ====
+Type: Informational
+Contract: Unknown
+Function name: _function_0xe9874106
+PC address: 146
+A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking.
+--------------------
+
+==== Transaction order dependence ====
+Type: Warning
+Contract: Unknown
+Function name: _function_0xe9874106
+PC address: 1285
+A possible transaction order independence vulnerability exists in function _function_0xe9874106. The value or direction of the call statement is determined from a tainted storage location
+--------------------
+
From b1d112784164e946e64cd61911c7f701620bd1ee Mon Sep 17 00:00:00 2001
From: Konrad Weiss
Date: Thu, 5 Jul 2018 10:13:45 +0200
Subject: [PATCH 36/62] Portyng symbolic name formating to the new svm and
instructions file structure
---
mythril/laser/ethereum/instructions.py | 47 +++++++++++++++-----------
1 file changed, 27 insertions(+), 20 deletions(-)
diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py
index 4d90da95..89844986 100644
--- a/mythril/laser/ethereum/instructions.py
+++ b/mythril/laser/ethereum/instructions.py
@@ -157,7 +157,7 @@ class Instruction:
result = Concat(BitVecVal(0, 248), Extract(offset + 7, offset, op1))
except AttributeError:
logging.debug("BYTE: Unsupported symbolic byte offset")
- result = BitVec(str(simplify(op1)) + "_" + str(simplify(op0)), 256)
+ result = BitVec(str(simplify(op1)) + "[" + str(simplify(op0)) + "]", 256)
mstate.stack.append(simplify(result))
return [global_state]
@@ -219,7 +219,7 @@ class Instruction:
base, exponent = util.pop_bitvec(state), util.pop_bitvec(state)
if (type(base) != BitVecNumRef) or (type(exponent) != BitVecNumRef):
- state.stack.append(BitVec(str(base) + "_EXP_" + str(exponent), 256))
+ state.stack.append(BitVec("(" + str(simplify(base)) + ")^(" + str(simplify(exponent)) + ")", 256))
elif base.as_long() == 2:
if exponent.as_long() == 0:
state.stack.append(BitVecVal(1, 256))
@@ -330,13 +330,13 @@ class Instruction:
b = environment.calldata[offset]
except AttributeError:
logging.debug("CALLDATALOAD: Unsupported symbolic index")
- state.stack.append(
- BitVec("calldata_" + str(environment.active_account.contract_name) + "_" + str(op0), 256))
+ state.stack.append(BitVec(
+ "calldata_" + str(environment.active_account.contract_name) + "[" + str(simplify(op0)) + "]", 256))
return [global_state]
except IndexError:
logging.debug("Calldata not set, using symbolic variable instead")
- state.stack.append(
- BitVec("calldata_" + str(environment.active_account.contract_name) + "_" + str(op0), 256))
+ state.stack.append(BitVec(
+ "calldata_" + str(environment.active_account.contract_name) + "[" + str(simplify(op0)) + "]", 256))
return [global_state]
if type(b) == int:
@@ -350,12 +350,12 @@ class Instruction:
state.stack.append(BitVecVal(int.from_bytes(val, byteorder='big'), 256))
# FIXME: broad exception catch
except:
- state.stack.append(
- BitVec("calldata_" + str(environment.active_account.contract_name) + "_" + str(op0), 256))
+ state.stack.append(BitVec(
+ "calldata_" + str(environment.active_account.contract_name) + "[" + str(simplify(op0)) + "]", 256))
else:
# symbolic variable
- state.stack.append(
- BitVec("calldata_" + str(environment.active_account.contract_name) + "_" + str(op0), 256))
+ state.stack.append(BitVec(
+ "calldata_" + str(environment.active_account.contract_name) + "[" + str(simplify(op0)) + "]", 256))
return [global_state]
@@ -382,24 +382,29 @@ class Instruction:
logging.debug("Unsupported symbolic memory offset in CALLDATACOPY")
return [global_state]
+ dstart_sym = False
try:
dstart = util.get_concrete_int(op1)
+ dstart_sym = True
# FIXME: broad exception catch
except:
logging.debug("Unsupported symbolic calldata offset in CALLDATACOPY")
- state.mem_extend(mstart, 1)
- state.memory[mstart] = BitVec("calldata_" + str(environment.active_account.contract_name) + "_cpy",
- 256)
- return [global_state]
+ dstart = simplify(op1)
+ size_sym = False
try:
size = util.get_concrete_int(op2)
+ size_sym = True
# FIXME: broad exception catch
except:
logging.debug("Unsupported symbolic size in CALLDATACOPY")
+ size = simplify(op2)
+
+ if dstart_sym or size_sym:
state.mem_extend(mstart, 1)
state.memory[mstart] = BitVec(
- "calldata_" + str(environment.active_account.contract_name) + "_" + str(dstart), 256)
+ "calldata_" + str(environment.active_account.contract_name) + "[" + str(dstart) + ": + " + str(
+ size) + "]", 256)
return [global_state]
if size > 0:
@@ -410,7 +415,8 @@ class Instruction:
logging.debug("Memory allocation error: mstart = " + str(mstart) + ", size = " + str(size))
state.mem_extend(mstart, 1)
state.memory[mstart] = BitVec(
- "calldata_" + str(environment.active_account.contract_name) + "_" + str(dstart), 256)
+ "calldata_" + str(environment.active_account.contract_name) + "[" + str(dstart) + ": + " + str(
+ size) + "]", 256)
return [global_state]
try:
@@ -423,7 +429,8 @@ class Instruction:
logging.debug("Exception copying calldata to memory")
state.memory[mstart] = BitVec(
- "calldata_" + str(environment.active_account.contract_name) + "_" + str(dstart), 256)
+ "calldata_" + str(environment.active_account.contract_name) + "[" + str(dstart) + ": + " + str(
+ size) + "]", 256)
return [global_state]
# Environment
@@ -474,7 +481,7 @@ class Instruction:
# FIXME: broad exception catch
except:
# Can't access symbolic memory offsets
- state.stack.append(BitVec("KECCAC_mem_" + str(op0) + ")", 256))
+ state.stack.append(BitVec("KECCAC_mem[" + str(simplify(op0)) + "]", 256))
return [global_state]
try:
@@ -590,14 +597,14 @@ class Instruction:
offset = util.get_concrete_int(op0)
except AttributeError:
logging.debug("Can't MLOAD from symbolic index")
- data = BitVec("mem_" + str(op0), 256)
+ data = BitVec("mem[" + str(simplify(op0)) + "]", 256)
state.stack.append(data)
return [global_state]
try:
data = util.concrete_int_from_bytes(state.memory, offset)
except IndexError: # Memory slot not allocated
- data = BitVec("mem_" + str(offset), 256)
+ data = BitVec("mem[" + str(offset) + "]", 256)
except TypeError: # Symbolic memory
data = state.memory[offset]
From 6bbab6855a12cabec3f22cf7fcbcde8408c3b9c3 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Thu, 5 Jul 2018 11:30:28 +0200
Subject: [PATCH 37/62] Add return statement
---
mythril/laser/ethereum/call.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/mythril/laser/ethereum/call.py b/mythril/laser/ethereum/call.py
index 23145b9e..483894ce 100644
--- a/mythril/laser/ethereum/call.py
+++ b/mythril/laser/ethereum/call.py
@@ -111,10 +111,13 @@ def get_callee_account(global_state, callee_address, dynamic_loader):
if code is None:
logging.info("No code returned, not a contract account?")
raise ValueError()
+ logging.info("Dependency loaded: " + callee_address)
- accounts[callee_address] = Account(callee_address, code, callee_address)
+ callee_account = Account(callee_address, code, callee_address)
+ accounts[callee_address] = callee_account
+
+ return callee_account
- logging.info("Dependency loaded: " + callee_address)
def get_call_data(global_state, memory_start, memory_size, pad=True):
From 5c0e65b2d80981ecfd8507acc598a80932c6ef9a Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Thu, 5 Jul 2018 11:55:29 +0200
Subject: [PATCH 38/62] Implementation of a depth first search search strategy
---
mythril/laser/ethereum/strategy/__init__.py | 0
mythril/laser/ethereum/strategy/basic.py | 17 +++++++++++++++++
mythril/laser/ethereum/svm.py | 13 ++++---------
3 files changed, 21 insertions(+), 9 deletions(-)
create mode 100644 mythril/laser/ethereum/strategy/__init__.py
create mode 100644 mythril/laser/ethereum/strategy/basic.py
diff --git a/mythril/laser/ethereum/strategy/__init__.py b/mythril/laser/ethereum/strategy/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/mythril/laser/ethereum/strategy/basic.py b/mythril/laser/ethereum/strategy/basic.py
new file mode 100644
index 00000000..4dc2d968
--- /dev/null
+++ b/mythril/laser/ethereum/strategy/basic.py
@@ -0,0 +1,17 @@
+class DepthFirstSearchStrategy:
+
+ def __init__(self, content, max_depth):
+ self.content = content
+ self.max_depth = max_depth
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ try:
+ global_state = self.content.pop(0)
+ if global_state.mstate.depth >= self.max_depth:
+ return self.__next__()
+ return global_state
+ except IndexError:
+ raise StopIteration()
diff --git a/mythril/laser/ethereum/svm.py b/mythril/laser/ethereum/svm.py
index 0001f8e0..fc835662 100644
--- a/mythril/laser/ethereum/svm.py
+++ b/mythril/laser/ethereum/svm.py
@@ -3,6 +3,7 @@ import logging
from mythril.laser.ethereum.state import GlobalState, Environment, CalldataType, Account
from mythril.laser.ethereum.instructions import Instruction
from mythril.laser.ethereum.cfg import NodeFlags, Node, Edge, JumpType
+from mythril.laser.ethereum.strategy.basic import DepthFirstSearchStrategy
TT256 = 2 ** 256
TT256M1 = 2 ** 256 - 1
@@ -31,7 +32,7 @@ class LaserEVM:
self.dynamic_loader = dynamic_loader
self.work_list = []
- self.max_depth = max_depth
+ self.strategy = DepthFirstSearchStrategy(self.work_list, max_depth)
logging.info("LASER EVM initialized with dynamic loader: " + str(dynamic_loader))
@@ -57,20 +58,14 @@ class LaserEVM:
initial_node.states.append(global_state)
# Empty the work_list before starting an execution
- self.work_list = [global_state]
+ self.work_list.append(global_state)
self._sym_exec()
logging.info("Execution complete")
logging.info("%d nodes, %d edges, %d total states", len(self.nodes), len(self.edges), self.total_states)
def _sym_exec(self):
- while True:
- try:
- global_state = self.work_list.pop(0)
- if global_state.mstate.depth >= self.max_depth: continue
- except IndexError:
- return
-
+ for global_state in self.strategy:
try:
new_states, op_code = self.execute_state(global_state)
except NotImplementedError:
From b973a1686f269044e670704b56c07ca79336c29c Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Thu, 5 Jul 2018 12:01:26 +0200
Subject: [PATCH 39/62] Add documentation and fix pop
---
mythril/laser/ethereum/strategy/basic.py | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/mythril/laser/ethereum/strategy/basic.py b/mythril/laser/ethereum/strategy/basic.py
index 4dc2d968..754cd3ef 100644
--- a/mythril/laser/ethereum/strategy/basic.py
+++ b/mythril/laser/ethereum/strategy/basic.py
@@ -1,17 +1,29 @@
-class DepthFirstSearchStrategy:
+"""
+This module implements basic symbolic execution search strategies
+"""
+
- def __init__(self, content, max_depth):
- self.content = content
+class DepthFirstSearchStrategy:
+ """
+ Implements a depth first search strategy
+ I.E. Follow one path to a leaf, and then continue to the next one
+ """
+ def __init__(self, work_list, max_depth):
+ self.work_list = work_list
self.max_depth = max_depth
def __iter__(self):
return self
def __next__(self):
+ """ Picks the next state to execute """
try:
- global_state = self.content.pop(0)
+ # This strategies assumes that new states are appended at the end of the work_list
+ # By taking the last element we effectively pick the "newest" states, which amounts to dfs
+ global_state = self.work_list.pop()
if global_state.mstate.depth >= self.max_depth:
return self.__next__()
return global_state
except IndexError:
raise StopIteration()
+
From b82717afedda02b94fed56e5abbed7a66480f879 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Thu, 5 Jul 2018 12:05:08 +0200
Subject: [PATCH 40/62] re add max depth for now
---
mythril/laser/ethereum/svm.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/mythril/laser/ethereum/svm.py b/mythril/laser/ethereum/svm.py
index fc835662..1ceb3740 100644
--- a/mythril/laser/ethereum/svm.py
+++ b/mythril/laser/ethereum/svm.py
@@ -33,6 +33,7 @@ class LaserEVM:
self.work_list = []
self.strategy = DepthFirstSearchStrategy(self.work_list, max_depth)
+ self.max_depth = max_depth
logging.info("LASER EVM initialized with dynamic loader: " + str(dynamic_loader))
From eb963d38fde46d39e91b4be14a68263b869d35d7 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Thu, 5 Jul 2018 12:16:18 +0200
Subject: [PATCH 41/62] Implement depth first search
---
mythril/laser/ethereum/strategy/basic.py | 25 ++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/mythril/laser/ethereum/strategy/basic.py b/mythril/laser/ethereum/strategy/basic.py
index 754cd3ef..33dca443 100644
--- a/mythril/laser/ethereum/strategy/basic.py
+++ b/mythril/laser/ethereum/strategy/basic.py
@@ -27,3 +27,28 @@ class DepthFirstSearchStrategy:
except IndexError:
raise StopIteration()
+
+class BreadthFirstSearchStrategy:
+ """
+ Implements a breadth first search strategy
+ I.E. Execute all states of a "level" before continuing
+ """
+ def __init__(self, work_list, max_depth):
+ self.work_list = work_list
+ self.max_depth = max_depth
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ """ Picks the next state to execute """
+ try:
+ # This strategies assumes that new states are appended at the end of the work_list
+ # By taking the first element we effectively pick the "oldest" states, which amounts to bfs
+ global_state = self.work_list.pop(0)
+ if global_state.mstate.depth >= self.max_depth:
+ return self.__next__()
+ return global_state
+ except IndexError:
+ raise StopIteration()
+
From 25f76368bca4e7865811fcc578a13ac10a09f8ce Mon Sep 17 00:00:00 2001
From: Nikhil Parasaram
Date: Fri, 6 Jul 2018 21:45:18 +0530
Subject: [PATCH 42/62] Support 0x0 for extcodesize
---
mythril/laser/ethereum/instructions.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py
index 4d90da95..64e87937 100644
--- a/mythril/laser/ethereum/instructions.py
+++ b/mythril/laser/ethereum/instructions.py
@@ -529,8 +529,12 @@ class Instruction:
logging.info("error accessing contract storage due to: " + str(e))
state.stack.append(BitVec("extcodesize_" + str(addr), 256))
return [global_state]
+
+ if code is None:
+ state.stack.append(0)
+ else:
+ state.stack.append(len(code.bytecode) // 2)
- state.stack.append(len(code.bytecode) // 2)
return [global_state]
@instruction
From 24fad14cbd498e49834cf22b3f043bfe66a7bd39 Mon Sep 17 00:00:00 2001
From: Nikhil Parasaram
Date: Fri, 6 Jul 2018 22:25:39 +0530
Subject: [PATCH 43/62] fix ethereum to 2.3.1
---
requirements.txt | 2 +-
setup.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/requirements.txt b/requirements.txt
index 13e88c78..aad67f69 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,7 +2,7 @@ configparser>=3.5.0
coverage
eth_abi>=1.0.0
eth-account>=0.1.0a2
-ethereum>=2.3.0
+ethereum==2.3.1
eth-hash>=0.1.0
eth-keyfile>=0.5.1
eth-keys>=0.2.0b3
diff --git a/setup.py b/setup.py
index 3cbf5f97..0e7c624d 100755
--- a/setup.py
+++ b/setup.py
@@ -305,7 +305,7 @@ setup(
packages=find_packages(exclude=['contrib', 'docs', 'tests']),
install_requires=[
- 'ethereum>=2.3.0',
+ 'ethereum==2.3.1',
'z3-solver>=4.5',
'requests',
'py-solc',
From d0efd35ce25a817415c17e82ee4d734c3f4e17d4 Mon Sep 17 00:00:00 2001
From: Nikhil Parasaram
Date: Sat, 7 Jul 2018 19:19:26 +0530
Subject: [PATCH 44/62] connect to infura with -l
---
mythril/mythril.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mythril/mythril.py b/mythril/mythril.py
index b63cc137..a72a82d7 100644
--- a/mythril/mythril.py
+++ b/mythril/mythril.py
@@ -335,9 +335,9 @@ class Mythril(object):
verbose_report=False, max_depth=12):
all_issues = []
+ if self.dynld and self.eth is None:
+ self.set_api_rpc_infura()
for contract in (contracts or self.contracts):
- if self.eth is None:
- self.set_api_rpc_infura()
sym = SymExecWrapper(contract, address,
dynloader=DynLoader(self.eth) if self.dynld else None,
max_depth=max_depth)
From 290aaf81988e55366100c900dae4bb5b767c499e Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Sat, 7 Jul 2018 22:16:01 +0200
Subject: [PATCH 45/62] Add condition not 0
---
mythril/laser/ethereum/call.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mythril/laser/ethereum/call.py b/mythril/laser/ethereum/call.py
index 483894ce..58eafed3 100644
--- a/mythril/laser/ethereum/call.py
+++ b/mythril/laser/ethereum/call.py
@@ -36,7 +36,7 @@ def get_call_parameters(global_state, dynamic_loader, with_value=False):
callee_account = None
call_data, call_data_type = get_call_data(global_state, meminstart, meminsz, False)
- if int(callee_address, 16) >= 5:
+ if int(callee_address, 16) >= 5 or int(callee_address) != 0:
call_data, call_data_type = get_call_data(global_state, meminstart, meminsz)
callee_account = get_callee_account(global_state, callee_address, dynamic_loader)
From c3d1eb85c36ccb0f46f638f01d05f90d82b6dbb5 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Sat, 7 Jul 2018 22:16:47 +0200
Subject: [PATCH 46/62] Pass None as node
---
mythril/laser/ethereum/instructions.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py
index 4d90da95..72451f48 100644
--- a/mythril/laser/ethereum/instructions.py
+++ b/mythril/laser/ethereum/instructions.py
@@ -913,7 +913,7 @@ class Instruction:
value,
environment.origin,
calldata_type=call_data_type)
- new_global_state = GlobalState(global_state.accounts, callee_environment, MachineState(gas))
+ new_global_state = GlobalState(global_state.accounts, callee_environment, None, MachineState(gas))
new_global_state.mstate.depth = global_state.mstate.depth + 1
new_global_state.mstate.constraints = copy(global_state.mstate.constraints)
return [global_state]
@@ -940,7 +940,7 @@ class Instruction:
environment.caller = environment.address
environment.calldata = call_data
- new_global_state = GlobalState(global_state.accounts, environment, MachineState(gas))
+ new_global_state = GlobalState(global_state.accounts, environment, None, MachineState(gas))
new_global_state.mstate.depth = global_state.mstate.depth + 1
new_global_state.mstate.constraints = copy(global_state.mstate.constraints)
@@ -968,7 +968,7 @@ class Instruction:
environment.code = callee_account.code
environment.calldata = call_data
- new_global_state = GlobalState(global_state.accounts, environment, MachineState(gas))
+ new_global_state = GlobalState(global_state.accounts, environment, None, MachineState(gas))
new_global_state.mstate.depth = global_state.mstate.depth + 1
new_global_state.mstate.constraints = copy(global_state.mstate.constraints)
From 09c41deb6370ffdb548e9df04d7722e55b38c39b Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Sat, 7 Jul 2018 22:43:01 +0200
Subject: [PATCH 47/62] Fix node issue
---
mythril/laser/ethereum/instructions.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py
index 72451f48..56456fdd 100644
--- a/mythril/laser/ethereum/instructions.py
+++ b/mythril/laser/ethereum/instructions.py
@@ -913,7 +913,7 @@ class Instruction:
value,
environment.origin,
calldata_type=call_data_type)
- new_global_state = GlobalState(global_state.accounts, callee_environment, None, MachineState(gas))
+ new_global_state = GlobalState(global_state.accounts, callee_environment, global_state.node, MachineState(gas))
new_global_state.mstate.depth = global_state.mstate.depth + 1
new_global_state.mstate.constraints = copy(global_state.mstate.constraints)
return [global_state]
@@ -940,7 +940,7 @@ class Instruction:
environment.caller = environment.address
environment.calldata = call_data
- new_global_state = GlobalState(global_state.accounts, environment, None, MachineState(gas))
+ new_global_state = GlobalState(global_state.accounts, environment, global_state.node, MachineState(gas))
new_global_state.mstate.depth = global_state.mstate.depth + 1
new_global_state.mstate.constraints = copy(global_state.mstate.constraints)
@@ -968,7 +968,7 @@ class Instruction:
environment.code = callee_account.code
environment.calldata = call_data
- new_global_state = GlobalState(global_state.accounts, environment, None, MachineState(gas))
+ new_global_state = GlobalState(global_state.accounts, environment, global_state.node, MachineState(gas))
new_global_state.mstate.depth = global_state.mstate.depth + 1
new_global_state.mstate.constraints = copy(global_state.mstate.constraints)
From 7c638272cbe936ba40cea9d0b5552e0edebeb6aa Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Sat, 7 Jul 2018 23:12:49 +0200
Subject: [PATCH 48/62] Reverse comparison
---
mythril/laser/ethereum/call.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mythril/laser/ethereum/call.py b/mythril/laser/ethereum/call.py
index 58eafed3..63d09837 100644
--- a/mythril/laser/ethereum/call.py
+++ b/mythril/laser/ethereum/call.py
@@ -36,7 +36,7 @@ def get_call_parameters(global_state, dynamic_loader, with_value=False):
callee_account = None
call_data, call_data_type = get_call_data(global_state, meminstart, meminsz, False)
- if int(callee_address, 16) >= 5 or int(callee_address) != 0:
+ if int(callee_address, 16) >= 5 or int(callee_address) == 0:
call_data, call_data_type = get_call_data(global_state, meminstart, meminsz)
callee_account = get_callee_account(global_state, callee_address, dynamic_loader)
From 83c5eca66bc82ca500e6fb75e7de66c34559f734 Mon Sep 17 00:00:00 2001
From: tintinweb
Date: Tue, 3 Jul 2018 23:05:24 +0200
Subject: [PATCH 49/62] added online lookup for signature hashes via
4bytes.directory
---
mythril/disassembler/disassembly.py | 26 +++--------
mythril/support/signatures.py | 67 +++++++++++++++++++++++++++++
2 files changed, 73 insertions(+), 20 deletions(-)
diff --git a/mythril/disassembler/disassembly.py b/mythril/disassembler/disassembly.py
index 787f297f..b7414529 100644
--- a/mythril/disassembler/disassembly.py
+++ b/mythril/disassembler/disassembly.py
@@ -1,6 +1,5 @@
from mythril.ether import asm,util
-import os
-import json
+from mythril.support.signatures import Signatures
import logging
@@ -13,21 +12,11 @@ class Disassembly:
self.addr_to_func = {}
self.bytecode = code
+ signatures = Signatures(enable_online_lookkup=True) # control if you want to have online sighash lookups
try:
- mythril_dir = os.environ['MYTHRIL_DIR']
- except KeyError:
- mythril_dir = os.path.join(os.path.expanduser('~'), ".mythril")
-
- # Load function signatures
-
- signatures_file = os.path.join(mythril_dir, 'signatures.json')
-
- if not os.path.exists(signatures_file):
- logging.info("Missing function signature file. Resolving of function names disabled.")
- signatures = {}
- else:
- with open(signatures_file) as f:
- signatures = json.load(f)
+ signatures.open() # open from default locations
+ except FileNotFoundError:
+ logging.info("Missing function signature file. Resolving of function names from disabled.")
# Parse jump table & resolve function names
@@ -36,7 +25,7 @@ class Disassembly:
for i in jmptable_indices:
func_hash = self.instruction_list[i]['argument']
try:
- func_name = signatures[func_hash]
+ func_name = signatures.get(func_hash) # tries local cache, file and optional online lookup
except KeyError:
func_name = "_function_" + func_hash
@@ -49,8 +38,5 @@ class Disassembly:
except:
continue
-
-
def get_easm(self):
-
return asm.instruction_list_to_easm(self.instruction_list)
diff --git a/mythril/support/signatures.py b/mythril/support/signatures.py
index 0431dd21..5fb21737 100644
--- a/mythril/support/signatures.py
+++ b/mythril/support/signatures.py
@@ -1,7 +1,17 @@
import re
+import os
+import logging
+import json
from ethereum import utils
+try:
+ # load if available but do not fail
+ import ethereum_input_decoder
+except ImportError:
+ ethereum_input_decoder = None
+
+# TODO: tintinweb: move this and signature functionality from mythril.py to class Signatures to have one single interface.
def add_signatures_from_file(file, sigs={}):
funcs = []
@@ -42,3 +52,60 @@ def add_signatures_from_file(file, sigs={}):
signature = re.sub(r'\s', '', signature)
sigs["0x" + utils.sha3(signature)[:4].hex()] = signature
+
+
+class Signatures(object):
+
+ def __init__(self, enable_online_lookkup=True):
+ self.signatures = {} # signatures in-mem cache
+ self.enable_online_lookup =enable_online_lookkup # enable online funcsig resolving
+
+ def open(self, path=None):
+ if not path:
+ # try default locations
+ try:
+ mythril_dir = os.environ['MYTHRIL_DIR']
+ except KeyError:
+ mythril_dir = os.path.join(os.path.expanduser('~'), ".mythril")
+ path = os.path.join(mythril_dir, 'signatures.json')
+
+ if not os.path.exists(path):
+ raise FileNotFoundError("Missing function signature file. Resolving of function names disabled.")
+
+ with open(path) as f:
+ sigs = json.load(f)
+
+ # normalize it to {sighash:list(signatures,...)}
+ for sighash,funcsig in sigs.items():
+ self.signatures.setdefault(sighash, [])
+ self.signatures[sighash].append(funcsig)
+
+ return self
+
+ def get(self, sighash):
+ """
+ get a function signature for a sighash
+ 1) try local cache
+ 2) try online lookup
+ :param sighash:
+ :return: list of function signatures
+ """
+ if not self.signatures.get(sighash) and self.enable_online_lookup:
+ self.signatures[sighash] = Signatures.lookup_online(sighash) # might return multiple sigs
+ return self.signatures.get(sighash)
+
+
+ @staticmethod
+ def lookup_online(sighash):
+ """
+ Lookup function signatures from 4bytes.directory.
+ //tintinweb: the smart-contract-sanctuary project dumps contracts from etherscan.io and feeds them into
+ 4bytes.directory.
+ https://github.com/tintinweb/smart-contract-sanctuary
+
+ :param s: function signature as hexstr
+ :return: a list of possible function signatures for this hash
+ """
+ if not ethereum_input_decoder:
+ return None
+ return list(ethereum_input_decoder.decoder.FourByteDirectory.lookup_signatures(sighash))
From cdd27383970244d943a7de89d8c58d0910e95702 Mon Sep 17 00:00:00 2001
From: tintinweb
Date: Tue, 3 Jul 2018 23:12:48 +0200
Subject: [PATCH 50/62] result to online lookup can be ambiguous. use first
item and note this in disassembly
---
mythril/disassembler/disassembly.py | 14 +++++++++++---
mythril/support/signatures.py | 13 ++++++++-----
2 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/mythril/disassembler/disassembly.py b/mythril/disassembler/disassembly.py
index b7414529..de1c9bad 100644
--- a/mythril/disassembler/disassembly.py
+++ b/mythril/disassembler/disassembly.py
@@ -12,11 +12,11 @@ class Disassembly:
self.addr_to_func = {}
self.bytecode = code
- signatures = Signatures(enable_online_lookkup=True) # control if you want to have online sighash lookups
+ signatures = Signatures(enable_online_lookup=True) # control if you want to have online sighash lookups
try:
signatures.open() # open from default locations
except FileNotFoundError:
- logging.info("Missing function signature file. Resolving of function names from disabled.")
+ logging.info("Missing function signature file. Resolving of function names from signature file disabled.")
# Parse jump table & resolve function names
@@ -25,7 +25,15 @@ class Disassembly:
for i in jmptable_indices:
func_hash = self.instruction_list[i]['argument']
try:
- func_name = signatures.get(func_hash) # tries local cache, file and optional online lookup
+ # tries local cache, file and optional online lookup
+ # may return more than one function signature. since we cannot probe for the correct one we'll use the first
+ func_names = signatures.get(func_hash)
+ if len(func_names) > 1:
+ # ambigious result
+ func_name = "**ambiguous** %s"%func_names[0] # return first hit but note that result was ambiguous
+ else:
+ # only one item
+ func_name = func_names[0]
except KeyError:
func_name = "_function_" + func_hash
diff --git a/mythril/support/signatures.py b/mythril/support/signatures.py
index 5fb21737..04fde734 100644
--- a/mythril/support/signatures.py
+++ b/mythril/support/signatures.py
@@ -56,9 +56,9 @@ def add_signatures_from_file(file, sigs={}):
class Signatures(object):
- def __init__(self, enable_online_lookkup=True):
+ def __init__(self, enable_online_lookup=True):
self.signatures = {} # signatures in-mem cache
- self.enable_online_lookup =enable_online_lookkup # enable online funcsig resolving
+ self.enable_online_lookup =enable_online_lookup # enable online funcsig resolving
def open(self, path=None):
if not path:
@@ -91,14 +91,17 @@ class Signatures(object):
:return: list of function signatures
"""
if not self.signatures.get(sighash) and self.enable_online_lookup:
- self.signatures[sighash] = Signatures.lookup_online(sighash) # might return multiple sigs
- return self.signatures.get(sighash)
+ funcsigs = Signatures.lookup_online(sighash) # might return multiple sigs
+ if funcsigs:
+ # only store if we get at least one result
+ self.signatures[sighash] = funcsigs
+ return self.signatures[sighash] # raise keyerror
@staticmethod
def lookup_online(sighash):
"""
- Lookup function signatures from 4bytes.directory.
+ Lookup function signatures from 4byte.directory.
//tintinweb: the smart-contract-sanctuary project dumps contracts from etherscan.io and feeds them into
4bytes.directory.
https://github.com/tintinweb/smart-contract-sanctuary
From 73efcffde213e1f17aec220611b1d6ac58a38d7d Mon Sep 17 00:00:00 2001
From: tintinweb
Date: Wed, 4 Jul 2018 19:55:11 +0200
Subject: [PATCH 51/62] rebase off master refactor function signature handling
-> one single class to handle signatures -> Signatures().get(sighash) and
Signatures()[sighash] interfaces -> added simple file locking mechanism ref
#294 -> fix signature caching (avoid looking up same hash multiple times)
---
mythril/disassembler/disassembly.py | 11 +-
mythril/mythril.py | 58 +++----
mythril/support/signatures.py | 232 ++++++++++++++++++++++------
3 files changed, 210 insertions(+), 91 deletions(-)
diff --git a/mythril/disassembler/disassembly.py b/mythril/disassembler/disassembly.py
index de1c9bad..a20d4ffe 100644
--- a/mythril/disassembler/disassembly.py
+++ b/mythril/disassembler/disassembly.py
@@ -1,9 +1,9 @@
from mythril.ether import asm,util
-from mythril.support.signatures import Signatures
+from mythril.support.signatures import SignatureDb
import logging
-class Disassembly:
+class Disassembly(object):
def __init__(self, code):
self.instruction_list = asm.disassemble(util.safe_decode(code))
@@ -12,7 +12,7 @@ class Disassembly:
self.addr_to_func = {}
self.bytecode = code
- signatures = Signatures(enable_online_lookup=True) # control if you want to have online sighash lookups
+ signatures = SignatureDb(enable_online_lookup=True) # control if you want to have online sighash lookups
try:
signatures.open() # open from default locations
except FileNotFoundError:
@@ -30,7 +30,7 @@ class Disassembly:
func_names = signatures.get(func_hash)
if len(func_names) > 1:
# ambigious result
- func_name = "**ambiguous** %s"%func_names[0] # return first hit but note that result was ambiguous
+ func_name = "**ambiguous** %s" % func_names[0] # return first hit but note that result was ambiguous
else:
# only one item
func_name = func_names[0]
@@ -46,5 +46,8 @@ class Disassembly:
except:
continue
+ signatures.write() # store resolved signatures (potentially resolved online)
+
def get_easm(self):
+ # todo: tintinweb - print funcsig resolved data from self.addr_to_func?
return asm.instruction_list_to_easm(self.instruction_list)
diff --git a/mythril/mythril.py b/mythril/mythril.py
index a72a82d7..0a85366b 100644
--- a/mythril/mythril.py
+++ b/mythril/mythril.py
@@ -78,8 +78,6 @@ class Mythril(object):
mythril.get_state_variable_from_storage(args)
"""
-
-
def __init__(self, solv=None,
solc_args=None, dynld=False):
@@ -88,7 +86,17 @@ class Mythril(object):
self.dynld = dynld
self.mythril_dir = self._init_mythril_dir()
- self.signatures_file, self.sigs = self._init_signatures()
+
+ self.sigs = signatures.SignatureDb()
+ try:
+ self.sigs.open() # tries mythril_dir/signatures.json by default (provide path= arg to make this configurable)
+ except FileNotFoundError as fnfe:
+ logging.info(
+ "No signature database found. Creating database if sigs are loaded in: " + self.sigs.signatures_file + "\n" +
+ "Consider replacing it with the pre-initialized database at https://raw.githubusercontent.com/ConsenSys/mythril/master/signatures.json")
+ except json.JSONDecodeError as jde:
+ raise CriticalError("Invalid JSON in signatures file " + self.sigs.signatures_file + "\n" + str(jde))
+
self.solc_binary = self._init_solc_binary(solv)
self.leveldb_dir = self._init_config()
@@ -110,33 +118,6 @@ class Mythril(object):
os.mkdir(mythril_dir)
return mythril_dir
- def _init_signatures(self):
-
- # If no function signature file exists, create it. Function signatures from Solidity source code are added automatically.
-
- signatures_file = os.path.join(self.mythril_dir, 'signatures.json')
-
- sigs = {}
- if not os.path.exists(signatures_file):
- logging.info("No signature database found. Creating empty database: " + signatures_file + "\n" +
- "Consider replacing it with the pre-initialized database at https://raw.githubusercontent.com/ConsenSys/mythril/master/signatures.json")
- with open(signatures_file, 'a') as f:
- json.dump({}, f)
-
- with open(signatures_file) as f:
- try:
- sigs = json.load(f)
- except json.JSONDecodeError as e:
- raise CriticalError("Invalid JSON in signatures file " + signatures_file + "\n" + str(e))
- return signatures_file, sigs
-
- def _update_signatures(self, jsonsigs):
- # Save updated function signatures
- with open(self.signatures_file, 'w') as f:
- json.dump(jsonsigs, f)
-
- self.sigs = jsonsigs
-
def _init_config(self):
# If no config file exists, create it. Default LevelDB path is specified based on OS
@@ -300,27 +281,32 @@ class Mythril(object):
file = os.path.expanduser(file)
try:
- signatures.add_signatures_from_file(file, self.sigs)
- self._update_signatures(self.sigs)
+ # import signatures from solidity source
+ with open(file, encoding="utf-8") as f:
+ self.sigs.import_from_solidity_source(f.read())
+
contract = SolidityContract(file, contract_name, solc_args=self.solc_args)
logging.info("Analyzing contract %s:%s" % (file, contract.name))
except FileNotFoundError:
- raise CriticalError("Input file not found: " + file)
+ raise CriticalError("Input file not found: " + file)
except CompilerError as e:
- raise CriticalError(e)
+ raise CriticalError(e)
except NoContractFoundError:
logging.info("The file " + file + " does not contain a compilable contract.")
else:
self.contracts.append(contract)
contracts.append(contract)
+ # Save updated function signatures
+ self.sigs.write() # dump signatures to disk (previously opened file or default location)
+
return address, contracts
def dump_statespace(self, contract, address=None, max_depth=12):
sym = SymExecWrapper(contract, address,
- dynloader=DynLoader(self.eth) if self.dynld else None,
- max_depth=max_depth)
+ dynloader=DynLoader(self.eth) if self.dynld else None,
+ max_depth=max_depth)
return get_serializable_statespace(sym)
diff --git a/mythril/support/signatures.py b/mythril/support/signatures.py
index 04fde734..af86abc4 100644
--- a/mythril/support/signatures.py
+++ b/mythril/support/signatures.py
@@ -1,66 +1,90 @@
+#!/usr/bin/env python3
+# -*- coding: UTF-8 -*-
+"""mythril.py: Function Signature Database
+"""
import re
import os
-import logging
import json
+import time
+import pathlib
+import logging
from ethereum import utils
+# todo: tintinweb - make this a normal requirement? (deps: eth-abi and requests, both already required by mythril)
try:
# load if available but do not fail
import ethereum_input_decoder
+ from ethereum_input_decoder.decoder import FourByteDirectoryOnlineLookupError
except ImportError:
+ # fake it :)
ethereum_input_decoder = None
+ FourByteDirectoryOnlineLookupError = Exception
-# TODO: tintinweb: move this and signature functionality from mythril.py to class Signatures to have one single interface.
-def add_signatures_from_file(file, sigs={}):
-
- funcs = []
-
- with open(file, encoding="utf-8") as f:
-
- code = f.read()
-
- funcs = re.findall(r'function[\s]+(\w+\([^\)]*\))', code, re.DOTALL)
-
- for f in funcs:
+class SimpleFileLock(object):
+ # todo: replace with something more reliable. this is a quick shot on concurrency and might not work in all cases
- f = re.sub(r'[\n]', '', f)
+ def __init__(self, path):
+ self.path = path
+ self.lockfile = pathlib.Path("%s.lck" % path)
+ self.locked = False
- m = re.search(r'^([A-Za-z0-9_]+)', f)
+ def aquire(self, timeout=5):
+ if self.locked:
+ raise Exception("SimpleFileLock: lock already aquired")
- if (m):
-
- signature = m.group(1)
-
- m = re.search(r'\((.*)\)', f)
-
- _args = m.group(1).split(",")
-
- types = []
+ t_end = time.time()+timeout
+ while time.time() < t_end:
+ # try to aquire lock
+ try:
+ self.lockfile.touch(mode=0o0000, exist_ok=False) # touch the lockfile
+ # lockfile does not exist. we have a lock now
+ self.locked = True
+ return
+ except FileExistsError as fee:
+ # check if lockfile date exceeds age and cleanup lock
+ if time.time() > self.lockfile.stat().st_mtime + 60 * 5:
+ self.release(force=True) # cleanup old lockfile > 5mins
- for arg in _args:
+ time.sleep(0.5) # busywait is evil
+ continue
- _type = arg.lstrip().split(" ")[0]
- if _type == "uint":
- _type = "uint256"
+ raise Exception("SimpleFileLock: timeout hit. failed to aquire lock: %s"% (time.time()-self.lockfile.stat().st_mtime))
- types.append(_type)
+ def release(self, force=False):
+ if not force and not self.locked:
+ raise Exception("SimpleFileLock: aquire lock first")
- typelist = ",".join(types)
- signature += "(" + typelist + ")"
+ try:
+ self.lockfile.unlink() # might throw if we force unlock and the file gets removed in the meantime. TOCTOU
+ except FileNotFoundError as fnfe:
+ logging.warning("SimpleFileLock: release(force=%s) on unavailable file. race? %r" % (force, fnfe))
- signature = re.sub(r'\s', '', signature)
+ self.locked = False
- sigs["0x" + utils.sha3(signature)[:4].hex()] = signature
-class Signatures(object):
+class SignatureDb(object):
def __init__(self, enable_online_lookup=True):
+ """
+ Constr
+ :param enable_online_lookup: enable onlien signature hash lookup
+ """
self.signatures = {} # signatures in-mem cache
- self.enable_online_lookup =enable_online_lookup # enable online funcsig resolving
+ self.signatures_file = None
+ self.signatures_file_lock = None
+ self.enable_online_lookup = enable_online_lookup # enable online funcsig resolving
+ self.online_lookup_miss = set() # temporarily track misses from onlinedb to avoid requesting the same non-existent sighash multiple times
+ self.online_directory_unavailable_until = 0 # flag the online directory as unavailable for some time
def open(self, path=None):
+ """
+ Open a function signature db from json file
+
+ :param path: specific path to signatures.json; default mythril location if not specified
+ :return: self
+ """
if not path:
# try default locations
try:
@@ -69,46 +93,152 @@ class Signatures(object):
mythril_dir = os.path.join(os.path.expanduser('~'), ".mythril")
path = os.path.join(mythril_dir, 'signatures.json')
+ self.signatures_file = path # store early to allow error handling to access the place we tried to load the file
+
if not os.path.exists(path):
+ logging.debug("Signatures: file not found: %s" % path)
raise FileNotFoundError("Missing function signature file. Resolving of function names disabled.")
- with open(path) as f:
+ self.signatures_file_lock = SimpleFileLock(self.signatures_file) # lock file to prevent concurrency issues
+ self.signatures_file_lock.aquire() # try to aquire it within the next 10s
+
+ with open(path, 'r') as f:
sigs = json.load(f)
+ self.signatures_file_lock.release() # release lock
+
# normalize it to {sighash:list(signatures,...)}
- for sighash,funcsig in sigs.items():
+ for sighash, funcsig in sigs.items():
+ if isinstance(funcsig, list):
+ self.signatures = sigs # keep original todo: tintinweb - super hacky. make sure signatures.json is initially in correct format fixme
+ break # already normalized
self.signatures.setdefault(sighash, [])
self.signatures[sighash].append(funcsig)
return self
- def get(self, sighash):
+ def write(self, path=None, sync=True):
+ """
+ Write signatures database as json to file
+
+ :param path: specify path otherwise update the file that was loaded with open()
+ :param sync: lock signature file, load contents and merge it into memcached sighash db, then save it
+ :return: self
+ """
+ path = path or self.signatures_file
+ self.signatures_file_lock = SimpleFileLock(path) # lock file to prevent concurrency issues
+ self.signatures_file_lock.aquire() # try to aquire it within the next 10s
+
+ if sync and os.path.exists(path):
+ # reload and save if file exists
+ with open(path, 'r') as f:
+ sigs = json.load(f)
+
+ sigs.update(self.signatures) # reload file and merge cached sigs into what we load from file
+ self.signatures = sigs
+
+ with open(path, 'w') as f:
+ json.dump(self.signatures, f)
+
+ self.signatures_file_lock.release()
+ return self
+
+ def get(self, sighash, timeout=2):
"""
get a function signature for a sighash
1) try local cache
- 2) try online lookup
- :param sighash:
- :return: list of function signatures
- """
- if not self.signatures.get(sighash) and self.enable_online_lookup:
- funcsigs = Signatures.lookup_online(sighash) # might return multiple sigs
- if funcsigs:
- # only store if we get at least one result
- self.signatures[sighash] = funcsigs
+ 2) try online lookup (if enabled; if not flagged as unavailable)
+ :param sighash: function signature hash as hexstr
+ :param timeout: online lookup timeout
+ :return: list of matching function signatures
+ """
+ if not sighash.startswith("0x"):
+ sighash = "0x%s" % sighash # normalize sighash format
+
+ if self.enable_online_lookup and not self.signatures.get(sighash) and sighash not in self.online_lookup_miss and time.time() > self.online_directory_unavailable_until:
+ # online lookup enabled, and signature not in cache, sighash was not a miss earlier, and online directory not down
+ logging.debug("Signatures: performing online lookup for sighash %r" % sighash)
+ try:
+ funcsigs = SignatureDb.lookup_online(sighash, timeout=timeout) # might return multiple sigs
+ if funcsigs:
+ # only store if we get at least one result
+ self.signatures[sighash] = funcsigs
+ else:
+ # miss
+ self.online_lookup_miss.add(sighash)
+ except FourByteDirectoryOnlineLookupError as fbdole:
+ self.online_directory_unavailable_until = time.time() + 2 * 60 # wait at least 2 mins to try again
+ logging.warning("online function signature lookup not available. will not try to lookup hash for the next 2 minutes. exception: %r" % fbdole)
return self.signatures[sighash] # raise keyerror
+ def __getitem__(self, item):
+ """
+ Provide dict interface Signatures()[sighash]
+ :param item: sighash
+ :return: list of matching signatures
+ """
+ return self.get(sighash=item)
+
+ def import_from_solidity_source(self, code):
+ """
+ Import Function Signatures from solidity source files
+ :param code: solidity source code
+ :return: self
+ """
+ self.signatures.update(SignatureDb.parse_function_signatures_from_solidity_source(code))
+ return self
@staticmethod
- def lookup_online(sighash):
+ def lookup_online(sighash, timeout=None, proxies=None):
"""
Lookup function signatures from 4byte.directory.
//tintinweb: the smart-contract-sanctuary project dumps contracts from etherscan.io and feeds them into
4bytes.directory.
https://github.com/tintinweb/smart-contract-sanctuary
- :param s: function signature as hexstr
- :return: a list of possible function signatures for this hash
+ :param sighash: function signature hash as hexstr
+ :param timeout: optional timeout for online lookup
+ :param proxies: optional proxy servers for online lookup
+ :return: a list of matching function signatures for this hash
"""
if not ethereum_input_decoder:
return None
- return list(ethereum_input_decoder.decoder.FourByteDirectory.lookup_signatures(sighash))
+ return list(ethereum_input_decoder.decoder.FourByteDirectory.lookup_signatures(sighash,
+ timeout=timeout,
+ proxies=proxies))
+
+ @staticmethod
+ def parse_function_signatures_from_solidity_source(code):
+ """
+ Parse solidity sourcecode for function signatures and return the signature hash and function signature
+ :param code: solidity source code
+ :return: dictionary {sighash: function_signature}
+ """
+ sigs = {}
+
+ funcs = re.findall(r'function[\s]+(.*?\))', code, re.DOTALL)
+ for f in funcs:
+ f = re.sub(r'[\n]', '', f)
+ m = re.search(r'^([A-Za-z0-9_]+)', f)
+
+ if m:
+ signature = m.group(1)
+ m = re.search(r'\((.*)\)', f)
+ _args = m.group(1).split(",")
+ types = []
+
+ for arg in _args:
+ _type = arg.lstrip().split(" ")[0]
+
+ if _type == "uint":
+ _type = "uint256"
+
+ types.append(_type)
+
+ typelist = ",".join(types)
+ signature += "(" + typelist + ")"
+ signature = re.sub(r'\s', '', signature)
+ sigs["0x" + utils.sha3(signature)[:4].hex()] = signature
+
+ logging.debug("Signatures: parse soldiity found %d signatures" % len(sigs))
+ return sigs
From 6851754059888d46bd8484a87fcfd82436df1ed3 Mon Sep 17 00:00:00 2001
From: tintinweb
Date: Fri, 6 Jul 2018 18:00:47 +0200
Subject: [PATCH 52/62] remove unnecessary comment (todo) reuse SimpleFileLock
instance if already set
Note: requests.[get|post|request](.., proxies=None) should be using the
default proxy settings (env)
Note: signature db path selection logic is currently not matching
mythril._init_config (but myhtril._init_mythril_dir)
---
mythril/support/signatures.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/mythril/support/signatures.py b/mythril/support/signatures.py
index af86abc4..e1582b68 100644
--- a/mythril/support/signatures.py
+++ b/mythril/support/signatures.py
@@ -99,7 +99,7 @@ class SignatureDb(object):
logging.debug("Signatures: file not found: %s" % path)
raise FileNotFoundError("Missing function signature file. Resolving of function names disabled.")
- self.signatures_file_lock = SimpleFileLock(self.signatures_file) # lock file to prevent concurrency issues
+ self.signatures_file_lock = self.signatures_file_lock or SimpleFileLock(self.signatures_file) # lock file to prevent concurrency issues
self.signatures_file_lock.aquire() # try to aquire it within the next 10s
with open(path, 'r') as f:
@@ -110,7 +110,7 @@ class SignatureDb(object):
# normalize it to {sighash:list(signatures,...)}
for sighash, funcsig in sigs.items():
if isinstance(funcsig, list):
- self.signatures = sigs # keep original todo: tintinweb - super hacky. make sure signatures.json is initially in correct format fixme
+ self.signatures = sigs
break # already normalized
self.signatures.setdefault(sighash, [])
self.signatures[sighash].append(funcsig)
@@ -126,7 +126,7 @@ class SignatureDb(object):
:return: self
"""
path = path or self.signatures_file
- self.signatures_file_lock = SimpleFileLock(path) # lock file to prevent concurrency issues
+ self.signatures_file_lock = self.signatures_file_lock or SimpleFileLock(path) # lock file to prevent concurrency issues
self.signatures_file_lock.aquire() # try to aquire it within the next 10s
if sync and os.path.exists(path):
From 9b5bd6de777e57d48af26f5a26d04f86e8690c93 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Sun, 8 Jul 2018 14:56:24 +0200
Subject: [PATCH 53/62] Use base 16
---
mythril/laser/ethereum/call.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mythril/laser/ethereum/call.py b/mythril/laser/ethereum/call.py
index 63d09837..aee2f30c 100644
--- a/mythril/laser/ethereum/call.py
+++ b/mythril/laser/ethereum/call.py
@@ -36,7 +36,7 @@ def get_call_parameters(global_state, dynamic_loader, with_value=False):
callee_account = None
call_data, call_data_type = get_call_data(global_state, meminstart, meminsz, False)
- if int(callee_address, 16) >= 5 or int(callee_address) == 0:
+ if int(callee_address, 16) >= 5 or int(callee_address, 16) == 0:
call_data, call_data_type = get_call_data(global_state, meminstart, meminsz)
callee_account = get_callee_account(global_state, callee_address, dynamic_loader)
From deb98df7c5d4bd6467f06073ddb0f545f15154c6 Mon Sep 17 00:00:00 2001
From: Nikhil Parasaram
Date: Sun, 8 Jul 2018 23:17:26 +0530
Subject: [PATCH 54/62] return a list for blockhash function
---
mythril/laser/ethereum/instructions.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py
index a7d9521f..949de064 100644
--- a/mythril/laser/ethereum/instructions.py
+++ b/mythril/laser/ethereum/instructions.py
@@ -529,7 +529,7 @@ class Instruction:
logging.info("error accessing contract storage due to: " + str(e))
state.stack.append(BitVec("extcodesize_" + str(addr), 256))
return [global_state]
-
+
if code is None:
state.stack.append(0)
else:
@@ -555,7 +555,7 @@ class Instruction:
state = global_state.mstate
blocknumber = state.stack.pop()
state.stack.append(BitVec("blockhash_block_" + str(blocknumber), 256))
- return global_state
+ return [global_state]
@instruction
def coinbase_(self, global_state):
From ac818454ab9bee4b762c035103718e0e95ca39c3 Mon Sep 17 00:00:00 2001
From: Konrad Weiss
Date: Mon, 9 Jul 2018 08:48:58 +0200
Subject: [PATCH 55/62] Correcting the symetric variable formatting for
calldatacopy
---
mythril/laser/ethereum/instructions.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py
index 89844986..1fbce31f 100644
--- a/mythril/laser/ethereum/instructions.py
+++ b/mythril/laser/ethereum/instructions.py
@@ -385,20 +385,20 @@ class Instruction:
dstart_sym = False
try:
dstart = util.get_concrete_int(op1)
- dstart_sym = True
# FIXME: broad exception catch
except:
logging.debug("Unsupported symbolic calldata offset in CALLDATACOPY")
dstart = simplify(op1)
+ dstart_sym = True
size_sym = False
try:
size = util.get_concrete_int(op2)
- size_sym = True
# FIXME: broad exception catch
except:
logging.debug("Unsupported symbolic size in CALLDATACOPY")
size = simplify(op2)
+ size_sym = True
if dstart_sym or size_sym:
state.mem_extend(mstart, 1)
From f873d041ee459d78d16a560a3e6dceae1728c071 Mon Sep 17 00:00:00 2001
From: Konrad Weiss
Date: Tue, 10 Jul 2018 12:50:33 +0200
Subject: [PATCH 56/62] Revert "Merge branch 'master' of
https://github.com/LoCorVin/mythril into feature/reformatsymindices"
This reverts commit a8de6b1a55d1e2cf12ae5710b6096df1db94b8f5, reversing
changes made to ac818454ab9bee4b762c035103718e0e95ca39c3.
---
annotationWrapper.py | 69 --------
mythril/analysis/modules/build_traces.py | 94 -----------
mythril/analysis/modules/dummy.py | 41 -----
mythril/analysis/symbolic.py | 9 +-
mythril/ether/soliditycontract.py | 3 -
mythril/ether/util.py | 2 +-
mythril/mythril.py | 8 -
mythril/solidnotary/__init__.py | 0
mythril/solidnotary/abitypemapping.py | 0
mythril/solidnotary/annotation.py | 28 ---
mythril/solidnotary/calldata.py | 150 -----------------
mythril/solidnotary/solidnotary.py | 72 --------
mythril/solidnotary/transactiontrace.py | 206 -----------------------
mythril/solidnotary/z3utility.py | 19 ---
14 files changed, 3 insertions(+), 698 deletions(-)
delete mode 100644 annotationWrapper.py
delete mode 100644 mythril/analysis/modules/build_traces.py
delete mode 100644 mythril/analysis/modules/dummy.py
delete mode 100644 mythril/solidnotary/__init__.py
delete mode 100644 mythril/solidnotary/abitypemapping.py
delete mode 100644 mythril/solidnotary/annotation.py
delete mode 100644 mythril/solidnotary/calldata.py
delete mode 100644 mythril/solidnotary/solidnotary.py
delete mode 100644 mythril/solidnotary/transactiontrace.py
delete mode 100644 mythril/solidnotary/z3utility.py
diff --git a/annotationWrapper.py b/annotationWrapper.py
deleted file mode 100644
index 02337e84..00000000
--- a/annotationWrapper.py
+++ /dev/null
@@ -1,69 +0,0 @@
-"""
- Parses the files for annotations to extract the information and do some transformations on the code.
- On return the Annotation information is used to change mythrils output regarding the changes code pieces
-
-"""
-
-from glob import glob
-import re, sys
-import json
-
-newlines = ["\r\n", "\r", "\n"]
-
-def find_all(a_str, sub):
- start = 0
- while True:
- start = a_str.find(sub, start)
- if start == -1:
- return
- yield start
- start += len(sub)
-
-def count_elements(source, elements):
- ret = 0
- for element in elements:
- ret += source.count(element)
- return ret
-
-
-def replace_index(text, toReplace, replacement, index):
- return text[:index] + replacement + text[(index + len(toReplace)):]
-
-"""
- Here it might be better to split annotations into the containing constraint an the prefix and sufix
-"""
-def parse_annotation_info(filedata):
- annotations = []
- for inv in re.findall(r'//invariant\(([^\)]+)\)(\r\n|\r|\n)', filedata):
- match_inv = "//invariant(" + inv[0] + ")"
- for pos in find_all(filedata, match_inv + inv[1]):
- line = count_elements(filedata[:pos], newlines) + 1
- col = pos - max(map(lambda x: filedata[:pos].rfind(x), newlines))
- annotations.append((pos, line, col, '//invariant(', inv[0], ")", inv[1]))
- return set(annotations)
-
-
-def read_write_file(filename):
- with open(filename, 'r') as file :
- filedata = file.read()
-
- annotations = parse_annotation_info(filedata)
-
- annotations = sorted(list(annotations), key=lambda x: x[0], reverse=True)
- for annotation in annotations:
- filedata = replace_index(filedata, annotation[3] + annotation[4] + annotation[5] + annotation[6], "assert("
- + annotation[4] + ");" + annotation[6], annotation[0])
- # Replace the target string
- # filedata = filedata.replace('@ensure', '@invariant')
- # filedata = filedata.replace('@invariant', '@ensure')
-
- with open(filename, 'w') as file:
- file.write(filedata)
- return annotations
-
-annot_map = {}
-
-for sol_file in glob("./*.sol"):
- annot_map[sol_file] = read_write_file(sol_file)
-json.dump(annot_map, sys.stdout)
-print("#end annotations#")
diff --git a/mythril/analysis/modules/build_traces.py b/mythril/analysis/modules/build_traces.py
deleted file mode 100644
index 76519410..00000000
--- a/mythril/analysis/modules/build_traces.py
+++ /dev/null
@@ -1,94 +0,0 @@
-from mythril.analysis.report import Issue
-from mythril.solidnotary.transactiontrace import TransactionTrace
-from mythril.disassembler.disassembly import Disassembly
-from laser.ethereum.svm import GlobalState, Account, Environment, MachineState, CalldataType
-from z3 import BitVec
-from mythril.analysis.symbolic import SymExecWrapper
-from mythril.solidnotary.solidnotary import get_transaction_traces, get_construction_traces
-from mythril.solidnotary.z3utility import are_satisfiable
-import logging
-from mythril.solidnotary.calldata import get_minimal_constructor_param_encoding_len, abi_json_to_abi
-
-
-'''
- Build execution traces from the statespace
-'''
-
-def print_obj(obj):
- print()
- print(type(obj))
- print(obj)
- print(dir(obj))
- print(obj.decl())
- print(obj.params())
- print(obj.children())
- print()
-
-def get_constr_glbstate(contract, address):
-
- mstate = MachineState(gas=10000000)
-
- minimal_const_byte_len = get_minimal_constructor_param_encoding_len(abi_json_to_abi(contract.abi))
-
- # better would be to append symbolic params to the bytecode such that the codecopy instruction that copies the
- # params into memory takes care of placing them onto the memory with the respective size.
- for i in range(int(minimal_const_byte_len / 32)):
- mstate.mem_extend(128 + 32 * i, 32)
- mstate.memory.insert(128 + 32 * i, BitVec('calldata_' + contract.name + '_' + str(i * 32), 256))
-
- # Todo Replace pure placement of enough symbolic 32 Byte-words with placement of symbolic variables that contain
- # the name of the solidity variables
-
- accounts = {address: Account(address, contract.disassembly, contract_name=contract.name)}
-
- environment = Environment(
- accounts[address],
- BitVec("caller", 256),
- [],
- BitVec("gasprice", 256),
- BitVec("callvalue", 256),
- BitVec("origin", 256),
- calldata_type=CalldataType.SYMBOLIC,
- )
-
- # Todo find source for account info, maybe the std statespace?
-
- return GlobalState(accounts, environment, mstate)
-
-
-def execute(statespace):
-
- logging.debug("Executing module: Transaction End")
-
- constructor_trace = {}
-
- if hasattr(statespace, "sym_constr"):
- sym_exe_tuple = statespace.sym_constr
- glbstate = get_constr_glbstate(sym_exe_tuple[0], sym_exe_tuple[1])
- sym_exe_tuple = statespace.sym_constr + (glbstate,)
- constr_statespace = SymExecWrapper(*sym_exe_tuple)
- constructor_trace = get_construction_traces(constr_statespace) # Todo the traces here should not contain references to storages anymore
- for t in constructor_trace:
- t.pp_trace()
-
- traces = get_transaction_traces(statespace)
- for trace in constructor_trace:
- comp_trace_lvls = trace.apply_up_to_trace_levels(traces, 3)
- for trace_lvl in comp_trace_lvls:
- for t in trace_lvl:
- t.pp_trace()
-
- # for trace in traces:
- # trace.pp_trace()
-
- #print("==== Second level traces ====")
- #for trace in traces:
- # comp_trace_lvls = trace.apply_up_to_trace_levels(traces, 1)
- #for trace_lvl in range(len(comp_trace_lvls)):
- # print("\nTrace level: " + str(trace_lvl))
- #for comp_trace in comp_trace_lvls[trace_lvl]:
- # print(comp_trace.storage)
- # for k, s in comp_trace.storage.items():
- # print_obj(s)
-
- return []
diff --git a/mythril/analysis/modules/dummy.py b/mythril/analysis/modules/dummy.py
deleted file mode 100644
index 44b0879f..00000000
--- a/mythril/analysis/modules/dummy.py
+++ /dev/null
@@ -1,41 +0,0 @@
-from mythril.analysis.report import Issue
-import logging
-from z3 import *
-from mythril.solidnotary.z3utility import simplify_constraints, are_satisfiable
-
-
-'''
- To print content of the statespace after it was build.
-'''
-
-def print_obj(obj):
- print()
- print(obj)
- print(type(obj))
- print(dir(obj))
- print()
-
-
-def execute(statespace):
-
- logging.debug("Executing module: Transaction End")
-
- issues = []
-
-# for k in statespace.nodes:
-# node = statespace.nodes[k]
-
-# for state in node.states:
-
-# instruction = state.get_current_instruction()
-
-# if(instruction['opcode'] == "STOP"):
-# print()
- #print(state.environment.active_account.storage)
- # print(state.mstate.constraints)
- #simpl_const = simplify_constraints(state.mstate.constraints)
- #print(simpl_const)
- #print(are_satisfiable(simpl_const))
- # print("opc: {}, add: {} {}".format(instruction['opcode'], instruction['address'], instruction['argument'] if 'argument' in instruction else ""))
-
- return issues
diff --git a/mythril/analysis/symbolic.py b/mythril/analysis/symbolic.py
index 975c52bf..5d47c356 100644
--- a/mythril/analysis/symbolic.py
+++ b/mythril/analysis/symbolic.py
@@ -11,7 +11,7 @@ class SymExecWrapper:
Wrapper class for the LASER Symbolic virtual machine. Symbolically executes the code and does a bit of pre-analysis for convenience.
'''
- def __init__(self, contract, address, dynloader=None, max_depth=12, gblState=None):
+ def __init__(self, contract, address, dynloader=None, max_depth=12):
account = svm.Account(address, contract.disassembly, contract_name=contract.name)
@@ -19,12 +19,7 @@ class SymExecWrapper:
self.laser = svm.LaserEVM(self.accounts, dynamic_loader=dynloader, max_depth=max_depth)
- if not (gblState is None):
- # Adding the ability to specify a custom global state, e.g. machine configuration from outside
- node = self.laser._sym_exec(gblState)
- self.laser.nodes[node.uid] = node
- else:
- self.laser.sym_exec(address)
+ self.laser.sym_exec(address)
self.nodes = self.laser.nodes
self.edges = self.laser.edges
diff --git a/mythril/ether/soliditycontract.py b/mythril/ether/soliditycontract.py
index 95b863b5..919b3d30 100644
--- a/mythril/ether/soliditycontract.py
+++ b/mythril/ether/soliditycontract.py
@@ -51,7 +51,6 @@ class SolidityContract(ETHContract):
if filename == input_file and name == _name:
name = name
code = contract['bin-runtime']
- abi = contract['abi']
creation_code = contract['bin']
srcmap = contract['srcmap-runtime'].split(";")
has_contract = True
@@ -66,7 +65,6 @@ class SolidityContract(ETHContract):
if filename == input_file and len(contract['bin-runtime']):
name = name
code = contract['bin-runtime']
- abi = contract['abi']
creation_code = contract['bin']
srcmap = contract['srcmap-runtime'].split(";")
has_contract = True
@@ -91,7 +89,6 @@ class SolidityContract(ETHContract):
lineno = self.solidity_files[idx].data[0:offset].count('\n') + 1
self.mappings.append(SourceMapping(idx, offset, length, lineno))
- self.abi = abi
super().__init__(code, creation_code, name=name)
diff --git a/mythril/ether/util.py b/mythril/ether/util.py
index 467c37df..e01cae28 100644
--- a/mythril/ether/util.py
+++ b/mythril/ether/util.py
@@ -18,7 +18,7 @@ def safe_decode(hex_encoded_string):
def get_solc_json(file, solc_binary="solc", solc_args=None):
- cmd = [solc_binary, "--combined-json", "bin,bin-runtime,srcmap-runtime,abi", '--allow-paths', "."]
+ cmd = [solc_binary, "--combined-json", "bin,bin-runtime,srcmap-runtime", '--allow-paths', "."]
if solc_args:
cmd.extend(solc_args.split(" "))
diff --git a/mythril/mythril.py b/mythril/mythril.py
index e2bb6c37..b63cc137 100644
--- a/mythril/mythril.py
+++ b/mythril/mythril.py
@@ -16,8 +16,6 @@ from solc.exceptions import SolcError
import solc
from configparser import ConfigParser
import platform
-from copy import deepcopy
-from mythril.disassembler.disassembly import Disassembly
from mythril.ether import util
from mythril.ether.ethcontract import ETHContract
@@ -344,12 +342,6 @@ class Mythril(object):
dynloader=DynLoader(self.eth) if self.dynld else None,
max_depth=max_depth)
-
- contr_to_const = deepcopy(contract)
- contr_to_const.disassembly = Disassembly(contr_to_const.creation_code)
- contr_to_const.code = contr_to_const.creation_code
- sym.sym_constr = (contr_to_const, address, DynLoader(self.eth) if self.dynld else None, max_depth)
-
issues = fire_lasers(sym, modules)
if type(contract) == SolidityContract:
diff --git a/mythril/solidnotary/__init__.py b/mythril/solidnotary/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/mythril/solidnotary/abitypemapping.py b/mythril/solidnotary/abitypemapping.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/mythril/solidnotary/annotation.py b/mythril/solidnotary/annotation.py
deleted file mode 100644
index cbf95ce1..00000000
--- a/mythril/solidnotary/annotation.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from re import search
-
-class Annotation:
-
- def __init__(self, annstring, lineno, fileoffset):
- self.annstring = annstring
-
- annotation = search(r'@(?P[^\{\}]*)(\{(?P.*)\})?', annstring)
- if not annotation:
- raise SyntaxError("{} is not a correct annotation".format(annstring))
-
- self.aname = annotation['aname']
- self.acontent = annotation['acontent']
- self.lineno = lineno
- self.length = len(annstring)
- self.fileoffset = fileoffset
-
-class ContractAnnotation(Annotation):
- pass
-
-class MemberAnnotation(Annotation):
- pass
-
-class InlineAnnotation(Annotation):
- pass
-
-class ContractAnnotation(Annotation):
- pass
diff --git a/mythril/solidnotary/calldata.py b/mythril/solidnotary/calldata.py
deleted file mode 100644
index 27891271..00000000
--- a/mythril/solidnotary/calldata.py
+++ /dev/null
@@ -1,150 +0,0 @@
-from re import search
-from mythril.exceptions import CompilerError
-from subprocess import Popen, PIPE
-import json
-import sys
-
-class CalldataMap:
-
- def __init__(self, abi, solc_v):
- pass
-
- def __init__(self, solidity_file, solc_v):
- pass
-
-def get_minimal_param_encoding_len(abi_inputs):
- len = 0
- return len
-
-def get_minimal_byte_enc_len(abi_obj):
- if type(abi_obj) == list:
- return sum([head_byte_length_min(t) for t in abi_obj]) + sum([tail_byte_length_min(t) for t in abi_obj])
- if type(abi_obj) == str:
- stype = abi_obj
- else:
- stype = abi_obj['type']
- if stype == 'tuple':
- return get_minimal_byte_enc_len(abi_obj['components'])
- try:
- match = search(r'(?P
.*)\[(?P[0-9]+)\]', stype)
- pre = match['pre']
- post = match['post']
- return int(post) * get_minimal_byte_enc_len(pre)
- except (KeyError, TypeError) as e:
- pass
- if stype.endswith("[]"):
- return 32
-
- if stype == "string":
- return 32
- elif stype == "bytes":
- return 32 # 2 was the smallest observed value, remix did not allow specification of zero size bytes
- elif [stype.startswith(prefix_type) for prefix_type in ["int", "uint", "address", "bool", "fixed", "ufixed", "bytes"]]:
- return 32
-
-def head_byte_length_min(abi_obj):
- if is_dynamic(abi_obj):
- return 32
- else:
- return get_minimal_byte_enc_len(abi_obj)
-
-
-def tail_byte_length_min(abi_obj):
- if is_dynamic(abi_obj):
- return get_minimal_byte_enc_len(abi_obj)
- else:
- return 0
-
-def get_minimal_wsize(abi_obj):
- stype = abi_obj['type']
- if type(stype) == list:
- return sum(list(map(lambda a: get_minimal_wsize(a), stype)))
- if stype in ["bytes", "string"] or stype.endswith("[]"):
- return True
- if stype == 'tuple':
- return True in [is_dynamic(elem) for elem in abi_obj['components']]
- try:
- match = search(r'(?P
.*)(?P\[[0-9]+\])', stype)
- pre = match['pre']
- # post = match['post']
- return is_dynamic(pre)
- except (KeyError | TypeError):
- pass
- return False
-
-
-def get_minimal_constructor_param_encoding_len(abi):
- for spec in abi:
- try:
- if spec['type'] == 'constructor':
- con_inputs = spec['inputs']
- return get_minimal_byte_enc_len(con_inputs)
- except KeyError:
- print("ABI does not contain inputs for constructor")
- return -1
-
-def get_minimal_constr_param_byte_length(filename, contract_name=None):
- abi_decoded = get_solc_abi_json(filename)
- return get_minimal_constructor_param_encoding_len(abi_decoded)
-
-def is_dynamic(abi_obj):
- if type(abi_obj) == list:
- return True in list(map(lambda a: is_dynamic(a), abi_obj))
- if type(abi_obj) == str:
- stype = abi_obj
- else:
- stype = abi_obj['type']
- if stype in ["bytes", "string"] or stype.endswith("[]"):
- return True
- if stype == 'tuple':
- return True in [is_dynamic(elem) for elem in abi_obj['components']]
- try:
- match = search(r'(?P
.*)(?P\[[0-9]+\])', stype)
- pre = match['pre']
- # post = match['post']
- return is_dynamic(pre)
- except (KeyError, TypeError) as e:
- pass
- return False
-
-def get_solc_abi_json(file, solc_binary="solc", solc_args=None):
-
- cmd = [solc_binary, "--abi", '--allow-paths', "."]
-
- if solc_args:
- cmd.extend(solc_args.split(" "))
-
- cmd.append(file)
-
- try:
- p = Popen(cmd, stdout=PIPE, stderr=PIPE)
-
- stdout, stderr = p.communicate()
- ret = p.returncode
-
- if ret != 0:
- raise CompilerError("Solc experienced a fatal error (code %d).\n\n%s" % (ret, stderr.decode('UTF-8')))
- except FileNotFoundError:
- raise CompilerError("Compiler not found. Make sure that solc is installed and in PATH, or set the SOLC environment variable.")
-
- out = stdout.decode("UTF-8")
-
- if not len(out):
- raise CompilerError("Compilation failed.")
-
- out = out[out.index("["):]
-
- print(out)
-
- return json.loads(out)
-
-def abi_json_to_abi(abi_json):
- return json.loads(abi_json)
-
-
-if __name__ == "__main__":
- if len(sys.argv) > 1:
- print("Size:")
- print(get_minimal_constr_param_byte_length(sys.argv[1]))
- else:
- print("Error: No file specified")
diff --git a/mythril/solidnotary/solidnotary.py b/mythril/solidnotary/solidnotary.py
deleted file mode 100644
index 3a3091d2..00000000
--- a/mythril/solidnotary/solidnotary.py
+++ /dev/null
@@ -1,72 +0,0 @@
-import logging
-from mythril.solidnotary.transactiontrace import TransactionTrace
-from mythril.solidnotary.z3utility import are_satisfiable
-from laser.ethereum.svm import Environment, GlobalState, CalldataType
-from z3 import BitVec, simplify, is_false, is_bool, is_true, Solver, sat
-from copy import deepcopy
-
-
-class SolidNotary:
-
- def __init__(self):
- # Todo Parse Annotations and store them in an additional structure
- # Todo receive a list of files or a file, these are modified for the analysis
- pass
-
- def notarize(self):
- # Todo Instantiate an instance of Mythril, analyze and print the result
- # Todo Find how they are storing results
- pass
-
-def get_transaction_traces(statespace):
- print("get_transaction_traces")
-
- traces = []
-
- for k in statespace.nodes:
- node = statespace.nodes[k]
- for state in node.states:
- instruction = state.get_current_instruction()
- # print("op: " + str(instruction['opcode']) + ((" " + instruction['argument']) if instruction['opcode'].startswith("PUSH") else "") + " stack: " + str(state.mstate.stack).replace("\n", "")+ " mem: " + str(state.mstate.memory).replace("\n", ""))
- if instruction['opcode'] == "STOP":
- if are_satisfiable(state.mstate.constraints):
- traces.append(TransactionTrace(state.environment.active_account.storage, state.mstate.constraints))
- return traces
-
-def get_construction_traces(statespace):
- print("get_constructor_traces")
-
- traces = []
-
- for k in statespace.nodes:
- node = statespace.nodes[k]
- for state in node.states:
- instruction = state.get_current_instruction()
-
- # print("op: " + str(instruction['opcode']) + ((" " + instruction['argument']) if instruction['opcode'].startswith("PUSH") else "") + " stack: " + str(state.mstate.stack).replace("\n", "")+ " mem: " + str(state.mstate.memory).replace("\n", ""))
- if instruction['opcode'] == "RETURN":
- if are_satisfiable(state.mstate.constraints):
- traces.append(TransactionTrace(state.environment.active_account.storage, state.mstate.constraints))
- return traces
-
-def get_t_indexed_environment(active_account, index):
-
- # Initialize the execution environment
-
- environment = Environment(
- active_account,
- BitVec("caller_"+str(index), 256),
- [],
- BitVec("gasprice_"+str(index), 256),
- BitVec("callvalue_"+str(index), 256),
- BitVec("origin_"+str(index), 256),
- calldata_type=CalldataType.SYMBOLIC,
- )
-
- return environment
-
-def get_t_indexed_globstate(active_account, index):
- environment = get_t_indexed_environment(active_account, index)
- # Todo is this just some set of preset accounts? How should we deal with it
- return GlobalState(self.accounts, environment)
-
diff --git a/mythril/solidnotary/transactiontrace.py b/mythril/solidnotary/transactiontrace.py
deleted file mode 100644
index 44bcaca9..00000000
--- a/mythril/solidnotary/transactiontrace.py
+++ /dev/null
@@ -1,206 +0,0 @@
-from z3 import *
-from copy import deepcopy
-import re
-from mythril.solidnotary.z3utility import are_satisfiable, simplify_constraints
-
-"""
- Returns whether or the specified symbolic string stands for a data value that can be different from transaction to
- transaction without the need of an intermediate call to the contract (e.g. a transaction params, blocknumber, ...)
-"""
-
-
-def is_t_variable(var):
- var = str(var)
- if (var.startswith("caller")
- or var.startswith("gasprice")
- or var.startswith("callvalue")
- or var.startswith("origin")
- or var.startswith("calldata_")
- or var.startswith("calldatasize_")
- or var.startswith("balance_at")
- or var.startswith("KECCAC_mem_")
- or var.startswith("keccac_")
- or var.startswith("gasprice")
- or var.startswith("extcodesize")
- or var.startswith("returndatasize")
- # or var.startswith(var, "blockhash_block_") should not change between transactions
- or var.startswith("coinbase")
- or var.startswith("timestamp")
- or var.startswith("block_number")
- or var.startswith("block_difficulty")
- or var.startswith("block_gaslimit")
- or var.startswith("mem_")
- or var.startswith("msize")
- or var.startswith("gas")
- or var.startswith("retval_")
- or var.startswith("keccac_")):
- return True
- else:
- return False
-
-# Todo constructor mit den intentet initvalues versorgen
-
-
-def filter_for_t_variable_data(sym_vars):
- return list(filter(lambda x: is_t_variable(x), sym_vars))
-
-class TransactionTrace:
-
- def __init__(self, storage, constraints, lvl=1):
- self.storage = deepcopy(storage) # Todo give all non storage symbolic values that can be different every transaction the number one
- self.constraints = constraints # Todo eliminate all constraints that are not regarding the beginning of the transaction may not be necessary
- # eliminate all constraints that only contain names not in the set of names from storage
- self.constraints = simplify_constraints(self.constraints) # Todo simplification of the sum of constraints
- self.tran_constraints = deepcopy(self.constraints) # Todo minimize them if they do not involve outside symb variables
- self.lvl = lvl
- self.sym_names = self.extract_sym_names_from_storage()
- self.sym_names.extend(self.extract_sym_names_from_constraints())
- if lvl == 1:
- self.set_transaction_idx()
-
- # Todo the constraints of a trace are probably also important here and have to be somehow aggregated
- # Todo Identifiy addional trace information such as blocknumber and more
-
- def __str__(self):
- return str(self.as_dict())
-
- def as_dict(self):
-
- return {'lvl': self.lvl, 'storage': str(self.storage), 'constraints': str(self.constraints)}
-
- def pp_trace(self):
- print()
- print("Trace lvl: {}".format(self.lvl))
- print("Storage: {}".format({k: str(v).replace("\n", " ") for k, v in self.storage.items()}))
- print("Constraints: {}".format(list(map(lambda x: str(x).replace("\n", " "), self.constraints))))
- print()
-
-
- def add_transaction_idx(self, offset):
- new_names = []
- for name in self.sym_names:
- matched_name = re.search(r't([0-9]+)(_.*)', name)
- num = int(matched_name.group(1)) + offset
- new_names.append("t" + str(num) + matched_name.group(2))
- repl_tup = list(zip(self.sym_names, new_names))
-
- self.substitute_bv_names(repl_tup)
-
- self.sym_names = new_names
-
- def set_transaction_idx(self):
- repl_tup = []
- new_sym_names = []
- for name in self.sym_names:
- repl_tup.append((name, "t1_" + name))
- new_sym_names.append("t1_" + name)
- self.sym_names = new_sym_names
- self.substitute_bv_names(repl_tup)
-
- def substitute_bv_names(self, subs_tuple):
- subs_tuples = list(map(lambda name_t: (BitVec(name_t[0], 256), BitVec(name_t[1], 256)), subs_tuple))
- for s_num, slot in self.storage.items():
- self.storage[s_num] = substitute(slot, subs_tuples)
- for c_idx in range(len(self.constraints)):
- self.constraints[c_idx] = substitute(self.constraints[c_idx], subs_tuples)
-
- def extract_sym_names(self, obj):
- if (not hasattr(obj, 'children') or len(obj.children()) == 0) and hasattr(obj, 'decl') :
- return [str(obj.decl())]
- else:
- sym_vars = []
- for c in obj.children():
- sym_vars.extend(self.extract_sym_names(c))
- return sym_vars
-
- def extract_sym_names_from_constraints(self):
- sym_names = []
- for k,v in self.storage.items():
- sym_names.extend(self.extract_sym_names(v))
- return filter_for_t_variable_data(sym_names)
-
- def extract_sym_names_from_storage(self):
- sym_names = []
- for v in self.constraints:
- sym_names.extend(self.extract_sym_names(v))
- return filter_for_t_variable_data(sym_names) # Todo Check whether here it is the right choice too, to filter ...
-
- """
- Either do only deep checing here and use the proper trace or storage_slot reduction in the apply function. Or do
- both here.
- """
-
- def deep_equals(trace_lvl1, trace_lvl2):
- return set(trace_lvl1) == set(trace_lvl2) # Todo Impelement an ACTUAL deep comparison
-
- def simplify_storage(self):
- for k,v in self.storage.items():
- # Todo explore the arguments of this storage simplification in z3 to find ways to further simplify and to
- # sort this expressions for equality comparison
- self.storage[k] = simplify(v)
-
- """
- Applies the new trace tt on a possibly even changed trace self.
- """
- def apply_trace(self, tt):
- if tt is None:
- return self
- new_trace = deepcopy(tt)
- new_trace.add_transaction_idx(self.lvl)
- subs_map = list(map(lambda x: (BitVec("storage_" + str(x[0]), 256), x[1]), self.storage.items()))
- for k,v in new_trace.storage.items():
- new_trace.storage[k] = substitute(v, subs_map)
- for c_idx in range(len(new_trace.constraints)):
- new_trace.constraints[c_idx] = substitute(new_trace.constraints[c_idx], subs_map)
- new_trace.lvl += self.lvl
- new_trace.sym_names.extend(deepcopy(self.sym_names))
- # self can be omitted (e.g. when related storage locations were overwritten)
- new_trace.simplify_storage()
- new_trace.constraints = simplify_constraints(new_trace.constraints)
- # Simplify constraints in there sum to eliminate subconstraints
- if are_satisfiable(new_trace.constraints):
- return new_trace
- else:
- return None
-
- def apply_traces_parallel(self, traces):
- combined_traces = []
- for trace in traces:
- combined_traces.append(self.apply_trace(trace))
- return list(filter(lambda t: not t is None, combined_traces))
-
- def apply_exact_trace_levels(self, traces, depth):
- # Todo maybe some faster trace build not building one level at a time to e.g.
- # Todo reach level 17 but build 2, then 4, then 8 and then 16 then 17
- trace_lvl_n = [self]
- for i in range(depth):
- trace_lvl_np1 = []
- for trace in trace_lvl_n:
- trace_lvl_np1.extend(trace.apply_traces_parallel(traces))
- if TransactionTrace.deep_equals(trace_lvl_np1, trace_lvl_n): # Fixpoint detected, function needs to ignore lists, dicts and objects.
- return trace_lvl_n
- trace_lvl_n = trace_lvl_np1
- return trace_lvl_n
-
- def apply_up_to_trace_levels(self, traces, depth):
- traces_up_to = [[self]] # elements are trace_levels
- for i in range(depth):
- trace_lvl_np1 = []
- for trace in traces_up_to[-1]:
- trace_lvl_np1.extend(trace.apply_traces_parallel(traces))
- for trace_lvl_i in traces_up_to:
- # the following might be faster to check when using a content representing hash
- if TransactionTrace.deep_equals(trace_lvl_np1, trace_lvl_i): # cycle in the traces of trace chains detected: levels
- # while repeat themselves, function needs to ignore lists, dicts and objects.
- return traces_up_to
- traces_up_to.append(trace_lvl_np1)
- return traces_up_to
-
- # Todo Maybe implement a function that checks whether two traces are combinable before creating objekts, adv. in
- # case they are not the object creation doe not have to be done. Investigate whether a suicide trace completely
- # stopes the contract from being executable. In that case a suicided transaction also is not combinable with
- # successive transactions.
-
- # Todo write a function that allows to specify a function/invocable to explore the tracechain space in DFS manner
-
-
diff --git a/mythril/solidnotary/z3utility.py b/mythril/solidnotary/z3utility.py
deleted file mode 100644
index 50b80bac..00000000
--- a/mythril/solidnotary/z3utility.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from z3 import Solver, sat, simplify, is_bool, is_true, is_false
-from copy import deepcopy
-
-def are_satisfiable(constraints):
- s = Solver()
- for c in constraints:
- s.add(c)
- return s.check() == sat
-
-def simplify_constraints(constraints): # Todo simplification of the sum of constraints
- simp_const = []
- for const in constraints:
- simp_const.append(simplify(const))
- simp_const = list(filter(lambda c: not is_bool(c) or not is_true(c), simp_const))
- falses = list(filter(lambda c: is_bool(c) and is_false(c), simp_const))
- if len(falses) > 0:
- return [deepcopy(falses[0])]
-
- return simp_const
From b30e70235c5004cc7490d1a570d0ea9c63b58e03 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Tue, 10 Jul 2018 17:03:47 +0200
Subject: [PATCH 57/62] Implement coverage measurement
---
mythril/laser/ethereum/svm.py | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/mythril/laser/ethereum/svm.py b/mythril/laser/ethereum/svm.py
index 1ceb3740..943065ba 100644
--- a/mythril/laser/ethereum/svm.py
+++ b/mythril/laser/ethereum/svm.py
@@ -4,6 +4,7 @@ from mythril.laser.ethereum.state import GlobalState, Environment, CalldataType,
from mythril.laser.ethereum.instructions import Instruction
from mythril.laser.ethereum.cfg import NodeFlags, Node, Edge, JumpType
from mythril.laser.ethereum.strategy.basic import DepthFirstSearchStrategy
+from functools import reduce
TT256 = 2 ** 256
TT256M1 = 2 ** 256 - 1
@@ -23,6 +24,7 @@ class LaserEVM:
Laser EVM class
"""
def __init__(self, accounts, dynamic_loader=None, max_depth=22):
+ self.instructions_covered = []
self.accounts = accounts
self.nodes = {}
@@ -51,7 +53,8 @@ class LaserEVM:
calldata_type=CalldataType.SYMBOLIC,
)
- # TODO: contact name fix
+ self.instructions_covered = [False for _ in environment.code.instruction_list]
+
initial_node = Node(environment.active_account.contract_name)
self.nodes[initial_node.uid] = initial_node
@@ -63,6 +66,7 @@ class LaserEVM:
self._sym_exec()
logging.info("Execution complete")
+ logging.info("Achieved {0:.3g}% coverage".format(self.coverage))
logging.info("%d nodes, %d edges, %d total states", len(self.nodes), len(self.edges), self.total_states)
def _sym_exec(self):
@@ -81,6 +85,7 @@ class LaserEVM:
def execute_state(self, global_state):
instructions = global_state.environment.code.instruction_list
op_code = instructions[global_state.mstate.pc]['opcode']
+ self.instructions_covered[global_state.mstate.pc] = True
return Instruction(op_code, self.dynamic_loader).evaluate(global_state), op_code
def manage_cfg(self, opcode, new_states):
@@ -130,3 +135,8 @@ class LaserEVM:
logging.info("- Entering function " + environment.active_account.contract_name + ":" + new_node.function_name)
new_node.function_name = environment.active_function_name
+
+ @property
+ def coverage(self):
+ return reduce(lambda sum, val: sum + 1 if val else sum, self.instructions_covered) / float(
+ len(self.instructions_covered)) * 100
From e1552435e80737f5d592f676126522ba314fe444 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Tue, 10 Jul 2018 17:42:27 +0200
Subject: [PATCH 58/62] Add timeout logging to solver
---
mythril/analysis/solver.py | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/mythril/analysis/solver.py b/mythril/analysis/solver.py
index 9e59f831..0f6703e6 100644
--- a/mythril/analysis/solver.py
+++ b/mythril/analysis/solver.py
@@ -1,6 +1,6 @@
-from z3 import Solver, simplify, sat
+from z3 import Solver, simplify, sat, unknown
from mythril.exceptions import UnsatError
-
+import logging
def get_model(constraints):
s = Solver()
@@ -8,13 +8,12 @@ def get_model(constraints):
for constraint in constraints:
s.add(constraint)
-
- if (s.check() == sat):
-
+ result = s.check()
+ if result == sat:
return s.model()
-
- else:
- raise UnsatError
+ elif result == unknown:
+ logging.info("Timeout encountered while solving expression using z3")
+ raise UnsatError
def pretty_print_model(model):
From aa0f6064d5a6882a1f14ec7d2751112bb5d1fdba Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Tue, 10 Jul 2018 19:17:29 +0200
Subject: [PATCH 59/62] Use sum_ vs sum
---
mythril/laser/ethereum/svm.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mythril/laser/ethereum/svm.py b/mythril/laser/ethereum/svm.py
index 943065ba..ace985d4 100644
--- a/mythril/laser/ethereum/svm.py
+++ b/mythril/laser/ethereum/svm.py
@@ -138,5 +138,5 @@ class LaserEVM:
@property
def coverage(self):
- return reduce(lambda sum, val: sum + 1 if val else sum, self.instructions_covered) / float(
+ return reduce(lambda sum_, val: sum_ + 1 if val else sum_, self.instructions_covered) / float(
len(self.instructions_covered)) * 100
From 390bd99b1754c9b8440e2220cd9adacd28ad408e Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Wed, 11 Jul 2018 10:53:00 +0200
Subject: [PATCH 60/62] Add contract to as dict
---
mythril/analysis/report.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mythril/analysis/report.py b/mythril/analysis/report.py
index 2e2d3425..2e2e04d5 100644
--- a/mythril/analysis/report.py
+++ b/mythril/analysis/report.py
@@ -22,7 +22,7 @@ class Issue:
@property
def as_dict(self):
- issue = {'title': self.title, 'description':self.description, 'function': self.function, 'type': self.type, 'address': self.address, 'debug': self.debug}
+ issue = {'title': self.title, 'contract': self.contract, 'description': self.description, 'function': self.function, 'type': self.type, 'address': self.address, 'debug': self.debug}
if self.filename and self.lineno:
issue['filename'] = self.filename
From b38ba4e6b9a88f04f549c6f1b991a3bec7c673a1 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Wed, 11 Jul 2018 11:13:15 +0200
Subject: [PATCH 61/62] Regenerate json to include contract name
---
tests/report_test.py | 2 +-
.../outputs_expected/calls.sol.o.json | 2 +-
.../outputs_expected/ether_send.sol.o.json | 23 +-------------
.../outputs_expected/exceptions.sol.o.json | 2 +-
.../kinds_of_calls.sol.o.json | 2 +-
.../outputs_expected/metacoin.sol.o.json | 15 +--------
.../multi_contracts.sol.o.json | 2 +-
.../outputs_expected/origin.sol.o.json | 2 +-
.../outputs_expected/overflow.sol.o.json | 31 +------------------
.../outputs_expected/returnvalue.sol.o.json | 2 +-
.../outputs_expected/suicide.sol.o.json | 2 +-
.../outputs_expected/underflow.sol.o.json | 31 +------------------
12 files changed, 12 insertions(+), 104 deletions(-)
diff --git a/tests/report_test.py b/tests/report_test.py
index 88d4c777..a3cd0f70 100644
--- a/tests/report_test.py
+++ b/tests/report_test.py
@@ -112,7 +112,7 @@ def _get_changed_files_json(report_builder, reports):
output_current = TESTDATA_OUTPUTS_CURRENT / (input_file.name + postfix)
output_current.write_text(report_builder(report))
- if not ordered(json.loads(output_expected.read_text())) == ordered(json.loads(output_current.read_text())):
+ if False and not ordered(json.loads(output_expected.read_text())) == ordered(json.loads(output_current.read_text())):
yield input_file
diff --git a/tests/testdata/outputs_expected/calls.sol.o.json b/tests/testdata/outputs_expected/calls.sol.o.json
index 3a93166f..5b7e39a9 100644
--- a/tests/testdata/outputs_expected/calls.sol.o.json
+++ b/tests/testdata/outputs_expected/calls.sol.o.json
@@ -1 +1 @@
-{"error": null, "issues": [{"address": 661, "debug": "", "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", "function": "_function_0x5a6814ec", "title": "Message call to external contract", "type": "Informational"}, {"address": 666, "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0x5a6814ec", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 779, "debug": "", "description": "This contract executes a message call to an address found at storage slot 1. This storage slot can be written to by calling the function `_function_0x2776b163`. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.", "function": "_function_0xd24b08cc", "title": "Message call to external contract", "type": "Warning"}, {"address": 779, "debug": "", "description": "A possible transaction order independence vulnerability exists in function _function_0xd24b08cc. The value or direction of the call statement is determined from a tainted storage location", "function": "_function_0xd24b08cc", "title": "Transaction order dependence", "type": "Warning"}, {"address": 784, "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xd24b08cc", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 858, "debug": "", "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", "function": "_function_0xe11f493e", "title": "Message call to external contract", "type": "Informational"}, {"address": 869, "debug": "", "description": "The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities.", "function": "_function_0xe11f493e", "title": "State change after external call", "type": "Warning"}, {"address": 871, "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xe11f493e", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 912, "debug": "", "description": "This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.", "function": "_function_0xe1d10f79", "title": "Message call to external contract", "type": "Warning"}, {"address": 918, "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xe1d10f79", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true}
\ No newline at end of file
+{"error": null, "issues": [{"address": 661, "contract": "Unknown", "debug": "", "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", "function": "_function_0x5a6814ec", "title": "Message call to external contract", "type": "Informational"}, {"address": 666, "contract": "Unknown", "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0x5a6814ec", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 779, "contract": "Unknown", "debug": "", "description": "This contract executes a message call to an address found at storage slot 1. This storage slot can be written to by calling the function `_function_0x2776b163`. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.", "function": "_function_0xd24b08cc", "title": "Message call to external contract", "type": "Warning"}, {"address": 779, "contract": "Unknown", "debug": "", "description": "A possible transaction order independence vulnerability exists in function _function_0xd24b08cc. The value or direction of the call statement is determined from a tainted storage location", "function": "_function_0xd24b08cc", "title": "Transaction order dependence", "type": "Warning"}, {"address": 784, "contract": "Unknown", "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xd24b08cc", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 858, "contract": "Unknown", "debug": "", "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", "function": "_function_0xe11f493e", "title": "Message call to external contract", "type": "Informational"}, {"address": 869, "contract": "Unknown", "debug": "", "description": "The contract account state is changed after an external call. Consider that the called contract could re-enter the function before this state change takes place. This can lead to business logic vulnerabilities.", "function": "_function_0xe11f493e", "title": "State change after external call", "type": "Warning"}, {"address": 871, "contract": "Unknown", "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xe11f493e", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 912, "contract": "Unknown", "debug": "", "description": "This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.", "function": "_function_0xe1d10f79", "title": "Message call to external contract", "type": "Warning"}, {"address": 918, "contract": "Unknown", "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xe1d10f79", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/ether_send.sol.o.json b/tests/testdata/outputs_expected/ether_send.sol.o.json
index 6d6caad0..d893749f 100644
--- a/tests/testdata/outputs_expected/ether_send.sol.o.json
+++ b/tests/testdata/outputs_expected/ether_send.sol.o.json
@@ -1,22 +1 @@
-{
- "success": true,
- "error": null,
- "issues": [
- {
- "title": "Ether send",
- "description": "In the function `withdrawfunds()` a non-zero amount of Ether is sent to msg.sender.\n\nThere is a check on storage index 1. This storage slot can be written to by calling the function `crowdfunding()`.",
- "function": "withdrawfunds()",
- "type": "Warning",
- "address": 722,
- "debug": ""
- },
- {
- "title": "Integer Overflow",
- "description": "A possible integer overflow exists in the function `invest()`.\nThe addition or multiplication may result in a value higher than the maximum representable integer.",
- "function": "invest()",
- "type": "Warning",
- "address": 883,
- "debug": ""
- }
- ]
-}
+{"error": null, "issues": [{"address": 722, "contract": "Unknown", "debug": "", "description": "In the function `withdrawfunds()` a non-zero amount of Ether is sent to msg.sender.\n\nThere is a check on storage index 1. This storage slot can be written to by calling the function `crowdfunding()`.", "function": "withdrawfunds()", "title": "Ether send", "type": "Warning"}, {"address": 883, "contract": "Unknown", "debug": "", "description": "A possible integer overflow exists in the function `invest()`.\nThe addition or multiplication may result in a value higher than the maximum representable integer.", "function": "invest()", "title": "Integer Overflow", "type": "Warning"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/exceptions.sol.o.json b/tests/testdata/outputs_expected/exceptions.sol.o.json
index 4434c91f..e923bb3a 100644
--- a/tests/testdata/outputs_expected/exceptions.sol.o.json
+++ b/tests/testdata/outputs_expected/exceptions.sol.o.json
@@ -1 +1 @@
-{"error": null, "issues": [{"address": 446, "debug": "", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ", "function": "_function_0x546455b5", "title": "Exception state", "type": "Informational"}, {"address": 484, "debug": "", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ", "function": "_function_0x92dd38ea", "title": "Exception state", "type": "Informational"}, {"address": 506, "debug": "", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ", "function": "_function_0xa08299f1", "title": "Exception state", "type": "Informational"}, {"address": 531, "debug": "", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ", "function": "_function_0xb34c3610", "title": "Exception state", "type": "Informational"}], "success": true}
\ No newline at end of file
+{"error": null, "issues": [{"address": 446, "contract": "Unknown", "debug": "", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ", "function": "_function_0x546455b5", "title": "Exception state", "type": "Informational"}, {"address": 484, "contract": "Unknown", "debug": "", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ", "function": "_function_0x92dd38ea", "title": "Exception state", "type": "Informational"}, {"address": 506, "contract": "Unknown", "debug": "", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ", "function": "_function_0xa08299f1", "title": "Exception state", "type": "Informational"}, {"address": 531, "contract": "Unknown", "debug": "", "description": "A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. ", "function": "_function_0xb34c3610", "title": "Exception state", "type": "Informational"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.json b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.json
index 747f1118..ccdf57c0 100644
--- a/tests/testdata/outputs_expected/kinds_of_calls.sol.o.json
+++ b/tests/testdata/outputs_expected/kinds_of_calls.sol.o.json
@@ -1 +1 @@
-{"error": null, "issues": [{"address": 626, "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0x141f32ff", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 857, "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0x9b58bc26", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 1038, "debug": "", "description": "This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.", "function": "_function_0xeea4c864", "title": "Message call to external contract", "type": "Warning"}, {"address": 1046, "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xeea4c864", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true}
\ No newline at end of file
+{"error": null, "issues": [{"address": 626, "contract": "Unknown", "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0x141f32ff", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 857, "contract": "Unknown", "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0x9b58bc26", "title": "Unchecked CALL return value", "type": "Informational"}, {"address": 1038, "contract": "Unknown", "debug": "", "description": "This contract executes a message call to an address provided as a function argument. Generally, it is not recommended to call user-supplied addresses using Solidity's call() construct. Note that attackers might leverage reentrancy attacks to exploit race conditions or manipulate this contract's state.", "function": "_function_0xeea4c864", "title": "Message call to external contract", "type": "Warning"}, {"address": 1046, "contract": "Unknown", "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xeea4c864", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/metacoin.sol.o.json b/tests/testdata/outputs_expected/metacoin.sol.o.json
index fd59d519..b0610b5f 100644
--- a/tests/testdata/outputs_expected/metacoin.sol.o.json
+++ b/tests/testdata/outputs_expected/metacoin.sol.o.json
@@ -1,14 +1 @@
-{
- "success": true,
- "error": null,
- "issues": [
- {
- "title": "Integer Overflow",
- "description": "A possible integer overflow exists in the function `sendToken(address,uint256)`.\nThe addition or multiplication may result in a value higher than the maximum representable integer.",
- "function": "sendToken(address,uint256)",
- "type": "Warning",
- "address": 498,
- "debug": ""
- }
- ]
-}
+{"error": null, "issues": [{"address": 498, "contract": "Unknown", "debug": "", "description": "A possible integer overflow exists in the function `sendToken(address,uint256)`.\nThe addition or multiplication may result in a value higher than the maximum representable integer.", "function": "sendToken(address,uint256)", "title": "Integer Overflow", "type": "Warning"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/multi_contracts.sol.o.json b/tests/testdata/outputs_expected/multi_contracts.sol.o.json
index ff019037..1d4a5e35 100644
--- a/tests/testdata/outputs_expected/multi_contracts.sol.o.json
+++ b/tests/testdata/outputs_expected/multi_contracts.sol.o.json
@@ -1 +1 @@
-{"error": null, "issues": [{"address": 142, "debug": "", "description": "In the function `_function_0x8a4068dd` a non-zero amount of Ether is sent to msg.sender.\nIt seems that this function can be called without restrictions.", "function": "_function_0x8a4068dd", "title": "Ether send", "type": "Warning"}], "success": true}
\ No newline at end of file
+{"error": null, "issues": [{"address": 142, "contract": "Unknown", "debug": "", "description": "In the function `_function_0x8a4068dd` a non-zero amount of Ether is sent to msg.sender.\nIt seems that this function can be called without restrictions.", "function": "_function_0x8a4068dd", "title": "Ether send", "type": "Warning"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/origin.sol.o.json b/tests/testdata/outputs_expected/origin.sol.o.json
index 2024d492..1ac2d554 100644
--- a/tests/testdata/outputs_expected/origin.sol.o.json
+++ b/tests/testdata/outputs_expected/origin.sol.o.json
@@ -1 +1 @@
-{"error": null, "issues": [{"address": 317, "debug": "", "description": "Function transferOwnership(address) retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.\nSee also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin", "function": "transferOwnership(address)", "title": "Use of tx.origin", "type": "Warning"}], "success": true}
\ No newline at end of file
+{"error": null, "issues": [{"address": 317, "contract": "Unknown", "debug": "", "description": "Function transferOwnership(address) retrieves the transaction origin (tx.origin) using the ORIGIN opcode. Use msg.sender instead.\nSee also: https://solidity.readthedocs.io/en/develop/security-considerations.html#tx-origin", "function": "transferOwnership(address)", "title": "Use of tx.origin", "type": "Warning"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/overflow.sol.o.json b/tests/testdata/outputs_expected/overflow.sol.o.json
index 8345944e..341e5b46 100644
--- a/tests/testdata/outputs_expected/overflow.sol.o.json
+++ b/tests/testdata/outputs_expected/overflow.sol.o.json
@@ -1,30 +1 @@
-{
- "success": true,
- "error": null,
- "issues": [
- {
- "title": "Integer Underflow",
- "description": "A possible integer underflow exists in the function `sendeth(address,uint256)`.\nThe subtraction may result in a value < 0.",
- "function": "sendeth(address,uint256)",
- "type": "Warning",
- "address": 649,
- "debug": ""
- },
- {
- "title": "Integer Overflow",
- "description": "A possible integer overflow exists in the function `sendeth(address,uint256)`.\nThe addition or multiplication may result in a value higher than the maximum representable integer.",
- "function": "sendeth(address,uint256)",
- "type": "Warning",
- "address": 725,
- "debug": ""
- },
- {
- "title": "Integer Underflow",
- "description": "A possible integer underflow exists in the function `sendeth(address,uint256)`.\nThe subtraction may result in a value < 0.",
- "function": "sendeth(address,uint256)",
- "type": "Warning",
- "address": 567,
- "debug": ""
- }
- ]
-}
+{"error": null, "issues": [{"address": 567, "contract": "Unknown", "debug": "", "description": "A possible integer underflow exists in the function `sendeth(address,uint256)`.\nThe subtraction may result in a value < 0.", "function": "sendeth(address,uint256)", "title": "Integer Underflow", "type": "Warning"}, {"address": 649, "contract": "Unknown", "debug": "", "description": "A possible integer underflow exists in the function `sendeth(address,uint256)`.\nThe subtraction may result in a value < 0.", "function": "sendeth(address,uint256)", "title": "Integer Underflow", "type": "Warning"}, {"address": 725, "contract": "Unknown", "debug": "", "description": "A possible integer overflow exists in the function `sendeth(address,uint256)`.\nThe addition or multiplication may result in a value higher than the maximum representable integer.", "function": "sendeth(address,uint256)", "title": "Integer Overflow", "type": "Warning"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/returnvalue.sol.o.json b/tests/testdata/outputs_expected/returnvalue.sol.o.json
index a3fe1e4c..11ebd735 100644
--- a/tests/testdata/outputs_expected/returnvalue.sol.o.json
+++ b/tests/testdata/outputs_expected/returnvalue.sol.o.json
@@ -1 +1 @@
-{"error": null, "issues": [{"address": 196, "debug": "", "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", "function": "_function_0x633ab5e0", "title": "Message call to external contract", "type": "Informational"}, {"address": 285, "debug": "", "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", "function": "_function_0xe3bea282", "title": "Message call to external contract", "type": "Informational"}, {"address": 290, "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xe3bea282", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true}
\ No newline at end of file
+{"error": null, "issues": [{"address": 196, "contract": "Unknown", "debug": "", "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", "function": "_function_0x633ab5e0", "title": "Message call to external contract", "type": "Informational"}, {"address": 285, "contract": "Unknown", "debug": "", "description": "This contract executes a message call to to another contract. Make sure that the called contract is trusted and does not execute user-supplied code.", "function": "_function_0xe3bea282", "title": "Message call to external contract", "type": "Informational"}, {"address": 290, "contract": "Unknown", "debug": "", "description": "The return value of an external call is not checked. Note that execution continue even if the called contract throws.", "function": "_function_0xe3bea282", "title": "Unchecked CALL return value", "type": "Informational"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/suicide.sol.o.json b/tests/testdata/outputs_expected/suicide.sol.o.json
index a8a189b9..1b5818d1 100644
--- a/tests/testdata/outputs_expected/suicide.sol.o.json
+++ b/tests/testdata/outputs_expected/suicide.sol.o.json
@@ -1 +1 @@
-{"error": null, "issues": [{"address": 146, "debug": "", "description": "The function `_function_0xcbf0b0c0` executes the SUICIDE instruction. The remaining Ether is sent to an address provided as a function argument.\n\nIt seems that this function can be called without restrictions.", "function": "_function_0xcbf0b0c0", "title": "Unchecked SUICIDE", "type": "Warning"}], "success": true}
\ No newline at end of file
+{"error": null, "issues": [{"address": 146, "contract": "Unknown", "debug": "", "description": "The function `_function_0xcbf0b0c0` executes the SUICIDE instruction. The remaining Ether is sent to an address provided as a function argument.\n\nIt seems that this function can be called without restrictions.", "function": "_function_0xcbf0b0c0", "title": "Unchecked SUICIDE", "type": "Warning"}], "success": true}
\ No newline at end of file
diff --git a/tests/testdata/outputs_expected/underflow.sol.o.json b/tests/testdata/outputs_expected/underflow.sol.o.json
index 8345944e..341e5b46 100644
--- a/tests/testdata/outputs_expected/underflow.sol.o.json
+++ b/tests/testdata/outputs_expected/underflow.sol.o.json
@@ -1,30 +1 @@
-{
- "success": true,
- "error": null,
- "issues": [
- {
- "title": "Integer Underflow",
- "description": "A possible integer underflow exists in the function `sendeth(address,uint256)`.\nThe subtraction may result in a value < 0.",
- "function": "sendeth(address,uint256)",
- "type": "Warning",
- "address": 649,
- "debug": ""
- },
- {
- "title": "Integer Overflow",
- "description": "A possible integer overflow exists in the function `sendeth(address,uint256)`.\nThe addition or multiplication may result in a value higher than the maximum representable integer.",
- "function": "sendeth(address,uint256)",
- "type": "Warning",
- "address": 725,
- "debug": ""
- },
- {
- "title": "Integer Underflow",
- "description": "A possible integer underflow exists in the function `sendeth(address,uint256)`.\nThe subtraction may result in a value < 0.",
- "function": "sendeth(address,uint256)",
- "type": "Warning",
- "address": 567,
- "debug": ""
- }
- ]
-}
+{"error": null, "issues": [{"address": 567, "contract": "Unknown", "debug": "", "description": "A possible integer underflow exists in the function `sendeth(address,uint256)`.\nThe subtraction may result in a value < 0.", "function": "sendeth(address,uint256)", "title": "Integer Underflow", "type": "Warning"}, {"address": 649, "contract": "Unknown", "debug": "", "description": "A possible integer underflow exists in the function `sendeth(address,uint256)`.\nThe subtraction may result in a value < 0.", "function": "sendeth(address,uint256)", "title": "Integer Underflow", "type": "Warning"}, {"address": 725, "contract": "Unknown", "debug": "", "description": "A possible integer overflow exists in the function `sendeth(address,uint256)`.\nThe addition or multiplication may result in a value higher than the maximum representable integer.", "function": "sendeth(address,uint256)", "title": "Integer Overflow", "type": "Warning"}], "success": true}
\ No newline at end of file
From 084b1ef9555d0338ac1281ccd1f2c0dcf25ef53d Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Wed, 11 Jul 2018 11:14:02 +0200
Subject: [PATCH 62/62] Fix false
---
tests/report_test.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/report_test.py b/tests/report_test.py
index a3cd0f70..88d4c777 100644
--- a/tests/report_test.py
+++ b/tests/report_test.py
@@ -112,7 +112,7 @@ def _get_changed_files_json(report_builder, reports):
output_current = TESTDATA_OUTPUTS_CURRENT / (input_file.name + postfix)
output_current.write_text(report_builder(report))
- if False and not ordered(json.loads(output_expected.read_text())) == ordered(json.loads(output_current.read_text())):
+ if not ordered(json.loads(output_expected.read_text())) == ordered(json.loads(output_current.read_text())):
yield input_file