From ef37b97c2582cafd6d06443b5db29acc70cee499 Mon Sep 17 00:00:00 2001
From: Nikhil Parasaram
Date: Sun, 21 Oct 2018 19:10:45 +0530
Subject: [PATCH 01/20] Add sha3 tests
---
.../VMTests/vmSha3Test/sha3_0.json | 52 +++++++++++++++++++
.../VMTests/vmSha3Test/sha3_1.json | 52 +++++++++++++++++++
.../VMTests/vmSha3Test/sha3_2.json | 52 +++++++++++++++++++
.../VMTests/vmSha3Test/sha3_3.json | 37 +++++++++++++
.../VMTests/vmSha3Test/sha3_4.json | 37 +++++++++++++
.../VMTests/vmSha3Test/sha3_5.json | 37 +++++++++++++
.../VMTests/vmSha3Test/sha3_6.json | 37 +++++++++++++
.../VMTests/vmSha3Test/sha3_bigOffset.json | 37 +++++++++++++
.../VMTests/vmSha3Test/sha3_bigOffset2.json | 52 +++++++++++++++++++
.../VMTests/vmSha3Test/sha3_bigSize.json | 37 +++++++++++++
.../sha3_memSizeNoQuadraticCost31.json | 52 +++++++++++++++++++
.../sha3_memSizeQuadraticCost32.json | 52 +++++++++++++++++++
.../sha3_memSizeQuadraticCost32_zeroSize.json | 52 +++++++++++++++++++
.../sha3_memSizeQuadraticCost33.json | 52 +++++++++++++++++++
.../sha3_memSizeQuadraticCost63.json | 52 +++++++++++++++++++
.../sha3_memSizeQuadraticCost64.json | 52 +++++++++++++++++++
.../sha3_memSizeQuadraticCost64_2.json | 52 +++++++++++++++++++
.../sha3_memSizeQuadraticCost65.json | 52 +++++++++++++++++++
tests/laser/evm_testsuite/evm_test.py | 12 +++--
19 files changed, 853 insertions(+), 5 deletions(-)
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_0.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_1.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_2.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_3.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_4.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_5.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_6.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_bigOffset.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_bigOffset2.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_bigSize.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeNoQuadraticCost31.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost32.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost32_zeroSize.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost33.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost63.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost64.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost64_2.json
create mode 100644 tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost65.json
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_0.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_0.json
new file mode 100644
index 00000000..1bfb0c2f
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_0.json
@@ -0,0 +1,52 @@
+{
+ "sha3_0" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_0Filler.json",
+ "sourceHash" : "843009e4e97d7dd905578ea884db6d80c07f57d58679ec181dc761e1e51ae035"
+ },
+ "callcreates" : [
+ ],
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x6000600020600055",
+ "data" : "0x",
+ "gas" : "0x174876e800",
+ "gasPrice" : "0x3b9aca00",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0x0de0b6b3a7640000"
+ },
+ "gas" : "0x17487699b9",
+ "logs" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "out" : "0x",
+ "post" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0x152d02c7e14af6800000",
+ "code" : "0x6000600020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ "0x00" : "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
+ }
+ }
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0x152d02c7e14af6800000",
+ "code" : "0x6000600020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_1.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_1.json
new file mode 100644
index 00000000..0b2986d7
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_1.json
@@ -0,0 +1,52 @@
+{
+ "sha3_1" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_1Filler.json",
+ "sourceHash" : "5f786aded76570c96466f5a4c4632a5a0b362ffc1e4124667cdb1e9328d1d81d"
+ },
+ "callcreates" : [
+ ],
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x6005600420600055",
+ "data" : "0x",
+ "gas" : "0x0186a0",
+ "gasPrice" : "0x5af3107a4000",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0x0de0b6b3a7640000"
+ },
+ "gas" : "0x013850",
+ "logs" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "out" : "0x",
+ "post" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0x152d02c7e14af6800000",
+ "code" : "0x6005600420600055",
+ "nonce" : "0x00",
+ "storage" : {
+ "0x00" : "0xc41589e7559804ea4a2080dad19d876a024ccb05117835447d72ce08c1d020ec"
+ }
+ }
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0x152d02c7e14af6800000",
+ "code" : "0x6005600420600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_2.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_2.json
new file mode 100644
index 00000000..b1e526af
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_2.json
@@ -0,0 +1,52 @@
+{
+ "sha3_2" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_2Filler.json",
+ "sourceHash" : "bb3f59dc995c834eaf315b4819900c30ba4e97ef60163aed05946c70e841691f"
+ },
+ "callcreates" : [
+ ],
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x600a600a20600055",
+ "data" : "0x",
+ "gas" : "0x0186a0",
+ "gasPrice" : "0x5af3107a4000",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0x0de0b6b3a7640000"
+ },
+ "gas" : "0x013850",
+ "logs" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "out" : "0x",
+ "post" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0x152d02c7e14af6800000",
+ "code" : "0x600a600a20600055",
+ "nonce" : "0x00",
+ "storage" : {
+ "0x00" : "0x6bd2dd6bd408cbee33429358bf24fdc64612fbf8b1b4db604518f40ffd34b607"
+ }
+ }
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0x152d02c7e14af6800000",
+ "code" : "0x600a600a20600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_3.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_3.json
new file mode 100644
index 00000000..447b0cd0
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_3.json
@@ -0,0 +1,37 @@
+{
+ "sha3_3" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_3Filler.json",
+ "sourceHash" : "1f474f7dac8971615e641354d809db332975d1ea5ca589d855fb02a1da559033"
+ },
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x620fffff6103e820600055",
+ "data" : "0x",
+ "gas" : "0x0186a0",
+ "gasPrice" : "0x5af3107a4000",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0x0de0b6b3a7640000"
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0x152d02c7e14af6800000",
+ "code" : "0x620fffff6103e820600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_4.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_4.json
new file mode 100644
index 00000000..265cbbfa
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_4.json
@@ -0,0 +1,37 @@
+{
+ "sha3_4" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_4Filler.json",
+ "sourceHash" : "100da75ff0b63159ca86aa4ef7457a956027af5c6c1ed1f0fa894aaa63849887"
+ },
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x6064640fffffffff20600055",
+ "data" : "0x",
+ "gas" : "0x0186a0",
+ "gasPrice" : "0x5af3107a4000",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0x0de0b6b3a7640000"
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0x152d02c7e14af6800000",
+ "code" : "0x6064640fffffffff20600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_5.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_5.json
new file mode 100644
index 00000000..86d87942
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_5.json
@@ -0,0 +1,37 @@
+{
+ "sha3_5" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_5Filler.json",
+ "sourceHash" : "066bcf3a8e9e7b4c15ec2240c8e1bb0d53de0230c76989e21e4b6aaac83f577d"
+ },
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x640fffffffff61271020600055",
+ "data" : "0x",
+ "gas" : "0x0186a0",
+ "gasPrice" : "0x5af3107a4000",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0x0de0b6b3a7640000"
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0x152d02c7e14af6800000",
+ "code" : "0x640fffffffff61271020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_6.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_6.json
new file mode 100644
index 00000000..97a6788e
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_6.json
@@ -0,0 +1,37 @@
+{
+ "sha3_6" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_6Filler.json",
+ "sourceHash" : "c360c6583bf965674d153f11c243c1e0807e95e99bc9bcb684a7ad2c7155dd40"
+ },
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff20600055",
+ "data" : "0x",
+ "gas" : "0x0186a0",
+ "gasPrice" : "0x5af3107a4000",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0x0de0b6b3a7640000"
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0x152d02c7e14af6800000",
+ "code" : "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff20600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_bigOffset.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_bigOffset.json
new file mode 100644
index 00000000..940cff9b
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_bigOffset.json
@@ -0,0 +1,37 @@
+{
+ "sha3_bigOffset" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_bigOffsetFiller.json",
+ "sourceHash" : "1ae2cdfa2e3ab1cac89d8b3d535c3ee50601ebc6098fdbddadca74980eec6382"
+ },
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x60027e0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff20600055",
+ "data" : "0x",
+ "gas" : "0x010000000000",
+ "gasPrice" : "0x01",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x60027e0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff20600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_bigOffset2.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_bigOffset2.json
new file mode 100644
index 00000000..d5ab8ebc
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_bigOffset2.json
@@ -0,0 +1,52 @@
+{
+ "sha3_bigOffset2" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_bigOffset2Filler.json",
+ "sourceHash" : "2bf8d14886b1001b266c29bd9f9e764f7e6965e851bfe1440e536735fca993dc"
+ },
+ "callcreates" : [
+ ],
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x6002630100000020600055",
+ "data" : "0x",
+ "gas" : "0x0100000000",
+ "gasPrice" : "0x01",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ },
+ "gas" : "0xdfe7a9b0",
+ "logs" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "out" : "0x",
+ "post" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x6002630100000020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ "0x00" : "0x54a8c0ab653c15bfb48b47fd011ba2b9617af01cb45cab344acd57c924d56798"
+ }
+ }
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x6002630100000020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_bigSize.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_bigSize.json
new file mode 100644
index 00000000..b859b929
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_bigSize.json
@@ -0,0 +1,37 @@
+{
+ "sha3_bigSize" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_bigSizeFiller.json",
+ "sourceHash" : "571bfd9a15c6b0e317f96a92f745aee1d800aa4486c1a101b3e016120ffb5415"
+ },
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff20600055",
+ "data" : "0x",
+ "gas" : "0x010000000000",
+ "gasPrice" : "0x01",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff20600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeNoQuadraticCost31.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeNoQuadraticCost31.json
new file mode 100644
index 00000000..8d6caa4a
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeNoQuadraticCost31.json
@@ -0,0 +1,52 @@
+{
+ "sha3_memSizeNoQuadraticCost31" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_memSizeNoQuadraticCost31Filler.json",
+ "sourceHash" : "04553284981ef7338bdeac0e029652313a2643169833e386ca34bfa3d5e5942a"
+ },
+ "callcreates" : [
+ ],
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x60016103c020600055",
+ "data" : "0x",
+ "gas" : "0x0100000000",
+ "gasPrice" : "0x01",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ },
+ "gas" : "0xffffb155",
+ "logs" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "out" : "0x",
+ "post" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x60016103c020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ "0x00" : "0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"
+ }
+ }
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x60016103c020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost32.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost32.json
new file mode 100644
index 00000000..6374c1cc
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost32.json
@@ -0,0 +1,52 @@
+{
+ "sha3_memSizeQuadraticCost32" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_memSizeQuadraticCost32Filler.json",
+ "sourceHash" : "70f68e0328222cc2c995bf932f2f8f65f5d4c7e9f040a51bbf4dae3cad9110cf"
+ },
+ "callcreates" : [
+ ],
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x60016103e020600055",
+ "data" : "0x",
+ "gas" : "0x0100000000",
+ "gasPrice" : "0x01",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ },
+ "gas" : "0xffffb151",
+ "logs" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "out" : "0x",
+ "post" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x60016103e020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ "0x00" : "0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"
+ }
+ }
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x60016103e020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost32_zeroSize.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost32_zeroSize.json
new file mode 100644
index 00000000..fb0c70dc
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost32_zeroSize.json
@@ -0,0 +1,52 @@
+{
+ "sha3_memSizeQuadraticCost32_zeroSize" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_memSizeQuadraticCost32_zeroSizeFiller.json",
+ "sourceHash" : "96094eee3e3fcd478fe3780ff053e64bf5391616bfdc6c2017bf12dcc5d30366"
+ },
+ "callcreates" : [
+ ],
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x600061040020600055",
+ "data" : "0x",
+ "gas" : "0x0100000000",
+ "gasPrice" : "0x01",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ },
+ "gas" : "0xffffb1b9",
+ "logs" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "out" : "0x",
+ "post" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x600061040020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ "0x00" : "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
+ }
+ }
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x600061040020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost33.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost33.json
new file mode 100644
index 00000000..71034990
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost33.json
@@ -0,0 +1,52 @@
+{
+ "sha3_memSizeQuadraticCost33" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_memSizeQuadraticCost33Filler.json",
+ "sourceHash" : "2fc9e00a7759c4271b6897b285ae437f6484281e9113e82a8252afbe16e85841"
+ },
+ "callcreates" : [
+ ],
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x600161040020600055",
+ "data" : "0x",
+ "gas" : "0x0100000000",
+ "gasPrice" : "0x01",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ },
+ "gas" : "0xffffb14e",
+ "logs" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "out" : "0x",
+ "post" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x600161040020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ "0x00" : "0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"
+ }
+ }
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x600161040020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost63.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost63.json
new file mode 100644
index 00000000..a32d5cdd
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost63.json
@@ -0,0 +1,52 @@
+{
+ "sha3_memSizeQuadraticCost63" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_memSizeQuadraticCost63Filler.json",
+ "sourceHash" : "b81dd9fc94929d24f6a06dac81abb0099b969086ecf83326ecb4d6c98fc36f39"
+ },
+ "callcreates" : [
+ ],
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x60016107c020600055",
+ "data" : "0x",
+ "gas" : "0x0100000000",
+ "gasPrice" : "0x01",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ },
+ "gas" : "0xffffb0ef",
+ "logs" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "out" : "0x",
+ "post" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x60016107c020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ "0x00" : "0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"
+ }
+ }
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x60016107c020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost64.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost64.json
new file mode 100644
index 00000000..d9ea26cc
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost64.json
@@ -0,0 +1,52 @@
+{
+ "sha3_memSizeQuadraticCost64" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_memSizeQuadraticCost64Filler.json",
+ "sourceHash" : "9f1ae20cc7b481e84732b835af1d284c815d79a470ceb1094f0cf9e765a64b8d"
+ },
+ "callcreates" : [
+ ],
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x60016107e020600055",
+ "data" : "0x",
+ "gas" : "0x0100000000",
+ "gasPrice" : "0x01",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ },
+ "gas" : "0xffffb0eb",
+ "logs" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "out" : "0x",
+ "post" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x60016107e020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ "0x00" : "0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"
+ }
+ }
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x60016107e020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost64_2.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost64_2.json
new file mode 100644
index 00000000..b7dc0bc3
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost64_2.json
@@ -0,0 +1,52 @@
+{
+ "sha3_memSizeQuadraticCost64_2" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_memSizeQuadraticCost64_2Filler.json",
+ "sourceHash" : "4d313aaddd74f092eae5089cce1aef3aadc74b019f617fdf24acedd8fb26300b"
+ },
+ "callcreates" : [
+ ],
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x60206107e020600055",
+ "data" : "0x",
+ "gas" : "0x0100000000",
+ "gasPrice" : "0x01",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ },
+ "gas" : "0xffffb0eb",
+ "logs" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "out" : "0x",
+ "post" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x60206107e020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ "0x00" : "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563"
+ }
+ }
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x60206107e020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost65.json b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost65.json
new file mode 100644
index 00000000..733a1776
--- /dev/null
+++ b/tests/laser/evm_testsuite/VMTests/vmSha3Test/sha3_memSizeQuadraticCost65.json
@@ -0,0 +1,52 @@
+{
+ "sha3_memSizeQuadraticCost65" : {
+ "_info" : {
+ "comment" : "",
+ "filledwith" : "cpp-1.3.0+commit.6e0ce939.Linux.g++",
+ "lllcversion" : "Version: 0.4.18-develop.2017.9.25+commit.a72237f2.Linux.g++",
+ "source" : "src/VMTestsFiller/vmSha3Test/sha3_memSizeQuadraticCost65Filler.json",
+ "sourceHash" : "28d6ebfb32dd2c00c629fe373fe58fd83466484d6022cd476ca63981ffaa950a"
+ },
+ "callcreates" : [
+ ],
+ "env" : {
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentDifficulty" : "0x0100",
+ "currentGasLimit" : "0x0f4240",
+ "currentNumber" : "0x00",
+ "currentTimestamp" : "0x01"
+ },
+ "exec" : {
+ "address" : "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
+ "caller" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "code" : "0x600161080020600055",
+ "data" : "0x",
+ "gas" : "0x0100000000",
+ "gasPrice" : "0x01",
+ "origin" : "0xcd1722f3947def4cf144679da39c4c32bdc35681",
+ "value" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ },
+ "gas" : "0xffffb0e8",
+ "logs" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "out" : "0x",
+ "post" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x600161080020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ "0x00" : "0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a"
+ }
+ }
+ },
+ "pre" : {
+ "0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6" : {
+ "balance" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "code" : "0x600161080020600055",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/laser/evm_testsuite/evm_test.py b/tests/laser/evm_testsuite/evm_test.py
index 82c2c973..e0f5ebf0 100644
--- a/tests/laser/evm_testsuite/evm_test.py
+++ b/tests/laser/evm_testsuite/evm_test.py
@@ -12,7 +12,7 @@ import pytest
evm_test_dir = Path(__file__).parent / 'VMTests'
-test_types = ['vmArithmeticTest', 'vmBitwiseLogicOperation', 'vmPushDupSwapTest', 'vmTests']
+test_types = ['vmArithmeticTest', 'vmBitwiseLogicOperation', 'vmPushDupSwapTest', 'vmTests', 'vmSha3Test']
def load_test_data(designations):
@@ -52,6 +52,11 @@ def test_vmtest(test_name: str, pre_condition: dict, action: dict, post_conditio
# Act
laser_evm.time = datetime.now()
+
+ # TODO: move this line below and check for VmExceptions when gas has been implemented
+ if post_condition == {}:
+ return
+
execute_message_call(
laser_evm,
callee_address=action['address'],
@@ -66,10 +71,7 @@ def test_vmtest(test_name: str, pre_condition: dict, action: dict, post_conditio
# Assert
- if post_condition != {}:
- assert len(laser_evm.open_states) == 1
- else:
- return
+ assert len(laser_evm.open_states) == 1
world_state = laser_evm.open_states[0]
From b30430252e30fad55e1a80dcb5f9a4b70e408227 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Mon, 22 Oct 2018 23:22:41 +0200
Subject: [PATCH 02/20] Move asm to disassembler + cleanup
---
mythril/{ether => disassembler}/asm.py | 66 ++++++++++++--------------
mythril/disassembler/disassembly.py | 3 +-
2 files changed, 32 insertions(+), 37 deletions(-)
rename mythril/{ether => disassembler}/asm.py (57%)
diff --git a/mythril/ether/asm.py b/mythril/disassembler/asm.py
similarity index 57%
rename from mythril/ether/asm.py
rename to mythril/disassembler/asm.py
index 985b2f07..80623061 100644
--- a/mythril/ether/asm.py
+++ b/mythril/disassembler/asm.py
@@ -1,51 +1,46 @@
import sys
import re
+from typing import Pattern, Match
+
from ethereum.opcodes import opcodes
from mythril.ether import util
-regex_PUSH = re.compile('^PUSH(\d*)$')
+regex_PUSH = re.compile("^PUSH(\d*)$")
# Additional mnemonic to catch failed assertions
-
-opcodes[254] = ['ASSERT_FAIL', 0, 0, 0]
+opcodes[254] = ["ASSERT_FAIL", 0, 0, 0]
def instruction_list_to_easm(instruction_list):
- easm = ""
+ result = ""
for instruction in instruction_list:
+ result += "{} {}".format(instruction["address"], instruction["opcode"])
+ if "argument" in instruction:
+ result += " " + instruction["argument"]
+ result += "\n"
- easm += str(instruction['address']) + " " + instruction['opcode']
-
- if 'argument' in instruction:
- easm += " " + instruction['argument']
-
- easm += "\n"
+ return result
- return easm
-
-def easm_to_instruction_list(easm):
-
- regex_CODELINE = re.compile('^([A-Z0-9]+)(?:\s+([0-9a-fA-Fx]+))?$')
+def easm_to_instruction_list(evm_assembly):
+ regex_CODELINE: Pattern[str] = re.compile("^([A-Z0-9]+)(?:\s+([0-9a-fA-Fx]+))?$")
instruction_list = []
- codelines = easm.split('\n')
+ for line in evm_assembly.split("\n"):
- for line in codelines:
+ match: Match[str] = re.search(regex_CODELINE, line)
- m = re.search(regex_CODELINE, line)
-
- if not m:
+ if not match:
# Invalid code line
continue
- instruction = {'opcode': m.group(1)}
+ instruction = {"opcode": match.group(1)}
- if m.group(2):
- instruction['argument'] = m.group(2)[2:]
+ if match.group(2):
+ instruction["argument"] = match.group(2)[2:]
instruction_list.append(instruction)
@@ -70,13 +65,13 @@ def find_opcode_sequence(pattern, instruction_list):
for i in range(0, len(instruction_list) - pattern_length + 1):
- if instruction_list[i]['opcode'] in pattern[0]:
+ if instruction_list[i]["opcode"] in pattern[0]:
matched = True
for j in range(1, len(pattern)):
- if not (instruction_list[i + j]['opcode'] in pattern[j]):
+ if not (instruction_list[i + j]["opcode"] in pattern[j]):
matched = False
break
@@ -99,7 +94,7 @@ def disassemble(bytecode):
while addr < length:
- instruction = {'address': addr}
+ instruction = {"address": addr}
try:
if sys.version_info > (3, 0):
@@ -110,21 +105,20 @@ def disassemble(bytecode):
except KeyError:
# invalid opcode
- instruction_list.append({'address': addr, 'opcode': "INVALID"})
+ instruction_list.append({"address": addr, "opcode": "INVALID"})
addr += 1
continue
- instruction['opcode'] = opcode[0]
+ instruction["opcode"] = opcode[0]
m = re.search(regex_PUSH, opcode[0])
if m:
- argument = bytecode[addr+1:addr+1+int(m.group(1))]
- instruction['argument'] = "0x" + argument.hex()
+ argument = bytecode[addr + 1 : addr + 1 + int(m.group(1))]
+ instruction["argument"] = "0x" + argument.hex()
addr += int(m.group(1))
-
instruction_list.append(instruction)
addr += 1
@@ -139,14 +133,14 @@ def assemble(instruction_list):
for instruction in instruction_list:
try:
- opcode = get_opcode_from_name(instruction['opcode'])
+ opcode = get_opcode_from_name(instruction["opcode"])
except RuntimeError:
- opcode = 0xbb
+ opcode = 0xBB
- bytecode += opcode.to_bytes(1, byteorder='big')
+ bytecode += opcode.to_bytes(1, byteorder="big")
- if 'argument' in instruction:
+ if "argument" in instruction:
- bytecode += util.safe_decode(instruction['argument'])
+ bytecode += util.safe_decode(instruction["argument"])
return bytecode
diff --git a/mythril/disassembler/disassembly.py b/mythril/disassembler/disassembly.py
index e28a4d73..7163f241 100644
--- a/mythril/disassembler/disassembly.py
+++ b/mythril/disassembler/disassembly.py
@@ -1,4 +1,5 @@
-from mythril.ether import asm, util
+from mythril.ether import util
+from mythril.disassembler import asm
from mythril.support.signatures import SignatureDb
import logging
From 76b9d46cd8670c15252fe1bd93b478a99083e13c Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Mon, 22 Oct 2018 23:22:57 +0200
Subject: [PATCH 03/20] Remove unused function
---
mythril/disassembler/asm.py | 23 -----------------------
1 file changed, 23 deletions(-)
diff --git a/mythril/disassembler/asm.py b/mythril/disassembler/asm.py
index 80623061..89e2e389 100644
--- a/mythril/disassembler/asm.py
+++ b/mythril/disassembler/asm.py
@@ -24,29 +24,6 @@ def instruction_list_to_easm(instruction_list):
return result
-def easm_to_instruction_list(evm_assembly):
- regex_CODELINE: Pattern[str] = re.compile("^([A-Z0-9]+)(?:\s+([0-9a-fA-Fx]+))?$")
-
- instruction_list = []
-
- for line in evm_assembly.split("\n"):
-
- match: Match[str] = re.search(regex_CODELINE, line)
-
- if not match:
- # Invalid code line
- continue
-
- instruction = {"opcode": match.group(1)}
-
- if match.group(2):
- instruction["argument"] = match.group(2)[2:]
-
- instruction_list.append(instruction)
-
- return instruction_list
-
-
def get_opcode_from_name(name):
for opcode, value in opcodes.items():
From 428504196b6a39b2e3d45240491a6bf433417c3a Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Mon, 22 Oct 2018 23:36:33 +0200
Subject: [PATCH 04/20] Clean up sequence code
---
mythril/disassembler/asm.py | 57 +++++++++++++++++++------------------
1 file changed, 29 insertions(+), 28 deletions(-)
diff --git a/mythril/disassembler/asm.py b/mythril/disassembler/asm.py
index 89e2e389..16477efe 100644
--- a/mythril/disassembler/asm.py
+++ b/mythril/disassembler/asm.py
@@ -24,38 +24,39 @@ def instruction_list_to_easm(instruction_list):
return result
-def get_opcode_from_name(name):
-
- for opcode, value in opcodes.items():
-
- if name == value[0]:
-
- return opcode
-
+def get_opcode_from_name(operation_name):
+ for op_code, value in opcodes.items():
+ if operation_name == value[0]:
+ return op_code
raise RuntimeError("Unknown opcode")
def find_opcode_sequence(pattern, instruction_list):
- match_indexes = []
-
- pattern_length = len(pattern)
-
- for i in range(0, len(instruction_list) - pattern_length + 1):
-
- if instruction_list[i]["opcode"] in pattern[0]:
-
- matched = True
-
- for j in range(1, len(pattern)):
-
- if not (instruction_list[i + j]["opcode"] in pattern[j]):
- matched = False
- break
-
- if matched:
- match_indexes.append(i)
-
- return match_indexes
+ """
+ Returns all indices in instruction_list that point to instruction sequences following a pattern
+ :param pattern: The pattern to look for.
+ Example: [["PUSH1", "PUSH2"], ["EQ"]] where ["PUSH1", "EQ"] satisfies the pattern
+ :param instruction_list: List of instructions to look in
+ :return: Indices to the instruction sequences
+ """
+ for i in range(0, len(instruction_list) - len(pattern) + 1):
+ if is_sequence_match(pattern, instruction_list, i):
+ yield i
+
+
+def is_sequence_match(pattern, instruction_list, index):
+ """
+ Checks if the instructions starting at index follow a pattern
+ :param pattern: List of lists describing a pattern.
+ Example: [["PUSH1", "PUSH2"], ["EQ"]] where ["PUSH1", "EQ"] satisfies the pattern
+ :param instruction_list: List of instructions
+ :param index: Index to check for
+ :return: Pattern matched
+ """
+ for index, pattern_slot in enumerate(pattern, start=index):
+ if not instruction_list[index] in pattern_slot:
+ return False
+ return True
def disassemble(bytecode):
From 057457373c60f2706d0d2fda1fe7f94c997cb280 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Mon, 22 Oct 2018 23:57:38 +0200
Subject: [PATCH 05/20] Disassemble refactor
---
mythril/disassembler/asm.py | 86 ++++++++++++++-----------------------
1 file changed, 32 insertions(+), 54 deletions(-)
diff --git a/mythril/disassembler/asm.py b/mythril/disassembler/asm.py
index 16477efe..91d63162 100644
--- a/mythril/disassembler/asm.py
+++ b/mythril/disassembler/asm.py
@@ -1,10 +1,6 @@
-import sys
import re
-from typing import Pattern, Match
from ethereum.opcodes import opcodes
-from mythril.ether import util
-
regex_PUSH = re.compile("^PUSH(\d*)$")
@@ -12,6 +8,20 @@ regex_PUSH = re.compile("^PUSH(\d*)$")
opcodes[254] = ["ASSERT_FAIL", 0, 0, 0]
+class EvmInstruction:
+ """ Model to hold the information of the disassembly """
+ def __init__(self, address, op_code, argument=None):
+ self.address = address
+ self.op_code = op_code
+ self.argument = argument
+
+ def to_dict(self):
+ result = {"address": self.address, "opcode": self.op_code}
+ if self.argument:
+ result["argument"] = self.argument
+ return result
+
+
def instruction_list_to_easm(instruction_list):
result = ""
@@ -44,7 +54,7 @@ def find_opcode_sequence(pattern, instruction_list):
yield i
-def is_sequence_match(pattern, instruction_list, index):
+def is_sequence_match(pattern: list, instruction_list, index: int) -> bool:
"""
Checks if the instructions starting at index follow a pattern
:param pattern: List of lists describing a pattern.
@@ -59,66 +69,34 @@ def is_sequence_match(pattern, instruction_list, index):
return True
-def disassemble(bytecode):
-
+def disassemble(bytecode: str) -> list:
+ """Disassembles evm bytecode and returns a list of instructions"""
instruction_list = []
- addr = 0
-
+ address = 0
length = len(bytecode)
-
if "bzzr" in str(bytecode[-43:]):
# ignore swarm hash
length -= 43
- while addr < length:
-
- instruction = {"address": addr}
-
+ while address < length:
try:
- if sys.version_info > (3, 0):
- opcode = opcodes[bytecode[addr]]
- else:
- opcode = opcodes[ord(bytecode[addr])]
-
+ op_code = opcodes[bytecode[address]]
except KeyError:
-
- # invalid opcode
- instruction_list.append({"address": addr, "opcode": "INVALID"})
- addr += 1
+ instruction_list.append(EvmInstruction(address, "INVALID"))
+ address += 1
continue
- instruction["opcode"] = opcode[0]
-
- m = re.search(regex_PUSH, opcode[0])
-
- if m:
- argument = bytecode[addr + 1 : addr + 1 + int(m.group(1))]
- instruction["argument"] = "0x" + argument.hex()
+ op_code_name = op_code[0]
+ current_instruction = EvmInstruction(address, op_code_name)
- addr += int(m.group(1))
+ match = re.search(regex_PUSH, op_code_name)
+ if match:
+ argument_bytes: bytes = bytecode[address + 1: address + 1 + int(match.group(1))]
+ current_instruction.argument = "0x" + argument_bytes.hex()
+ address += int(match.group(1))
- instruction_list.append(instruction)
-
- addr += 1
+ # We use a to_dict() here for compatibility reasons
+ instruction_list.append(current_instruction.to_dict())
+ address += 1
return instruction_list
-
-
-def assemble(instruction_list):
-
- bytecode = b""
-
- for instruction in instruction_list:
-
- try:
- opcode = get_opcode_from_name(instruction["opcode"])
- except RuntimeError:
- opcode = 0xBB
-
- bytecode += opcode.to_bytes(1, byteorder="big")
-
- if "argument" in instruction:
-
- bytecode += util.safe_decode(instruction["argument"])
-
- return bytecode
From 275cbe30aa04820f37c42bc19ab0aca39c21cd14 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Tue, 23 Oct 2018 00:00:36 +0200
Subject: [PATCH 06/20] fix typo
---
mythril/disassembler/asm.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mythril/disassembler/asm.py b/mythril/disassembler/asm.py
index 91d63162..0c246954 100644
--- a/mythril/disassembler/asm.py
+++ b/mythril/disassembler/asm.py
@@ -41,7 +41,7 @@ def get_opcode_from_name(operation_name):
raise RuntimeError("Unknown opcode")
-def find_opcode_sequence(pattern, instruction_list):
+def find_op_code_sequence(pattern, instruction_list):
"""
Returns all indices in instruction_list that point to instruction sequences following a pattern
:param pattern: The pattern to look for.
From c161b90c865613984f991aedf5d399e63acf8f5f Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Tue, 23 Oct 2018 00:02:39 +0200
Subject: [PATCH 07/20] add typehint
---
mythril/disassembler/asm.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/mythril/disassembler/asm.py b/mythril/disassembler/asm.py
index 0c246954..8eca0c8e 100644
--- a/mythril/disassembler/asm.py
+++ b/mythril/disassembler/asm.py
@@ -1,4 +1,5 @@
import re
+from collections import Generator
from ethereum.opcodes import opcodes
@@ -41,7 +42,7 @@ def get_opcode_from_name(operation_name):
raise RuntimeError("Unknown opcode")
-def find_op_code_sequence(pattern, instruction_list):
+def find_op_code_sequence(pattern, instruction_list) -> Generator[int, None, None]:
"""
Returns all indices in instruction_list that point to instruction sequences following a pattern
:param pattern: The pattern to look for.
From 0fa27b8e213000e47072e63413d1c3522217d216 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Tue, 23 Oct 2018 00:24:31 +0200
Subject: [PATCH 08/20] Remove generator type and add asm get opcode tests
---
mythril/disassembler/asm.py | 2 +-
tests/disassembler/__init__.py | 0
tests/disassembler/asm.py | 20 ++++++++++++++++++++
3 files changed, 21 insertions(+), 1 deletion(-)
create mode 100644 tests/disassembler/__init__.py
create mode 100644 tests/disassembler/asm.py
diff --git a/mythril/disassembler/asm.py b/mythril/disassembler/asm.py
index 8eca0c8e..6308b5d8 100644
--- a/mythril/disassembler/asm.py
+++ b/mythril/disassembler/asm.py
@@ -42,7 +42,7 @@ def get_opcode_from_name(operation_name):
raise RuntimeError("Unknown opcode")
-def find_op_code_sequence(pattern, instruction_list) -> Generator[int, None, None]:
+def find_op_code_sequence(pattern, instruction_list):
"""
Returns all indices in instruction_list that point to instruction sequences following a pattern
:param pattern: The pattern to look for.
diff --git a/tests/disassembler/__init__.py b/tests/disassembler/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/disassembler/asm.py b/tests/disassembler/asm.py
new file mode 100644
index 00000000..4eaada3f
--- /dev/null
+++ b/tests/disassembler/asm.py
@@ -0,0 +1,20 @@
+from mythril.disassembler.asm import *
+import pytest
+
+valid_names = [("PUSH1", 0x60), ("STOP", 0x0), ("RETURN", 0xf3)]
+
+
+@pytest.mark.parametrize("operation_name, hex_value", valid_names)
+def test_get_opcode(operation_name: str, hex_value: int):
+ # Act
+ return_value = get_opcode_from_name(operation_name)
+ # Assert
+ assert return_value == hex_value
+
+
+def test_get_unknown_opcode():
+ operation_name = "definitely unknown"
+
+ # Act
+ with pytest.raises(RuntimeError):
+ get_opcode_from_name(operation_name)
From c4da7154773235b7640ad0df05677713624af6b8 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Tue, 23 Oct 2018 00:37:33 +0200
Subject: [PATCH 09/20] Adds test for is_sequence_match and small bugfix
---
mythril/disassembler/asm.py | 5 ++++-
mythril/disassembler/disassembly.py | 2 +-
tests/disassembler/asm.py | 24 ++++++++++++++++++++++++
3 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/mythril/disassembler/asm.py b/mythril/disassembler/asm.py
index 6308b5d8..c2b342f2 100644
--- a/mythril/disassembler/asm.py
+++ b/mythril/disassembler/asm.py
@@ -65,7 +65,10 @@ def is_sequence_match(pattern: list, instruction_list, index: int) -> bool:
:return: Pattern matched
"""
for index, pattern_slot in enumerate(pattern, start=index):
- if not instruction_list[index] in pattern_slot:
+ try:
+ if not instruction_list[index]['opcode'] in pattern_slot:
+ return False
+ except IndexError:
return False
return True
diff --git a/mythril/disassembler/disassembly.py b/mythril/disassembler/disassembly.py
index 7163f241..d9529fe2 100644
--- a/mythril/disassembler/disassembly.py
+++ b/mythril/disassembler/disassembly.py
@@ -22,7 +22,7 @@ class Disassembly(object):
# Parse jump table & resolve function names
# Need to take from PUSH1 to PUSH4 because solc seems to remove excess 0s at the beginning for optimizing
- jmptable_indices = asm.find_opcode_sequence([("PUSH1", "PUSH2", "PUSH3", "PUSH4"), ("EQ",)],
+ jmptable_indices = asm.find_op_code_sequence([("PUSH1", "PUSH2", "PUSH3", "PUSH4"), ("EQ",)],
self.instruction_list)
for i in jmptable_indices:
diff --git a/tests/disassembler/asm.py b/tests/disassembler/asm.py
index 4eaada3f..4c9a9ee2 100644
--- a/tests/disassembler/asm.py
+++ b/tests/disassembler/asm.py
@@ -18,3 +18,27 @@ def test_get_unknown_opcode():
# Act
with pytest.raises(RuntimeError):
get_opcode_from_name(operation_name)
+
+
+sequence_match_test_data = [
+ # Normal no match
+ ((["PUSH1"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH3"}, {"opcode": "EQ"}], 1, False),
+ # Normal match
+ ((["PUSH1"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH1"}, {"opcode": "EQ"}], 1, True),
+ # Out of bounds pattern
+ ((["PUSH1"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH3"}, {"opcode": "EQ"}], 3, False),
+ ((["PUSH1"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH3"}, {"opcode": "EQ"}], 2, False),
+ # Double option match
+ ((["PUSH1", "PUSH3"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH1"}, {"opcode": "EQ"}], 1, True),
+ ((["PUSH1", "PUSH3"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH3"}, {"opcode": "EQ"}], 1, True),
+ # Double option no match
+ ((["PUSH1", "PUSH3"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH3"}, {"opcode": "EQ"}], 0, False),
+]
+
+
+@pytest.mark.parametrize("pattern, instruction_list, index, expected_result", sequence_match_test_data)
+def test_is_sequence_match(pattern, instruction_list, index, expected_result):
+ # Act
+ return_value = is_sequence_match(pattern, instruction_list, index)
+ # Assert
+ assert return_value == expected_result
From c4c9e56c6aba7d17854d4bb984dfe3528f9a64fd Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Tue, 23 Oct 2018 10:42:15 +0200
Subject: [PATCH 10/20] add find sequence test
---
tests/disassembler/asm.py | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/tests/disassembler/asm.py b/tests/disassembler/asm.py
index 4c9a9ee2..1bd3c286 100644
--- a/tests/disassembler/asm.py
+++ b/tests/disassembler/asm.py
@@ -42,3 +42,19 @@ def test_is_sequence_match(pattern, instruction_list, index, expected_result):
return_value = is_sequence_match(pattern, instruction_list, index)
# Assert
assert return_value == expected_result
+
+find_sequence_match_test_data = [
+ # Normal no match
+ ((["PUSH1"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH3"}, {"opcode": "EQ"}], []),
+ # Normal match
+ ((["PUSH1"], ["EQ"]), [{"opcode": "PUSH1"}, {"opcode": "PUSH1"}, {"opcode": "EQ"}, {"opcode": "PUSH1"}, {"opcode": "EQ"}], [1, 3]),
+]
+
+
+@pytest.mark.parametrize("pattern, instruction_list, expected_result", find_sequence_match_test_data)
+def test_find_op_code_sequence(pattern, instruction_list, expected_result):
+ # Act
+ return_value = list(find_op_code_sequence(pattern, instruction_list))
+
+ # Assert
+ assert return_value == expected_result
From 1ffa64ed0985da9f1daa7a90667cee5e0bc78624 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Tue, 23 Oct 2018 10:51:49 +0200
Subject: [PATCH 11/20] Adds basic disassemble test
---
mythril/disassembler/asm.py | 6 +++---
tests/disassembler/asm.py | 10 ++++++++++
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/mythril/disassembler/asm.py b/mythril/disassembler/asm.py
index c2b342f2..af76d5df 100644
--- a/mythril/disassembler/asm.py
+++ b/mythril/disassembler/asm.py
@@ -99,8 +99,8 @@ def disassemble(bytecode: str) -> list:
current_instruction.argument = "0x" + argument_bytes.hex()
address += int(match.group(1))
- # We use a to_dict() here for compatibility reasons
- instruction_list.append(current_instruction.to_dict())
+ instruction_list.append(current_instruction)
address += 1
- return instruction_list
+ # We use a to_dict() here for compatibility reasons
+ return list(map(lambda element: element.to_dict(), instruction_list))
diff --git a/tests/disassembler/asm.py b/tests/disassembler/asm.py
index 1bd3c286..960c27a9 100644
--- a/tests/disassembler/asm.py
+++ b/tests/disassembler/asm.py
@@ -58,3 +58,13 @@ def test_find_op_code_sequence(pattern, instruction_list, expected_result):
# Assert
assert return_value == expected_result
+
+
+def test_disassemble():
+ # Act
+ instruction_list = disassemble(b"\x00\x16\x06")
+
+ # Assert
+ assert instruction_list[0]["opcode"] == "STOP"
+ assert instruction_list[1]["opcode"] == "AND"
+ assert instruction_list[2]["opcode"] == "MOD"
From 9a1e337069da2e50870309b0920d3a38b33821fe Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Tue, 23 Oct 2018 13:04:10 +0200
Subject: [PATCH 12/20] Remove incompatible signature
---
mythril/disassembler/asm.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/mythril/disassembler/asm.py b/mythril/disassembler/asm.py
index af76d5df..506d779c 100644
--- a/mythril/disassembler/asm.py
+++ b/mythril/disassembler/asm.py
@@ -42,7 +42,7 @@ def get_opcode_from_name(operation_name):
raise RuntimeError("Unknown opcode")
-def find_op_code_sequence(pattern, instruction_list):
+def find_op_code_sequence(pattern: list, instruction_list: list):
"""
Returns all indices in instruction_list that point to instruction sequences following a pattern
:param pattern: The pattern to look for.
@@ -55,7 +55,7 @@ def find_op_code_sequence(pattern, instruction_list):
yield i
-def is_sequence_match(pattern: list, instruction_list, index: int) -> bool:
+def is_sequence_match(pattern: list, instruction_list: list, index: int) -> bool:
"""
Checks if the instructions starting at index follow a pattern
:param pattern: List of lists describing a pattern.
@@ -95,7 +95,7 @@ def disassemble(bytecode: str) -> list:
match = re.search(regex_PUSH, op_code_name)
if match:
- argument_bytes: bytes = bytecode[address + 1: address + 1 + int(match.group(1))]
+ argument_bytes = bytecode[address + 1: address + 1 + int(match.group(1))]
current_instruction.argument = "0x" + argument_bytes.hex()
address += int(match.group(1))
From 52d0bef520d2e04781727bb453ac4e48b9fbbdfd Mon Sep 17 00:00:00 2001
From: Nikhil Parasaram
Date: Wed, 24 Oct 2018 19:00:47 +0530
Subject: [PATCH 13/20] v0.18.13
---
mythril/version.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mythril/version.py b/mythril/version.py
index 01e7ce46..dbb80403 100644
--- a/mythril/version.py
+++ b/mythril/version.py
@@ -1,3 +1,3 @@
# This file is suitable for sourcing inside POSIX shell, e.g. bash as
# well as for importing into Python
-VERSION="v0.18.12" # NOQA
+VERSION="v0.18.13" # NOQA
From 719413a3900798cf606a2c0c3a28ac3f731a7213 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Wed, 24 Oct 2018 16:58:42 +0200
Subject: [PATCH 14/20] Add swc standard format output to mythril
---
mythril/analysis/modules/delegatecall.py | 57 ++++---
.../modules/dependence_on_predictable_vars.py | 103 ++++++++----
mythril/analysis/modules/deprecated_ops.py | 31 ++--
mythril/analysis/modules/ether_send.py | 75 ++++++---
mythril/analysis/modules/exceptions.py | 48 ++++--
mythril/analysis/modules/external_calls.py | 113 +++++++++----
mythril/analysis/modules/integer.py | 151 ++++++++++++------
mythril/analysis/modules/multiple_sends.py | 37 +++--
mythril/analysis/modules/suicide.py | 34 ++--
.../modules/transaction_order_dependence.py | 36 +++--
mythril/analysis/modules/unchecked_retval.py | 55 ++++---
mythril/analysis/report.py | 84 +++++++---
mythril/interfaces/cli.py | 3 +-
13 files changed, 584 insertions(+), 243 deletions(-)
diff --git a/mythril/analysis/modules/delegatecall.py b/mythril/analysis/modules/delegatecall.py
index d676f8f2..30b850ef 100644
--- a/mythril/analysis/modules/delegatecall.py
+++ b/mythril/analysis/modules/delegatecall.py
@@ -5,11 +5,11 @@ from mythril.analysis.report import Issue
import logging
-'''
+"""
MODULE DESCRIPTION:
Check for invocations of delegatecall(msg.data) in the fallback function.
-'''
+"""
def execute(statespace):
@@ -28,7 +28,7 @@ def execute(statespace):
continue
state = call.state
- address = state.get_current_instruction()['address']
+ address = state.get_current_instruction()["address"]
meminstart = get_variable(state.mstate.stack[-3])
if meminstart.type == VarType.CONCRETE:
@@ -41,17 +41,24 @@ def execute(statespace):
def _concrete_call(call, state, address, meminstart):
- if not re.search(r'calldata.*_0', str(state.mstate.memory[meminstart.val])):
+ if not re.search(r"calldata.*_0", str(state.mstate.memory[meminstart.val])):
return []
- issue = Issue(contract=call.node.contract_name, function=call.node.function_name, address=address,
- swc_id=DELEGATECALL_TO_UNTRUSTED_CONTRACT, title="Call data forwarded with delegatecall()",
- _type="Informational")
-
- issue.description = \
- "This contract forwards its call data via DELEGATECALL in its fallback function. " \
- "This means that any function in the called contract can be executed. Note that the callee contract will have " \
+ issue = Issue(
+ contract=call.node.contract_name,
+ function_name=call.node.function_name,
+ address=address,
+ swc_id=DELEGATECALL_TO_UNTRUSTED_CONTRACT,
+ bytecode=state.environment.code.bytecode,
+ title="Call data forwarded with delegatecall()",
+ _type="Informational",
+ )
+
+ issue.description = (
+ "This contract forwards its call data via DELEGATECALL in its fallback function. "
+ "This means that any function in the called contract can be executed. Note that the callee contract will have "
"access to the storage of the calling contract.\n "
+ )
target = hex(call.to.val) if call.to.type == VarType.CONCRETE else str(call.to)
issue.description += "DELEGATECALL target: {}".format(target)
@@ -60,23 +67,35 @@ def _concrete_call(call, state, address, meminstart):
def _symbolic_call(call, state, address, statespace):
- issue = Issue(contract=call.node.contract_name, function=call.node.function_name, address=address,
- swc_id=DELEGATECALL_TO_UNTRUSTED_CONTRACT, title=call.type + " to a user-supplied address")
+ issue = Issue(
+ contract=call.node.contract_name,
+ function_name=call.node.function_name,
+ address=address,
+ swc_id=DELEGATECALL_TO_UNTRUSTED_CONTRACT,
+ bytecode=state.environment.code.bytecode,
+ title=call.type + " to a user-supplied address",
+ )
if "calldata" in str(call.to):
- issue.description = \
- "This contract delegates execution to a contract address obtained from calldata. "
+ issue.description = "This contract delegates execution to a contract address obtained from calldata. "
else:
- m = re.search(r'storage_([a-z0-9_&^]+)', str(call.to))
+ m = re.search(r"storage_([a-z0-9_&^]+)", str(call.to))
if m:
idx = m.group(1)
- func = statespace.find_storage_write(state.environment.active_account.address, idx)
+ func = statespace.find_storage_write(
+ state.environment.active_account.address, idx
+ )
if func:
- issue.description = "This contract delegates execution to a contract address in storage slot " + str(
- idx) + ". This storage slot can be written to by calling the function `" + func + "`. "
+ issue.description = (
+ "This contract delegates execution to a contract address in storage slot "
+ + str(idx)
+ + ". This storage slot can be written to by calling the function `"
+ + func
+ + "`. "
+ )
else:
logging.debug("[DELEGATECALL] No storage writes to index " + str(idx))
diff --git a/mythril/analysis/modules/dependence_on_predictable_vars.py b/mythril/analysis/modules/dependence_on_predictable_vars.py
index 1e1085ab..d390c047 100644
--- a/mythril/analysis/modules/dependence_on_predictable_vars.py
+++ b/mythril/analysis/modules/dependence_on_predictable_vars.py
@@ -7,7 +7,7 @@ from mythril.analysis.swc_data import TIMESTAMP_DEPENDENCE, PREDICTABLE_VARS_DEP
from mythril.exceptions import UnsatError
import logging
-'''
+"""
MODULE DESCRIPTION:
Check for CALLs that send >0 Ether as a result of computation based on predictable variables such as
@@ -17,7 +17,7 @@ TODO:
- block.blockhash(block.number-1)
- block.blockhash(some_block_past_256_blocks_from_now)==0
- external source of random numbers (e.g. Oraclize)
-'''
+"""
def execute(statespace):
@@ -37,7 +37,7 @@ def execute(statespace):
if call.value.type == VarType.CONCRETE and call.value.val == 0:
continue
- address = call.state.get_current_instruction()['address']
+ address = call.state.get_current_instruction()["address"]
description = "In the function `" + call.node.function_name + "` "
description += "the following predictable state variables are used to determine Ether recipient:\n"
@@ -56,10 +56,21 @@ def execute(statespace):
for item in found:
description += "- block.{}\n".format(item)
if solve(call):
- swc_type = TIMESTAMP_DEPENDENCE if item == 'timestamp' else PREDICTABLE_VARS_DEPENDENCE
- issue = Issue(contract=call.node.contract_name, function=call.node.function_name, address=address,
- swc_id=swc_type, title="Dependence on predictable environment variable",
- _type="Warning", description=description)
+ swc_type = (
+ TIMESTAMP_DEPENDENCE
+ if item == "timestamp"
+ else PREDICTABLE_VARS_DEPENDENCE
+ )
+ issue = Issue(
+ contract=call.node.contract_name,
+ function_name=call.node.function_name,
+ address=address,
+ swc_id=swc_type,
+ bytecode=state.environment.code.bytecode,
+ title="Dependence on predictable environment variable",
+ _type="Warning",
+ description=description,
+ )
issues.append(issue)
# Second check: blockhash
@@ -68,48 +79,77 @@ def execute(statespace):
if "blockhash" in str(constraint):
description = "In the function `" + call.node.function_name + "` "
if "number" in str(constraint):
- m = re.search(r'blockhash\w+(\s-\s(\d+))*', str(constraint))
+ m = re.search(r"blockhash\w+(\s-\s(\d+))*", str(constraint))
if m and solve(call):
found = m.group(1)
if found: # block.blockhash(block.number - N)
- description += "predictable expression 'block.blockhash(block.number - " + m.group(2) + \
- ")' is used to determine Ether recipient"
+ description += (
+ "predictable expression 'block.blockhash(block.number - "
+ + m.group(2)
+ + ")' is used to determine Ether recipient"
+ )
if int(m.group(2)) > 255:
- description += ", this expression will always be equal to zero."
- elif "storage" in str(constraint): # block.blockhash(block.number - storage_0)
- description += "predictable expression 'block.blockhash(block.number - " + \
- "some_storage_var)' is used to determine Ether recipient"
+ description += (
+ ", this expression will always be equal to zero."
+ )
+ elif "storage" in str(
+ constraint
+ ): # block.blockhash(block.number - storage_0)
+ description += (
+ "predictable expression 'block.blockhash(block.number - "
+ + "some_storage_var)' is used to determine Ether recipient"
+ )
else: # block.blockhash(block.number)
- description += "predictable expression 'block.blockhash(block.number)'" + \
- " is used to determine Ether recipient"
- description += ", this expression will always be equal to zero."
-
- issue = Issue(contract=call.node.contract_name, function=call.node.function_name,
- address=address, title="Dependence on predictable variable",
- _type="Warning", description=description, swc_id=PREDICTABLE_VARS_DEPENDENCE)
+ description += (
+ "predictable expression 'block.blockhash(block.number)'"
+ + " is used to determine Ether recipient"
+ )
+ description += (
+ ", this expression will always be equal to zero."
+ )
+
+ issue = Issue(
+ contract=call.node.contract_name,
+ function_name=call.node.function_name,
+ address=address,
+ bytecode=call.state.environment.code.bytecode,
+ title="Dependence on predictable variable",
+ _type="Warning",
+ description=description,
+ swc_id=PREDICTABLE_VARS_DEPENDENCE,
+ )
issues.append(issue)
break
else:
- r = re.search(r'storage_([a-z0-9_&^]+)', str(constraint))
+ r = re.search(r"storage_([a-z0-9_&^]+)", str(constraint))
if r: # block.blockhash(storage_0)
- '''
+ """
We actually can do better here by adding a constraint blockhash_block_storage_0 == 0
and checking model satisfiability. When this is done, severity can be raised
from 'Informational' to 'Warning'.
Checking that storage at given index can be tainted is not necessary, since it usually contains
block.number of the 'commit' transaction in commit-reveal workflow.
- '''
+ """
index = r.group(1)
if index and solve(call):
- description += 'block.blockhash() is calculated using a value from storage ' \
- 'at index {}'.format(index)
- issue = Issue(contract=call.node.contract_name, function=call.node.function_name,
- address=address, title="Dependence on predictable variable",
- _type="Informational", description=description, swc_id=PREDICTABLE_VARS_DEPENDENCE)
+ description += (
+ "block.blockhash() is calculated using a value from storage "
+ "at index {}".format(index)
+ )
+ issue = Issue(
+ contract=call.node.contract_name,
+ function_name=call.node.function_name,
+ address=address,
+ bytecode=state.environment.code.bytecode,
+ title="Dependence on predictable variable",
+ _type="Informational",
+ description=description,
+ swc_id=PREDICTABLE_VARS_DEPENDENCE,
+ )
issues.append(issue)
break
return issues
@@ -121,7 +161,10 @@ def solve(call):
logging.debug("[DEPENDENCE_ON_PREDICTABLE_VARS] MODEL: " + str(model))
for decl in model.decls():
- logging.debug("[DEPENDENCE_ON_PREDICTABLE_VARS] main model: %s = 0x%x" % (decl.name(), model[decl].as_long()))
+ logging.debug(
+ "[DEPENDENCE_ON_PREDICTABLE_VARS] main model: %s = 0x%x"
+ % (decl.name(), model[decl].as_long())
+ )
return True
except UnsatError:
diff --git a/mythril/analysis/modules/deprecated_ops.py b/mythril/analysis/modules/deprecated_ops.py
index 2b187e2d..a5ffea2f 100644
--- a/mythril/analysis/modules/deprecated_ops.py
+++ b/mythril/analysis/modules/deprecated_ops.py
@@ -3,11 +3,11 @@ from mythril.analysis.swc_data import TX_ORIGIN_USAGE
import logging
-'''
+"""
MODULE DESCRIPTION:
Check for constraints on tx.origin (i.e., access to some functionality is restricted to a specific origin).
-'''
+"""
def execute(statespace):
@@ -23,14 +23,25 @@ def execute(statespace):
instruction = state.get_current_instruction()
- if instruction['opcode'] == "ORIGIN":
- description = "The function `{}` 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".format(node.function_name)
-
- issue = Issue(contract=node.contract_name, function=node.function_name, address=instruction['address'],
- title="Use of tx.origin", _type="Warning", swc_id=TX_ORIGIN_USAGE,
- description=description)
+ if instruction["opcode"] == "ORIGIN":
+ description = (
+ "The function `{}` 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".format(
+ node.function_name
+ )
+ )
+
+ issue = Issue(
+ contract=node.contract_name,
+ function_name=node.function_name,
+ address=instruction["address"],
+ title="Use of tx.origin",
+ bytecode=state.environment.code.bytecode,
+ _type="Warning",
+ swc_id=TX_ORIGIN_USAGE,
+ description=description,
+ )
issues.append(issue)
return issues
diff --git a/mythril/analysis/modules/ether_send.py b/mythril/analysis/modules/ether_send.py
index 00aac6a5..71131038 100644
--- a/mythril/analysis/modules/ether_send.py
+++ b/mythril/analysis/modules/ether_send.py
@@ -8,13 +8,13 @@ import re
import logging
-'''
+"""
MODULE DESCRIPTION:
Check for CALLs that send >0 Ether to either the transaction sender, or to an address provided as a function argument.
If msg.sender is checked against a value in storage, check whether that storage index is tainted (i.e. there's an unconstrained write
to that index).
-'''
+"""
def execute(statespace):
@@ -26,7 +26,7 @@ def execute(statespace):
for call in statespace.calls:
state = call.state
- address = state.get_current_instruction()['address']
+ address = state.get_current_instruction()["address"]
if "callvalue" in str(call.value):
logging.debug("[ETHER_SEND] Skipping refund function")
@@ -41,26 +41,38 @@ def execute(statespace):
description = "In the function `" + call.node.function_name + "` "
- if re.search(r'caller', str(call.to)):
+ if re.search(r"caller", str(call.to)):
description += "a non-zero amount of Ether is sent to msg.sender.\n"
interesting = True
- elif re.search(r'calldata', str(call.to)):
+ elif re.search(r"calldata", str(call.to)):
description += "a non-zero amount of Ether is sent to an address taken from function arguments.\n"
interesting = True
else:
- m = re.search(r'storage_([a-z0-9_&^]+)', str(call.to))
+ m = re.search(r"storage_([a-z0-9_&^]+)", str(call.to))
if m:
idx = m.group(1)
- description += "a non-zero amount of Ether is sent to an address taken from storage slot " + str(idx) + ".\n"
+ description += (
+ "a non-zero amount of Ether is sent to an address taken from storage slot "
+ + str(idx)
+ + ".\n"
+ )
- func = statespace.find_storage_write(state.environment.active_account.address, idx)
+ func = statespace.find_storage_write(
+ state.environment.active_account.address, idx
+ )
if func:
- description += "There is a check on storage index " + str(idx) + ". This storage slot can be written to by calling the function `" + func + "`.\n"
+ description += (
+ "There is a check on storage index "
+ + str(idx)
+ + ". This storage slot can be written to by calling the function `"
+ + func
+ + "`.\n"
+ )
interesting = True
else:
logging.debug("[ETHER_SEND] No storage writes to index " + str(idx))
@@ -80,31 +92,45 @@ def execute(statespace):
index += 1
logging.debug("[ETHER_SEND] Constraint: " + str(constraint))
- m = re.search(r'storage_([a-z0-9_&^]+)', str(constraint))
+ m = re.search(r"storage_([a-z0-9_&^]+)", str(constraint))
if m:
constrained = True
idx = m.group(1)
- func = statespace.find_storage_write(state.environment.active_account.address, idx)
+ func = statespace.find_storage_write(
+ state.environment.active_account.address, idx
+ )
if func:
- description += "\nThere is a check on storage index " + str(idx) + ". This storage slot can be written to by calling the function `" + func + "`."
+ description += (
+ "\nThere is a check on storage index "
+ + str(idx)
+ + ". This storage slot can be written to by calling the function `"
+ + func
+ + "`."
+ )
else:
- logging.debug("[ETHER_SEND] No storage writes to index " + str(idx))
+ logging.debug(
+ "[ETHER_SEND] No storage writes to index " + str(idx)
+ )
can_solve = False
break
# CALLER may also be constrained to hardcoded address. I.e. 'caller' and some integer
- elif re.search(r"caller", str(constraint)) and re.search(r'[0-9]{20}', str(constraint)):
+ elif re.search(r"caller", str(constraint)) and re.search(
+ r"[0-9]{20}", str(constraint)
+ ):
constrained = True
can_solve = False
break
if not constrained:
- description += "It seems that this function can be called without restrictions."
+ description += (
+ "It seems that this function can be called without restrictions."
+ )
if can_solve:
@@ -112,13 +138,24 @@ def execute(statespace):
model = solver.get_model(node.constraints)
for decl in model.decls():
- logging.debug("[ETHER_SEND] main model: %s = 0x%x" % (decl.name(), model[decl].as_long()))
+ logging.debug(
+ "[ETHER_SEND] main model: %s = 0x%x"
+ % (decl.name(), model[decl].as_long())
+ )
debug = "SOLVER OUTPUT:\n" + solver.pretty_print_model(model)
- issue = Issue(contract=call.node.contract_name, function=call.node.function_name, address=address,
- title="Ether send", _type="Warning", swc_id=UNPROTECTED_ETHER_WITHDRAWAL,
- description=description, debug=debug)
+ issue = Issue(
+ contract=call.node.contract_name,
+ function_name=call.node.function_name,
+ address=address,
+ title="Ether send",
+ _type="Warning",
+ swc_id=UNPROTECTED_ETHER_WITHDRAWAL,
+ description=description,
+ bytecode=state.environment.code.bytecode,
+ debug=debug,
+ )
issues.append(issue)
except UnsatError:
diff --git a/mythril/analysis/modules/exceptions.py b/mythril/analysis/modules/exceptions.py
index ac0723e0..d27e1729 100644
--- a/mythril/analysis/modules/exceptions.py
+++ b/mythril/analysis/modules/exceptions.py
@@ -5,12 +5,12 @@ from mythril.analysis import solver
import logging
-'''
+"""
MODULE DESCRIPTION:
Checks whether any exception states are reachable.
-'''
+"""
def execute(statespace):
@@ -25,25 +25,41 @@ def execute(statespace):
for state in node.states:
instruction = state.get_current_instruction()
- if instruction['opcode'] == "ASSERT_FAIL":
+ if instruction["opcode"] == "ASSERT_FAIL":
try:
model = solver.get_model(node.constraints)
- address = state.get_current_instruction()['address']
-
- 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. "
- description += "This is acceptable in most situations. " \
- "Note however that `assert()` should only be used to check invariants. " \
- "Use `require()` for regular input checking. "
-
- debug = "The exception is triggered under the following conditions:\n\n"
+ address = state.get_current_instruction()["address"]
+
+ 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. "
+ )
+ description += (
+ "This is acceptable in most situations. "
+ "Note however that `assert()` should only be used to check invariants. "
+ "Use `require()` for regular input checking. "
+ )
+
+ debug = (
+ "The exception is triggered under the following conditions:\n\n"
+ )
debug += solver.pretty_print_model(model)
- issues.append(Issue(contract=node.contract_name, function=node.function_name, address=address,
- swc_id=ASSERT_VIOLATION, title="Exception state", _type="Informational",
- description=description, debug=debug))
+ issues.append(
+ Issue(
+ contract=node.contract_name,
+ function_name=node.function_name,
+ address=address,
+ swc_id=ASSERT_VIOLATION,
+ title="Exception state",
+ _type="Informational",
+ description=description,
+ bytecode=state.environment.code.bytecode,
+ debug=debug,
+ )
+ )
except UnsatError:
logging.debug("[EXCEPTIONS] no model found")
diff --git a/mythril/analysis/modules/external_calls.py b/mythril/analysis/modules/external_calls.py
index 2f9350af..d85fe45a 100644
--- a/mythril/analysis/modules/external_calls.py
+++ b/mythril/analysis/modules/external_calls.py
@@ -7,11 +7,11 @@ import re
import logging
-'''
+"""
MODULE DESCRIPTION:
Check for call.value()() to external addresses
-'''
+"""
MAX_SEARCH_DEPTH = 64
@@ -28,8 +28,8 @@ def search_children(statespace, node, start_index=0, depth=0, results=None):
if n_states > start_index:
for j in range(start_index, n_states):
- if node.states[j].get_current_instruction()['opcode'] == 'SSTORE':
- results.append(node.states[j].get_current_instruction()['address'])
+ if node.states[j].get_current_instruction()["opcode"] == "SSTORE":
+ results.append(node.states[j].get_current_instruction()["address"])
children = []
@@ -39,7 +39,9 @@ def search_children(statespace, node, start_index=0, depth=0, results=None):
if len(children):
for node in children:
- return search_children(statespace, node, depth=depth + 1, results=results)
+ return search_children(
+ statespace, node, depth=depth + 1, results=results
+ )
return results
@@ -54,13 +56,20 @@ def execute(statespace):
for call in statespace.calls:
state = call.state
- address = state.get_current_instruction()['address']
+ address = state.get_current_instruction()["address"]
if call.type == "CALL":
- logging.info("[EXTERNAL_CALLS] Call to: %s, value = %s, gas = %s" % (str(call.to), str(call.value), str(call.gas)))
+ logging.info(
+ "[EXTERNAL_CALLS] Call to: %s, value = %s, gas = %s"
+ % (str(call.to), str(call.value), str(call.gas))
+ )
- if call.to.type == VarType.SYMBOLIC and (call.gas.type == VarType.CONCRETE and call.gas.val > 2300) or (call.gas.type == VarType.SYMBOLIC and "2300" not in str(call.gas)):
+ if (
+ call.to.type == VarType.SYMBOLIC
+ and (call.gas.type == VarType.CONCRETE and call.gas.val > 2300)
+ or (call.gas.type == VarType.SYMBOLIC and "2300" not in str(call.gas))
+ ):
description = "This contract executes a message call to "
@@ -76,59 +85,99 @@ def execute(statespace):
user_supplied = True
else:
- m = re.search(r'storage_([a-z0-9_&^]+)', str(call.to))
+ m = re.search(r"storage_([a-z0-9_&^]+)", str(call.to))
if m:
idx = m.group(1)
- func = statespace.find_storage_write(state.environment.active_account.address, idx)
+ func = statespace.find_storage_write(
+ state.environment.active_account.address, idx
+ )
if func:
- description += \
- "an address found at storage slot " + str(idx) + ". " + \
- "This storage slot can be written to by calling the function `" + func + "`. "
+ description += (
+ "an address found at storage slot "
+ + str(idx)
+ + ". "
+ + "This storage slot can be written to by calling the function `"
+ + func
+ + "`. "
+ )
user_supplied = True
if user_supplied:
- description += "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."
-
- issue = Issue(contract=call.node.contract_name, function=call.node.function_name,
- address=address, title="Message call to external contract", _type="Warning",
- description=description, swc_id=REENTRANCY)
+ description += (
+ "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."
+ )
+
+ issue = Issue(
+ contract=call.node.contract_name,
+ function_name=call.node.function_name,
+ address=address,
+ title="Message call to external contract",
+ _type="Warning",
+ description=description,
+ bytecode=state.environment.code.bytecode,
+ swc_id=REENTRANCY,
+ )
else:
description += "to another contract. Make sure that the called contract is trusted and does not execute user-supplied code."
- issue = Issue(contract=call.node.contract_name, function=call.node.function_name, address=address,
- title="Message call to external contract", _type="Informational",
- description=description, swc_id=REENTRANCY)
+ issue = Issue(
+ contract=call.node.contract_name,
+ function_name=call.node.function_name,
+ address=address,
+ title="Message call to external contract",
+ _type="Informational",
+ description=description,
+ bytecode=state.environment.code.bytecode,
+ swc_id=REENTRANCY,
+ )
issues.append(issue)
if address not in calls_visited:
calls_visited.append(address)
- logging.debug("[EXTERNAL_CALLS] Checking for state changes starting from " + call.node.function_name)
+ logging.debug(
+ "[EXTERNAL_CALLS] Checking for state changes starting from "
+ + call.node.function_name
+ )
# Check for SSTORE in remaining instructions in current node & nodes down the CFG
- state_change_addresses = search_children(statespace, call.node, call.state_index + 1, depth=0, results=[])
+ state_change_addresses = search_children(
+ statespace, call.node, call.state_index + 1, depth=0, results=[]
+ )
- logging.debug("[EXTERNAL_CALLS] Detected state changes at addresses: " + str(state_change_addresses))
+ logging.debug(
+ "[EXTERNAL_CALLS] Detected state changes at addresses: "
+ + str(state_change_addresses)
+ )
if len(state_change_addresses):
for address in state_change_addresses:
- 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."
-
- issue = Issue(contract=call.node.contract_name, function=call.node.function_name,
- address=address, title="State change after external call", _type="Warning",
- description=description, swc_id=REENTRANCY)
+ 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."
+ )
+
+ issue = Issue(
+ contract=call.node.contract_name,
+ function_name=call.node.function_name,
+ address=address,
+ title="State change after external call",
+ _type="Warning",
+ description=description,
+ bytecode=state.environment.code.bytecode,
+ swc_id=REENTRANCY,
+ )
issues.append(issue)
return issues
diff --git a/mythril/analysis/modules/integer.py b/mythril/analysis/modules/integer.py
index 48707c11..3b373926 100644
--- a/mythril/analysis/modules/integer.py
+++ b/mythril/analysis/modules/integer.py
@@ -9,13 +9,13 @@ import re
import copy
import logging
-'''
+"""
MODULE DESCRIPTION:
Check for integer underflows.
For every SUB instruction, check if there's a possible state where op1 > op0.
For every ADD, MUL instruction, check if there's a possible state where op1 + op0 > 2^32 - 1
-'''
+"""
def execute(statespace):
@@ -50,7 +50,7 @@ def _check_integer_overflow(statespace, state, node):
# Check the instruction
instruction = state.get_current_instruction()
- if instruction['opcode'] not in ("ADD", "MUL"):
+ if instruction["opcode"] not in ("ADD", "MUL"):
return issues
# Formulate overflow constraints
@@ -70,7 +70,7 @@ def _check_integer_overflow(statespace, state, node):
op1 = BitVecVal(op1, 256)
# Formulate expression
- if instruction['opcode'] == "ADD":
+ if instruction["opcode"] == "ADD":
expr = op0 + op1
else:
expr = op1 * op0
@@ -83,27 +83,43 @@ def _check_integer_overflow(statespace, state, node):
logging.debug("[INTEGER_OVERFLOW] no model found")
return issues
- if not _verify_integer_overflow(statespace, node, expr, state, model, constraint, op0, op1):
+ if not _verify_integer_overflow(
+ statespace, node, expr, state, model, constraint, op0, op1
+ ):
return issues
# Build issue
- issue = Issue(contract=node.contract_name, function=node.function_name, address=instruction['address'],
- swc_id=INTEGER_OVERFLOW_AND_UNDERFLOW, title="Integer Overflow", _type="Warning")
-
- issue.description = "A possible integer overflow exists in the function `{}`.\n" \
- "The addition or multiplication may result in a value higher than the maximum representable integer.".format(
- node.function_name)
+ issue = Issue(
+ contract=node.contract_name,
+ function_name=node.function_name,
+ address=instruction["address"],
+ swc_id=INTEGER_OVERFLOW_AND_UNDERFLOW,
+ bytecode=state.environment.code.bytecode,
+ title="Integer Overflow",
+ _type="Warning",
+ )
+
+ issue.description = (
+ "A possible integer overflow exists in the function `{}`.\n"
+ "The addition or multiplication may result in a value higher than the maximum representable integer.".format(
+ node.function_name
+ )
+ )
issue.debug = solver.pretty_print_model(model)
issues.append(issue)
return issues
-def _verify_integer_overflow(statespace, node, expr, state, model, constraint, op0, op1):
+def _verify_integer_overflow(
+ statespace, node, expr, state, model, constraint, op0, op1
+):
""" Verifies existence of integer overflow """
# If we get to this point then there has been an integer overflow
# Find out if the overflowed value is actually used
- interesting_usages = _search_children(statespace, node, expr, constraint=[constraint], index=node.states.index(state))
+ interesting_usages = _search_children(
+ statespace, node, expr, constraint=[constraint], index=node.states.index(state)
+ )
# Stop if it isn't
if len(interesting_usages) == 0:
@@ -111,6 +127,7 @@ def _verify_integer_overflow(statespace, node, expr, state, model, constraint, o
return _try_constraints(node.constraints, [Not(constraint)]) is not None
+
def _try_constraints(constraints, new_constraints):
"""
Tries new constraints
@@ -135,7 +152,7 @@ def _check_integer_underflow(statespace, state, node):
"""
issues = []
instruction = state.get_current_instruction()
- if instruction['opcode'] == "SUB":
+ if instruction["opcode"] == "SUB":
stack = state.mstate.stack
@@ -150,15 +167,22 @@ def _check_integer_underflow(statespace, state, node):
# Pattern 2: (256*If(1 & storage_0 == 0, 1, 0)) - 1, this would underlow if storage_0 = 0
if type(op0) == int and type(op1) == int:
return []
- if re.search(r'calldatasize_', str(op0)):
+ if re.search(r"calldatasize_", str(op0)):
return []
- if re.search(r'256\*.*If\(1', str(op0), re.DOTALL) or re.search(r'256\*.*If\(1', str(op1), re.DOTALL):
+ if re.search(r"256\*.*If\(1", str(op0), re.DOTALL) or re.search(
+ r"256\*.*If\(1", str(op1), re.DOTALL
+ ):
return []
- if re.search(r'32 \+.*calldata', str(op0), re.DOTALL) or re.search(r'32 \+.*calldata', str(op1), re.DOTALL):
+ if re.search(r"32 \+.*calldata", str(op0), re.DOTALL) or re.search(
+ r"32 \+.*calldata", str(op1), re.DOTALL
+ ):
return []
- logging.debug("[INTEGER_UNDERFLOW] Checking SUB {0}, {1} at address {2}".format(str(op0), str(op1),
- str(instruction['address'])))
+ logging.debug(
+ "[INTEGER_UNDERFLOW] Checking SUB {0}, {1} at address {2}".format(
+ str(op0), str(op1), str(instruction["address"])
+ )
+ )
allowed_types = [int, BitVecRef, BitVecNumRef]
if type(op0) in allowed_types and type(op1) in allowed_types:
@@ -170,17 +194,30 @@ def _check_integer_underflow(statespace, state, node):
# If we get to this point then there has been an integer overflow
# Find out if the overflowed value is actually used
- interesting_usages = _search_children(statespace, node, (op0 - op1), index=node.states.index(state))
+ interesting_usages = _search_children(
+ statespace, node, (op0 - op1), index=node.states.index(state)
+ )
# Stop if it isn't
if len(interesting_usages) == 0:
return issues
- issue = Issue(contract=node.contract_name, function=node.function_name, address=instruction['address'],
- swc_id=INTEGER_OVERFLOW_AND_UNDERFLOW, title="Integer Underflow", _type="Warning")
-
- issue.description = "A possible integer underflow exists in the function `" + node.function_name + "`.\n" \
- "The subtraction may result in a value < 0."
+ issue = Issue(
+ contract=node.contract_name,
+ function_name=node.function_name,
+ address=instruction["address"],
+ swc_id=INTEGER_OVERFLOW_AND_UNDERFLOW,
+ bytecode=state.environment.code.bytecode,
+ title="Integer Underflow",
+ _type="Warning",
+ )
+
+ issue.description = (
+ "A possible integer underflow exists in the function `"
+ + node.function_name
+ + "`.\n"
+ "The subtraction may result in a value < 0."
+ )
issue.debug = solver.pretty_print_model(model)
issues.append(issue)
@@ -192,29 +229,39 @@ def _check_integer_underflow(statespace, state, node):
def _check_usage(state, taint_result):
"""Delegates checks to _check_{instruction_name}()"""
- opcode = state.get_current_instruction()['opcode']
+ opcode = state.get_current_instruction()["opcode"]
- if opcode == 'JUMPI':
+ if opcode == "JUMPI":
if _check_jumpi(state, taint_result):
return [state]
- elif opcode == 'SSTORE':
+ elif opcode == "SSTORE":
if _check_sstore(state, taint_result):
return [state]
return []
+
def _check_jumpi(state, taint_result):
""" Check if conditional jump is dependent on the result of expression"""
- assert state.get_current_instruction()['opcode'] == 'JUMPI'
+ assert state.get_current_instruction()["opcode"] == "JUMPI"
return taint_result.check(state, -2)
def _check_sstore(state, taint_result):
""" Check if store operation is dependent on the result of expression"""
- assert state.get_current_instruction()['opcode'] == 'SSTORE'
+ assert state.get_current_instruction()["opcode"] == "SSTORE"
return taint_result.check(state, -2)
-def _search_children(statespace, node, expression, taint_result=None, constraint=None, index=0, depth=0, max_depth=64):
+def _search_children(
+ statespace,
+ node,
+ expression,
+ taint_result=None,
+ constraint=None,
+ index=0,
+ depth=0,
+ max_depth=64,
+):
"""
Checks the statespace for children states, with JUMPI or SSTORE instuctions,
for dependency on expression
@@ -236,7 +283,9 @@ def _search_children(statespace, node, expression, taint_result=None, constraint
state = node.states[index]
taint_stack = [False for _ in state.mstate.stack]
taint_stack[-1] = True
- taint_result = TaintRunner.execute(statespace, node, state, initial_stack=taint_stack)
+ taint_result = TaintRunner.execute(
+ statespace, node, state, initial_stack=taint_stack
+ )
results = []
@@ -247,25 +296,31 @@ def _search_children(statespace, node, expression, taint_result=None, constraint
for j in range(index, len(node.states)):
current_state = node.states[j]
current_instruction = current_state.get_current_instruction()
- if current_instruction['opcode'] in ('JUMPI', 'SSTORE'):
+ if current_instruction["opcode"] in ("JUMPI", "SSTORE"):
element = _check_usage(current_state, taint_result)
if len(element) < 1:
continue
if _check_requires(element[0], node, statespace, constraint):
- continue
+ continue
results += element
# Recursively search children
- children = \
- [
- statespace.nodes[edge.node_to]
- for edge in statespace.edges
- if edge.node_from == node.uid
- # and _try_constraints(statespace.nodes[edge.node_to].constraints, constraint) is not None
- ]
+ children = [
+ statespace.nodes[edge.node_to]
+ for edge in statespace.edges
+ if edge.node_from == node.uid
+ # and _try_constraints(statespace.nodes[edge.node_to].constraints, constraint) is not None
+ ]
for child in children:
- results += _search_children(statespace, child, expression, taint_result, depth=depth + 1, max_depth=max_depth)
+ results += _search_children(
+ statespace,
+ child,
+ expression,
+ taint_result,
+ depth=depth + 1,
+ max_depth=max_depth,
+ )
return results
@@ -273,16 +328,16 @@ def _search_children(statespace, node, expression, taint_result=None, constraint
def _check_requires(state, node, statespace, constraint):
"""Checks if usage of overflowed statement results in a revert statement"""
instruction = state.get_current_instruction()
- if instruction['opcode'] is not "JUMPI":
+ if instruction["opcode"] is not "JUMPI":
return False
children = [
- statespace.nodes[edge.node_to]
- for edge in statespace.edges
- if edge.node_from == node.uid
- ]
+ statespace.nodes[edge.node_to]
+ for edge in statespace.edges
+ if edge.node_from == node.uid
+ ]
for child in children:
- opcodes = [s.get_current_instruction()['opcode'] for s in child.states]
+ opcodes = [s.get_current_instruction()["opcode"] for s in child.states]
if "REVERT" in opcodes or "ASSERT_FAIL" in opcodes:
return True
# I added the following case, bc of false positives if the max depth is not high enough
diff --git a/mythril/analysis/modules/multiple_sends.py b/mythril/analysis/modules/multiple_sends.py
index baaea896..a53e20b5 100644
--- a/mythril/analysis/modules/multiple_sends.py
+++ b/mythril/analysis/modules/multiple_sends.py
@@ -1,6 +1,7 @@
from mythril.analysis.report import Issue
from mythril.analysis.swc_data import *
from mythril.laser.ethereum.cfg import JumpType
+
"""
MODULE DESCRIPTION:
@@ -21,16 +22,25 @@ def execute(statespace):
if len(findings) > 0:
node = call.node
instruction = call.state.get_current_instruction()
- issue = Issue(contract=node.contract_name, function=node.function_name, address=instruction['address'],
- swc_id=MULTIPLE_SENDS, title="Multiple Calls", _type="Informational")
-
- issue.description = \
- "Multiple sends exist in one transaction. Try to isolate each external call into its own transaction," \
+ issue = Issue(
+ contract=node.contract_name,
+ function_name=node.function_name,
+ address=instruction["address"],
+ swc_id=MULTIPLE_SENDS,
+ bytecode=call.state.environment.code.bytecode,
+ title="Multiple Calls",
+ _type="Informational",
+ )
+
+ issue.description = (
+ "Multiple sends exist in one transaction. Try to isolate each external call into its own transaction,"
" as external calls can fail accidentally or deliberately.\nConsecutive calls: \n"
+ )
for finding in findings:
- issue.description += \
- "Call at address: {}\n".format(finding.state.get_current_instruction()['address'])
+ issue.description += "Call at address: {}\n".format(
+ finding.state.get_current_instruction()["address"]
+ )
issues.append(issue)
return issues
@@ -44,15 +54,22 @@ def _explore_nodes(call, statespace):
def _explore_states(call, statespace):
other_calls = list(
- filter(lambda other: other.node == call.node and other.state_index > call.state_index, statespace.calls)
+ filter(
+ lambda other: other.node == call.node
+ and other.state_index > call.state_index,
+ statespace.calls,
)
+ )
return other_calls
def _child_nodes(statespace, node):
result = []
- children = [statespace.nodes[edge.node_to] for edge in statespace.edges if edge.node_from == node.uid
- and edge.type != JumpType.Transaction]
+ children = [
+ statespace.nodes[edge.node_to]
+ for edge in statespace.edges
+ if edge.node_from == node.uid and edge.type != JumpType.Transaction
+ ]
for child in children:
result.append(child)
diff --git a/mythril/analysis/modules/suicide.py b/mythril/analysis/modules/suicide.py
index e2185fe5..0d1b4859 100644
--- a/mythril/analysis/modules/suicide.py
+++ b/mythril/analysis/modules/suicide.py
@@ -6,12 +6,12 @@ from mythril.exceptions import UnsatError
import logging
-'''
+"""
MODULE DESCRIPTION:
Check for SUICIDE instructions that either can be reached by anyone, or where msg.sender is checked against a tainted storage index
(i.e. there's a write to that index is unconstrained by msg.sender).
-'''
+"""
def execute(state_space):
@@ -33,13 +33,15 @@ def _analyze_state(state, node):
issues = []
instruction = state.get_current_instruction()
- if instruction['opcode'] != "SUICIDE":
+ if instruction["opcode"] != "SUICIDE":
return []
to = state.mstate.stack[-1]
logging.debug("[UNCHECKED_SUICIDE] suicide in function " + node.function_name)
- description = "The function `" + node.function_name + "` executes the SUICIDE instruction. "
+ description = (
+ "The function `" + node.function_name + "` executes the SUICIDE instruction. "
+ )
if "caller" in str(to):
description += "The remaining Ether is sent to the caller's address.\n"
@@ -56,19 +58,31 @@ def _analyze_state(state, node):
if len(state.world_state.transaction_sequence) > 1:
creator = state.world_state.transaction_sequence[0].caller
for transaction in state.world_state.transaction_sequence[1:]:
- not_creator_constraints.append(Not(Extract(159, 0, transaction.caller) == Extract(159, 0, creator)))
- not_creator_constraints.append(Not(Extract(159, 0, transaction.caller) == 0))
+ not_creator_constraints.append(
+ Not(Extract(159, 0, transaction.caller) == Extract(159, 0, creator))
+ )
+ not_creator_constraints.append(
+ Not(Extract(159, 0, transaction.caller) == 0)
+ )
try:
model = solver.get_model(node.constraints + not_creator_constraints)
debug = "SOLVER OUTPUT:\n" + solver.pretty_print_model(model)
- issue = Issue(contract=node.contract_name, function=node.function_name, address=instruction['address'],
- swc_id=UNPROTECTED_SELFDESTRUCT, title="Unchecked SUICIDE", _type="Warning",
- description=description, debug=debug)
+ issue = Issue(
+ contract=node.contract_name,
+ function_name=node.function_name,
+ address=instruction["address"],
+ swc_id=UNPROTECTED_SELFDESTRUCT,
+ bytecode=state.environment.code.bytecode,
+ title="Unchecked SUICIDE",
+ _type="Warning",
+ description=description,
+ debug=debug,
+ )
issues.append(issue)
except UnsatError:
- logging.debug("[UNCHECKED_SUICIDE] no model found")
+ logging.debug("[UNCHECKED_SUICIDE] no model found")
return issues
diff --git a/mythril/analysis/modules/transaction_order_dependence.py b/mythril/analysis/modules/transaction_order_dependence.py
index f6621293..bd6a36f8 100644
--- a/mythril/analysis/modules/transaction_order_dependence.py
+++ b/mythril/analysis/modules/transaction_order_dependence.py
@@ -7,12 +7,12 @@ from mythril.analysis.report import Issue
from mythril.analysis.swc_data import TX_ORDER_DEPENDENCE
from mythril.exceptions import UnsatError
-'''
+"""
MODULE DESCRIPTION:
This module finds the existance of transaction order dependence vulnerabilities.
The following webpage contains an extensive description of the vulnerability:
https://consensys.github.io/smart-contract-best-practices/known_attacks/#transaction-ordering-dependence-tod-front-running
-'''
+"""
def execute(statespace):
@@ -24,19 +24,30 @@ def execute(statespace):
for call in statespace.calls:
# Do analysis
interesting_storages = list(_get_influencing_storages(call))
- changing_sstores = list(_get_influencing_sstores(statespace, interesting_storages))
+ changing_sstores = list(
+ _get_influencing_sstores(statespace, interesting_storages)
+ )
# Build issue if necessary
if len(changing_sstores) > 0:
node = call.node
instruction = call.state.get_current_instruction()
- issue = Issue(contract=node.contract_name, function=node.function_name, address=instruction['address'],
- title="Transaction order dependence", swc_id=TX_ORDER_DEPENDENCE, _type="Warning")
-
- issue.description = \
- "A possible transaction order dependence vulnerability exists in function {}. The value or " \
- "direction of the call statement is determined from a tainted storage location"\
- .format(node.function_name)
+ issue = Issue(
+ contract=node.contract_name,
+ function_name=node.function_name,
+ address=instruction["address"],
+ title="Transaction order dependence",
+ bytecode=call.state.environment.code.bytecode,
+ swc_id=TX_ORDER_DEPENDENCE,
+ _type="Warning",
+ )
+
+ issue.description = (
+ "A possible transaction order dependence vulnerability exists in function {}. The value or "
+ "direction of the call statement is determined from a tainted storage location".format(
+ node.function_name
+ )
+ )
issues.append(issue)
return issues
@@ -65,7 +76,7 @@ def _get_storage_variable(storage, state):
:param state: state to retrieve the variable from
:return: z3 object representing storage
"""
- index = int(re.search('[0-9]+', storage).group())
+ index = int(re.search("[0-9]+", storage).group())
try:
return state.environment.active_account.storage[index]
except KeyError:
@@ -85,6 +96,7 @@ def _can_change(constraints, variable):
except AttributeError:
return False
+
def _get_influencing_storages(call):
""" Examines a Call object and returns an iterator of all storages that influence the call value or direction"""
state = call.state
@@ -108,7 +120,7 @@ def _get_influencing_storages(call):
def _get_influencing_sstores(statespace, interesting_storages):
""" Gets sstore (state, node) tuples that write to interesting_storages"""
- for sstore_state, node in _get_states_with_opcode(statespace, 'SSTORE'):
+ for sstore_state, node in _get_states_with_opcode(statespace, "SSTORE"):
index, value = sstore_state.mstate.stack[-1], sstore_state.mstate.stack[-2]
try:
index = util.get_concrete_int(index)
diff --git a/mythril/analysis/modules/unchecked_retval.py b/mythril/analysis/modules/unchecked_retval.py
index 5ee2b327..4d912fef 100644
--- a/mythril/analysis/modules/unchecked_retval.py
+++ b/mythril/analysis/modules/unchecked_retval.py
@@ -6,7 +6,7 @@ import logging
import re
-'''
+"""
MODULE DESCRIPTION:
Test whether CALL return value is checked.
@@ -22,7 +22,7 @@ For low-level-calls this check is omitted. E.g.:
c.call.value(0)(bytes4(sha3("ping(uint256)")),1);
-'''
+"""
def execute(statespace):
@@ -43,19 +43,27 @@ def execute(statespace):
instr = state.get_current_instruction()
- if instr['opcode'] == 'ISZERO' and re.search(r'retval', str(state.mstate.stack[-1])):
+ if instr["opcode"] == "ISZERO" and re.search(
+ r"retval", str(state.mstate.stack[-1])
+ ):
retval_checked = True
break
if not retval_checked:
- address = state.get_current_instruction()['address']
- issue = Issue(contract=node.contract_name, function=node.function_name, address=address,
- title="Unchecked CALL return value", swc_id=UNCHECKED_RET_VAL)
-
- issue.description = \
- "The return value of an external call is not checked. " \
+ address = state.get_current_instruction()["address"]
+ issue = Issue(
+ contract=node.contract_name,
+ function_name=node.function_name,
+ address=address,
+ title="Unchecked CALL return value",
+ swc_id=UNCHECKED_RET_VAL,
+ )
+
+ issue.description = (
+ "The return value of an external call is not checked. "
"Note that execution continue even if the called contract throws."
+ )
issues.append(issue)
@@ -63,12 +71,14 @@ def execute(statespace):
n_states = len(node.states)
- for idx in range(0, n_states - 1): # Ignore CALLs at last position in a node
+ for idx in range(
+ 0, n_states - 1
+ ): # Ignore CALLs at last position in a node
state = node.states[idx]
instr = state.get_current_instruction()
- if instr['opcode'] == 'CALL':
+ if instr["opcode"] == "CALL":
retval_checked = False
@@ -78,7 +88,9 @@ def execute(statespace):
_state = node.states[_idx]
_instr = _state.get_current_instruction()
- if _instr['opcode'] == 'ISZERO' and re.search(r'retval', str(_state .mstate.stack[-1])):
+ if _instr["opcode"] == "ISZERO" and re.search(
+ r"retval", str(_state.mstate.stack[-1])
+ ):
retval_checked = True
break
@@ -87,13 +99,20 @@ def execute(statespace):
if not retval_checked:
- address = instr['address']
- issue = Issue(contract=node.contract_name, function=node.function_name,
- address=address, title="Unchecked CALL return value", swc_id=UNCHECKED_RET_VAL)
-
- issue.description = \
- "The return value of an external call is not checked. " \
+ address = instr["address"]
+ issue = Issue(
+ contract=node.contract_name,
+ function_name=node.function_name,
+ bytecode=state.environment.code.bytecode,
+ address=address,
+ title="Unchecked CALL return value",
+ swc_id=UNCHECKED_RET_VAL,
+ )
+
+ issue.description = (
+ "The return value of an external call is not checked. "
"Note that execution continue even if the called contract throws."
+ )
issues.append(issue)
diff --git a/mythril/analysis/report.py b/mythril/analysis/report.py
index a6cfd59d..e4443cfa 100644
--- a/mythril/analysis/report.py
+++ b/mythril/analysis/report.py
@@ -1,16 +1,27 @@
-import hashlib
+import logging
import json
import operator
from jinja2 import PackageLoader, Environment
+import hashlib
class Issue:
-
- def __init__(self, contract, function, address, swc_id, title, _type="Informational", description="", debug=""):
+ def __init__(
+ self,
+ contract,
+ function_name,
+ address,
+ swc_id,
+ title,
+ bytecode,
+ _type="Informational",
+ description="",
+ debug="",
+ ):
self.title = title
self.contract = contract
- self.function = function
+ self.function = function_name
self.address = address
self.description = description
self.type = _type
@@ -20,32 +31,51 @@ class Issue:
self.code = None
self.lineno = None
+ try:
+ s = hashlib.sha3_256()
+ s.update(bytes.fromhex(bytecode))
+ self.bytecode_hash = "0x" + s.hexdigest()
+ except ValueError:
+ logging.debug("Unable to change the bytecode to bytes. Bytecode: {}".format(bytecode))
+ self.bytecode_hash = ""
@property
def as_dict(self):
- issue = {'title': self.title, 'swc_id': self.swc_id, 'contract': self.contract, 'description': self.description,
- 'function': self.function, 'type': self.type, 'address': self.address, 'debug': self.debug}
+ issue = {
+ "title": self.title,
+ "swc_id": self.swc_id,
+ "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
- issue['lineno'] = self.lineno
+ issue["filename"] = self.filename
+ issue["lineno"] = self.lineno
if self.code:
- issue['code'] = self.code
+ issue["code"] = self.code
return issue
def add_code_info(self, contract):
if self.address:
- codeinfo = contract.get_source_info(self.address, constructor=(self.function == 'constructor'))
+ codeinfo = contract.get_source_info(
+ self.address, constructor=(self.function == "constructor")
+ )
self.filename = codeinfo.filename
self.code = codeinfo.code
self.lineno = codeinfo.lineno
class Report:
- environment = Environment(loader=PackageLoader('mythril.analysis'), trim_blocks=True)
+ environment = Environment(
+ loader=PackageLoader("mythril.analysis"), trim_blocks=True
+ )
def __init__(self, verbose=False):
self.issues = {}
@@ -54,26 +84,44 @@ class Report:
def sorted_issues(self):
issue_list = [issue.as_dict for key, issue in self.issues.items()]
- return sorted(issue_list, key=operator.itemgetter('address', 'title'))
+ return sorted(issue_list, key=operator.itemgetter("address", "title"))
def append_issue(self, issue):
m = hashlib.md5()
- m.update((issue.contract + str(issue.address) + issue.title).encode('utf-8'))
+ m.update((issue.contract + str(issue.address) + issue.title).encode("utf-8"))
self.issues[m.digest()] = issue
def as_text(self):
name = self._file_name()
- template = Report.environment.get_template('report_as_text.jinja2')
- return template.render(filename=name, issues=self.sorted_issues(), verbose=self.verbose)
+ template = Report.environment.get_template("report_as_text.jinja2")
+ return template.render(
+ filename=name, issues=self.sorted_issues(), verbose=self.verbose
+ )
def as_json(self):
- result = {'success': True, 'error': None, 'issues': self.sorted_issues()}
+ result = {"success": True, "error": None, "issues": self.sorted_issues()}
+ return json.dumps(result, sort_keys=True)
+
+ def as_swc_standard_format(self):
+ """ Format defined for integration and correlation"""
+ result = {
+ "issues": [
+ {
+ "swc-id": "SWC-{}".format(issue.swc_id),
+ "bytecodeOffset": issue.address,
+ "codeHash": issue.bytecode_hash,
+ }
+ for issue in self.issues.values()
+ ]
+ }
return json.dumps(result, sort_keys=True)
def as_markdown(self):
filename = self._file_name()
- template = Report.environment.get_template('report_as_markdown.jinja2')
- return template.render(filename=filename, issues=self.sorted_issues(), verbose=self.verbose)
+ template = Report.environment.get_template("report_as_markdown.jinja2")
+ return template.render(
+ filename=filename, issues=self.sorted_issues(), verbose=self.verbose
+ )
def _file_name(self):
if len(self.issues.values()) > 0:
diff --git a/mythril/interfaces/cli.py b/mythril/interfaces/cli.py
index ea55e29c..96a1f441 100644
--- a/mythril/interfaces/cli.py
+++ b/mythril/interfaces/cli.py
@@ -50,7 +50,7 @@ def main():
inputs.add_argument('-l', '--dynld', action='store_true', help='auto-load dependencies from the blockchain')
outputs = parser.add_argument_group('output formats')
- outputs.add_argument('-o', '--outform', choices=['text', 'markdown', 'json'], default='text',
+ outputs.add_argument('-o', '--outform', choices=['text', 'markdown', 'json', 'swc-standard'], default='text',
help='report output format', metavar='')
outputs.add_argument('--verbose-report', action='store_true', help='Include debugging information in report')
@@ -233,6 +233,7 @@ def main():
create_timeout=args.create_timeout,
max_transaction_count=args.max_transaction_count)
outputs = {
+ 'swc-standard': report.as_swc_standard_format(),
'json': report.as_json(),
'text': report.as_text(),
'markdown': report.as_markdown()
From b67117c8b4dbae017e20c71c5c8acbcee296a6c9 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Wed, 24 Oct 2018 17:07:35 +0200
Subject: [PATCH 15/20] add more type hints
---
mythril/disassembler/asm.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/mythril/disassembler/asm.py b/mythril/disassembler/asm.py
index c2b342f2..c54746d8 100644
--- a/mythril/disassembler/asm.py
+++ b/mythril/disassembler/asm.py
@@ -16,14 +16,14 @@ class EvmInstruction:
self.op_code = op_code
self.argument = argument
- def to_dict(self):
+ def to_dict(self) -> dict:
result = {"address": self.address, "opcode": self.op_code}
if self.argument:
result["argument"] = self.argument
return result
-def instruction_list_to_easm(instruction_list):
+def instruction_list_to_easm(instruction_list: dict) -> str:
result = ""
for instruction in instruction_list:
@@ -35,14 +35,14 @@ def instruction_list_to_easm(instruction_list):
return result
-def get_opcode_from_name(operation_name):
+def get_opcode_from_name(operation_name: str) -> int:
for op_code, value in opcodes.items():
if operation_name == value[0]:
return op_code
raise RuntimeError("Unknown opcode")
-def find_op_code_sequence(pattern, instruction_list):
+def find_op_code_sequence(pattern: list, instruction_list: list) -> Generator:
"""
Returns all indices in instruction_list that point to instruction sequences following a pattern
:param pattern: The pattern to look for.
From 5f9494b979b56dc3e28333508e546321cc224cb4 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Wed, 24 Oct 2018 17:16:19 +0200
Subject: [PATCH 16/20] fix missing environments
---
tests/analysis/test_delegatecall.py | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/tests/analysis/test_delegatecall.py b/tests/analysis/test_delegatecall.py
index 9e88c1fd..324792e1 100644
--- a/tests/analysis/test_delegatecall.py
+++ b/tests/analysis/test_delegatecall.py
@@ -1,6 +1,7 @@
from mythril.analysis.modules.delegatecall import execute, _concrete_call, _symbolic_call
from mythril.analysis.ops import Call, Variable, VarType
from mythril.analysis.symbolic import SymExecWrapper
+from mythril.disassembler.disassembly import Disassembly
from mythril.laser.ethereum.cfg import Node
from mythril.laser.ethereum.state import GlobalState, Environment, Account
import pytest
@@ -11,8 +12,11 @@ import pytest_mock
def test_concrete_call():
# arrange
address = "0x10"
+ active_account = Account(address)
+ active_account.code = Disassembly("00")
+ environment = Environment(active_account, None, None, None, None, None)
- state = GlobalState(None, None, None)
+ state = GlobalState(None, environment, None)
state.mstate.memory = ["placeholder", "calldata_bling_0"]
node = Node("example")
@@ -43,7 +47,10 @@ def test_concrete_call_symbolic_to():
# arrange
address = "0x10"
- state = GlobalState(None, None, None)
+ active_account = Account(address)
+ active_account.code = Disassembly("00")
+ environment = Environment(active_account, None, None, None, None, None)
+ state = GlobalState(None, environment, None)
state.mstate.memory = ["placeholder", "calldata_bling_0"]
node = Node("example")
@@ -88,6 +95,7 @@ def test_symbolic_call_storage_to(mocker):
address = "0x10"
active_account = Account(address)
+ active_account.code = Disassembly("00")
environment = Environment(active_account, None, None, None, None, None)
state = GlobalState(None, environment, None)
state.mstate.memory = ["placeholder", "calldata_bling_0"]
@@ -127,7 +135,10 @@ def test_symbolic_call_calldata_to(mocker):
# arrange
address = "0x10"
- state = GlobalState(None, None, None)
+ active_account = Account(address)
+ active_account.code = Disassembly("00")
+ environment = Environment(active_account, None, None, None, None, None)
+ state = GlobalState(None, environment, None)
state.mstate.memory = ["placeholder", "calldata_bling_0"]
@@ -172,6 +183,8 @@ def test_delegate_call(sym_mock, concrete_mock, curr_instruction):
curr_instruction.return_value = {'address': '0x10'}
active_account = Account('0x10')
+ active_account.code = Disassembly("00")
+
environment = Environment(active_account, None, None, None, None, None)
state = GlobalState(None, environment, Node)
state.mstate.memory = ["placeholder", "calldata_bling_0"]
From 6f69858fbeb3d3c4b20467382ade7d6c83ce1443 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Wed, 24 Oct 2018 17:17:39 +0200
Subject: [PATCH 17/20] fix missing argument
---
mythril/analysis/modules/unchecked_retval.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/mythril/analysis/modules/unchecked_retval.py b/mythril/analysis/modules/unchecked_retval.py
index 4d912fef..3cbd800a 100644
--- a/mythril/analysis/modules/unchecked_retval.py
+++ b/mythril/analysis/modules/unchecked_retval.py
@@ -56,6 +56,7 @@ def execute(statespace):
contract=node.contract_name,
function_name=node.function_name,
address=address,
+ bytecode=state.environment.code.bytecode,
title="Unchecked CALL return value",
swc_id=UNCHECKED_RET_VAL,
)
From 1c396d93ad4e43a170038c88976cfd8b7221e169 Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Wed, 24 Oct 2018 17:42:17 +0200
Subject: [PATCH 18/20] Make statement more readable
---
mythril/disassembler/asm.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mythril/disassembler/asm.py b/mythril/disassembler/asm.py
index f8eba81a..762d1251 100644
--- a/mythril/disassembler/asm.py
+++ b/mythril/disassembler/asm.py
@@ -103,4 +103,4 @@ def disassemble(bytecode: str) -> list:
address += 1
# We use a to_dict() here for compatibility reasons
- return list(map(lambda element: element.to_dict(), instruction_list))
+ return [element.to_dict() for element in instruction_list]
From 2774fc65a26fdeecaf79a373510647bfec7f009c Mon Sep 17 00:00:00 2001
From: Joran Honig
Date: Wed, 24 Oct 2018 21:27:38 +0200
Subject: [PATCH 19/20] update hashing technique used
---
mythril/analysis/report.py | 8 ++++----
solidity_examples/rubixi.sol | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/mythril/analysis/report.py b/mythril/analysis/report.py
index e4443cfa..5d79bcf9 100644
--- a/mythril/analysis/report.py
+++ b/mythril/analysis/report.py
@@ -2,9 +2,9 @@ import logging
import json
import operator
from jinja2 import PackageLoader, Environment
+import sha3
import hashlib
-
class Issue:
def __init__(
self,
@@ -32,9 +32,9 @@ class Issue:
self.lineno = None
try:
- s = hashlib.sha3_256()
- s.update(bytes.fromhex(bytecode))
- self.bytecode_hash = "0x" + s.hexdigest()
+ keccak = sha3.keccak_256()
+ keccak.update(bytes.fromhex(bytecode))
+ self.bytecode_hash = "0x" + keccak.hexdigest()
except ValueError:
logging.debug("Unable to change the bytecode to bytes. Bytecode: {}".format(bytecode))
self.bytecode_hash = ""
diff --git a/solidity_examples/rubixi.sol b/solidity_examples/rubixi.sol
index 91fda1b6..301e9196 100644
--- a/solidity_examples/rubixi.sol
+++ b/solidity_examples/rubixi.sol
@@ -26,7 +26,7 @@ contract Rubixi {
Participant[] private participants;
//Fallback function
- function() {
+ function() payable {
init();
}
From dc09c2e94f50f7c4cea437bb78433d690434f241 Mon Sep 17 00:00:00 2001
From: Nikhil Parasaram
Date: Sat, 27 Oct 2018 13:19:15 +0530
Subject: [PATCH 20/20] Change the issue description
---
mythril/analysis/modules/ether_send.py | 8 +-
mythril/analysis/modules/exceptions.py | 3 +-
mythril/analysis/modules/integer.py | 12 +-
mythril/analysis/modules/multiple_sends.py | 2 +-
mythril/analysis/modules/suicide.py | 5 +-
.../modules/transaction_order_dependence.py | 6 +-
tests/cmd_line_test.py | 3 +-
.../outputs_expected/calls.sol.o.graph.html | 10 +-
.../outputs_expected/calls.sol.o.json | 2 +-
.../outputs_expected/calls.sol.o.markdown | 2 +-
.../outputs_expected/calls.sol.o.text | 2 +-
.../environments.sol.o.graph.html | 10 +-
.../outputs_expected/environments.sol.o.json | 2 +-
.../environments.sol.o.markdown | 9 +-
.../outputs_expected/environments.sol.o.text | 12 +-
.../ether_send.sol.o.graph.html | 10 +-
.../outputs_expected/ether_send.sol.o.json | 2 +-
.../ether_send.sol.o.markdown | 5 +-
.../outputs_expected/ether_send.sol.o.text | 6 +-
.../exceptions.sol.o.graph.html | 10 +-
.../outputs_expected/exceptions.sol.o.json | 2 +-
.../exceptions.sol.o.markdown | 8 +-
.../outputs_expected/exceptions.sol.o.text | 8 +-
.../kinds_of_calls.sol.o.graph.html | 10 +-
.../metacoin.sol.o.graph.html | 10 +-
.../multi_contracts.sol.o.graph.html | 10 +-
.../multi_contracts.sol.o.json | 2 +-
.../multi_contracts.sol.o.markdown | 2 +-
.../multi_contracts.sol.o.text | 2 +-
.../nonascii.sol.o.graph.html | 10 +-
.../outputs_expected/origin.sol.o.graph.html | 10 +-
.../outputs_expected/origin.sol.o.json | 2 +-
.../outputs_current/calls.sol.o.easm | 400 ++++++++++++++++
.../outputs_current/calls.sol.o.graph.html | 62 +++
.../outputs_current/calls.sol.o.json | 1 +
.../outputs_current/calls.sol.o.markdown | 111 +++++
.../outputs_current/calls.sol.o.text | 90 ++++
.../outputs_current/environments.sol.o.easm | 259 +++++++++++
.../environments.sol.o.graph.html | 62 +++
.../outputs_current/environments.sol.o.json | 1 +
.../environments.sol.o.markdown | 34 ++
.../outputs_current/environments.sol.o.text | 30 ++
.../outputs_current/ether_send.sol.o.easm | 420 +++++++++++++++++
.../ether_send.sol.o.graph.html | 62 +++
.../outputs_current/ether_send.sol.o.json | 1 +
.../outputs_current/ether_send.sol.o.markdown | 25 +
.../outputs_current/ether_send.sol.o.text | 21 +
.../outputs_current/exceptions.sol.o.easm | 392 ++++++++++++++++
.../exceptions.sol.o.graph.html | 62 +++
.../outputs_current/exceptions.sol.o.json | 1 +
.../outputs_current/exceptions.sol.o.markdown | 45 ++
.../outputs_current/exceptions.sol.o.text | 36 ++
.../outputs_current/kinds_of_calls.sol.o.easm | 435 ++++++++++++++++++
.../kinds_of_calls.sol.o.graph.html | 62 +++
.../outputs_current/kinds_of_calls.sol.o.json | 1 +
.../kinds_of_calls.sol.o.markdown | 45 ++
.../outputs_current/kinds_of_calls.sol.o.text | 36 ++
.../outputs_current/metacoin.sol.o.easm | 253 ++++++++++
.../outputs_current/metacoin.sol.o.graph.html | 62 +++
.../outputs_current/metacoin.sol.o.json | 1 +
.../outputs_current/metacoin.sol.o.markdown | 3 +
.../outputs_current/metacoin.sol.o.text | 1 +
.../multi_contracts.sol.o.easm | 77 ++++
.../multi_contracts.sol.o.graph.html | 62 +++
.../multi_contracts.sol.o.json | 1 +
.../multi_contracts.sol.o.markdown | 13 +
.../multi_contracts.sol.o.text | 10 +
.../outputs_current/nonascii.sol.o.easm | 167 +++++++
.../outputs_current/nonascii.sol.o.graph.html | 62 +++
.../outputs_current/nonascii.sol.o.json | 1 +
.../outputs_current/nonascii.sol.o.markdown | 3 +
.../outputs_current/nonascii.sol.o.text | 1 +
.../outputs_current/origin.sol.o.easm | 168 +++++++
.../outputs_current/origin.sol.o.graph.html | 62 +++
.../outputs_current/origin.sol.o.json | 1 +
.../outputs_current/origin.sol.o.markdown | 13 +
.../outputs_current/origin.sol.o.text | 10 +
.../outputs_current/overflow.sol.o.easm | 388 ++++++++++++++++
.../outputs_current/overflow.sol.o.graph.html | 62 +++
.../outputs_current/overflow.sol.o.json | 1 +
.../outputs_current/overflow.sol.o.markdown | 34 ++
.../outputs_current/overflow.sol.o.text | 30 ++
.../outputs_current/returnvalue.sol.o.easm | 129 ++++++
.../returnvalue.sol.o.graph.html | 62 +++
.../outputs_current/returnvalue.sol.o.json | 1 +
.../returnvalue.sol.o.markdown | 34 ++
.../outputs_current/returnvalue.sol.o.text | 27 ++
.../outputs_current/suicide.sol.o.easm | 58 +++
.../outputs_current/suicide.sol.o.graph.html | 62 +++
.../outputs_current/suicide.sol.o.json | 1 +
.../outputs_current/suicide.sol.o.markdown | 12 +
.../outputs_current/suicide.sol.o.text | 10 +
.../outputs_current/underflow.sol.o.easm | 365 +++++++++++++++
.../underflow.sol.o.graph.html | 62 +++
.../outputs_current/underflow.sol.o.json | 1 +
.../outputs_current/underflow.sol.o.markdown | 34 ++
.../outputs_current/underflow.sol.o.text | 30 ++
.../overflow.sol.o.graph.html | 10 +-
.../outputs_expected/overflow.sol.o.json | 2 +-
.../outputs_expected/overflow.sol.o.markdown | 9 +-
.../outputs_expected/overflow.sol.o.text | 12 +-
.../returnvalue.sol.o.graph.html | 10 +-
.../outputs_expected/suicide.sol.o.graph.html | 10 +-
.../outputs_expected/suicide.sol.o.json | 2 +-
.../outputs_expected/suicide.sol.o.markdown | 2 +-
.../outputs_expected/suicide.sol.o.text | 2 +-
.../underflow.sol.o.graph.html | 10 +-
.../outputs_expected/underflow.sol.o.json | 2 +-
.../outputs_expected/underflow.sol.o.markdown | 9 +-
.../outputs_expected/underflow.sol.o.text | 12 +-
110 files changed, 5228 insertions(+), 129 deletions(-)
create mode 100644 tests/testdata/outputs_expected/outputs_current/calls.sol.o.easm
create mode 100644 tests/testdata/outputs_expected/outputs_current/calls.sol.o.graph.html
create mode 100644 tests/testdata/outputs_expected/outputs_current/calls.sol.o.json
create mode 100644 tests/testdata/outputs_expected/outputs_current/calls.sol.o.markdown
create mode 100644 tests/testdata/outputs_expected/outputs_current/calls.sol.o.text
create mode 100644 tests/testdata/outputs_expected/outputs_current/environments.sol.o.easm
create mode 100644 tests/testdata/outputs_expected/outputs_current/environments.sol.o.graph.html
create mode 100644 tests/testdata/outputs_expected/outputs_current/environments.sol.o.json
create mode 100644 tests/testdata/outputs_expected/outputs_current/environments.sol.o.markdown
create mode 100644 tests/testdata/outputs_expected/outputs_current/environments.sol.o.text
create mode 100644 tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.easm
create mode 100644 tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.graph.html
create mode 100644 tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.json
create mode 100644 tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.markdown
create mode 100644 tests/testdata/outputs_expected/outputs_current/ether_send.sol.o.text
create mode 100644 tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.easm
create mode 100644 tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.graph.html
create mode 100644 tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.json
create mode 100644 tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.markdown
create mode 100644 tests/testdata/outputs_expected/outputs_current/exceptions.sol.o.text
create mode 100644 tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.easm
create mode 100644 tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.graph.html
create mode 100644 tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.json
create mode 100644 tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.markdown
create mode 100644 tests/testdata/outputs_expected/outputs_current/kinds_of_calls.sol.o.text
create mode 100644 tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.easm
create mode 100644 tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.graph.html
create mode 100644 tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.json
create mode 100644 tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.markdown
create mode 100644 tests/testdata/outputs_expected/outputs_current/metacoin.sol.o.text
create mode 100644 tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.easm
create mode 100644 tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.graph.html
create mode 100644 tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.json
create mode 100644 tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.markdown
create mode 100644 tests/testdata/outputs_expected/outputs_current/multi_contracts.sol.o.text
create mode 100644 tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.easm
create mode 100644 tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.graph.html
create mode 100644 tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.json
create mode 100644 tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.markdown
create mode 100644 tests/testdata/outputs_expected/outputs_current/nonascii.sol.o.text
create mode 100644 tests/testdata/outputs_expected/outputs_current/origin.sol.o.easm
create mode 100644 tests/testdata/outputs_expected/outputs_current/origin.sol.o.graph.html
create mode 100644 tests/testdata/outputs_expected/outputs_current/origin.sol.o.json
create mode 100644 tests/testdata/outputs_expected/outputs_current/origin.sol.o.markdown
create mode 100644 tests/testdata/outputs_expected/outputs_current/origin.sol.o.text
create mode 100644 tests/testdata/outputs_expected/outputs_current/overflow.sol.o.easm
create mode 100644 tests/testdata/outputs_expected/outputs_current/overflow.sol.o.graph.html
create mode 100644 tests/testdata/outputs_expected/outputs_current/overflow.sol.o.json
create mode 100644 tests/testdata/outputs_expected/outputs_current/overflow.sol.o.markdown
create mode 100644 tests/testdata/outputs_expected/outputs_current/overflow.sol.o.text
create mode 100644 tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.easm
create mode 100644 tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.graph.html
create mode 100644 tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.json
create mode 100644 tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.markdown
create mode 100644 tests/testdata/outputs_expected/outputs_current/returnvalue.sol.o.text
create mode 100644 tests/testdata/outputs_expected/outputs_current/suicide.sol.o.easm
create mode 100644 tests/testdata/outputs_expected/outputs_current/suicide.sol.o.graph.html
create mode 100644 tests/testdata/outputs_expected/outputs_current/suicide.sol.o.json
create mode 100644 tests/testdata/outputs_expected/outputs_current/suicide.sol.o.markdown
create mode 100644 tests/testdata/outputs_expected/outputs_current/suicide.sol.o.text
create mode 100644 tests/testdata/outputs_expected/outputs_current/underflow.sol.o.easm
create mode 100644 tests/testdata/outputs_expected/outputs_current/underflow.sol.o.graph.html
create mode 100644 tests/testdata/outputs_expected/outputs_current/underflow.sol.o.json
create mode 100644 tests/testdata/outputs_expected/outputs_current/underflow.sol.o.markdown
create mode 100644 tests/testdata/outputs_expected/outputs_current/underflow.sol.o.text
diff --git a/mythril/analysis/modules/ether_send.py b/mythril/analysis/modules/ether_send.py
index 71131038..76e96a46 100644
--- a/mythril/analysis/modules/ether_send.py
+++ b/mythril/analysis/modules/ether_send.py
@@ -39,14 +39,14 @@ def execute(statespace):
interesting = False
- description = "In the function `" + call.node.function_name + "` "
+ description = "A non-zero amount of Ether is sent to a user-supplied address."
if re.search(r"caller", str(call.to)):
- description += "a non-zero amount of Ether is sent to msg.sender.\n"
+ description += " The target address is msg.sender.\n"
interesting = True
elif re.search(r"calldata", str(call.to)):
- description += "a non-zero amount of Ether is sent to an address taken from function arguments.\n"
+ description += " The target address is taken from function arguments.\n"
interesting = True
else:
@@ -56,7 +56,7 @@ def execute(statespace):
idx = m.group(1)
description += (
- "a non-zero amount of Ether is sent to an address taken from storage slot "
+ " The target address is taken from storage slot "
+ str(idx)
+ ".\n"
)
diff --git a/mythril/analysis/modules/exceptions.py b/mythril/analysis/modules/exceptions.py
index d27e1729..f1702abf 100644
--- a/mythril/analysis/modules/exceptions.py
+++ b/mythril/analysis/modules/exceptions.py
@@ -36,8 +36,7 @@ def execute(statespace):
"out-of-bounds array access, or assert violations. "
)
description += (
- "This is acceptable in most situations. "
- "Note however that `assert()` should only be used to check invariants. "
+ "Note that explicit `assert()` should only be used to check invariants. "
"Use `require()` for regular input checking. "
)
diff --git a/mythril/analysis/modules/integer.py b/mythril/analysis/modules/integer.py
index 3b373926..c6f02936 100644
--- a/mythril/analysis/modules/integer.py
+++ b/mythril/analysis/modules/integer.py
@@ -99,12 +99,7 @@ def _check_integer_overflow(statespace, state, node):
_type="Warning",
)
- issue.description = (
- "A possible integer overflow exists in the function `{}`.\n"
- "The addition or multiplication may result in a value higher than the maximum representable integer.".format(
- node.function_name
- )
- )
+ issue.description = "The arithmetic operation can result in integer overflow.\n"
issue.debug = solver.pretty_print_model(model)
issues.append(issue)
@@ -213,10 +208,7 @@ def _check_integer_underflow(statespace, state, node):
)
issue.description = (
- "A possible integer underflow exists in the function `"
- + node.function_name
- + "`.\n"
- "The subtraction may result in a value < 0."
+ "The substraction can result in an integer underflow.\n"
)
issue.debug = solver.pretty_print_model(model)
diff --git a/mythril/analysis/modules/multiple_sends.py b/mythril/analysis/modules/multiple_sends.py
index a53e20b5..c3489141 100644
--- a/mythril/analysis/modules/multiple_sends.py
+++ b/mythril/analysis/modules/multiple_sends.py
@@ -33,7 +33,7 @@ def execute(statespace):
)
issue.description = (
- "Multiple sends exist in one transaction. Try to isolate each external call into its own transaction,"
+ "Multiple sends are executed in a single transaction. Try to isolate each external call into its own transaction,"
" as external calls can fail accidentally or deliberately.\nConsecutive calls: \n"
)
diff --git a/mythril/analysis/modules/suicide.py b/mythril/analysis/modules/suicide.py
index 0d1b4859..70e68a4c 100644
--- a/mythril/analysis/modules/suicide.py
+++ b/mythril/analysis/modules/suicide.py
@@ -39,9 +39,8 @@ def _analyze_state(state, node):
to = state.mstate.stack[-1]
logging.debug("[UNCHECKED_SUICIDE] suicide in function " + node.function_name)
- description = (
- "The function `" + node.function_name + "` executes the SUICIDE instruction. "
- )
+
+ description = "A reachable SUICIDE instruction was detected. "
if "caller" in str(to):
description += "The remaining Ether is sent to the caller's address.\n"
diff --git a/mythril/analysis/modules/transaction_order_dependence.py b/mythril/analysis/modules/transaction_order_dependence.py
index bd6a36f8..8d98bfdb 100644
--- a/mythril/analysis/modules/transaction_order_dependence.py
+++ b/mythril/analysis/modules/transaction_order_dependence.py
@@ -43,10 +43,8 @@ def execute(statespace):
)
issue.description = (
- "A possible transaction order dependence vulnerability exists in function {}. The value or "
- "direction of the call statement is determined from a tainted storage location".format(
- node.function_name
- )
+ "Possible transaction order dependence vulnerability: The value or "
+ "direction of the call statement is determined from a tainted storage location"
)
issues.append(issue)
diff --git a/tests/cmd_line_test.py b/tests/cmd_line_test.py
index 9c5033aa..83ade882 100644
--- a/tests/cmd_line_test.py
+++ b/tests/cmd_line_test.py
@@ -26,7 +26,8 @@ class TruffleTestCase(BaseTestCase):
def test_analysis_truffle_project(self):
truffle_project_root = str(TESTS_DIR / "truffle_project")
command = "cd {}; truffle compile; python3 {} --truffle".format(truffle_project_root, MYTH)
- self.assertIn("In the function `withdrawfunds()` a non-zero amount of Ether is sent to msg.sender.", output_of(command))
+ self.assertIn("A non-zero amount of Ether is sent to a user-supplied address. The target address is msg.sender."
+ , output_of(command))
class InfuraTestCase(BaseTestCase):
diff --git a/tests/testdata/outputs_expected/calls.sol.o.graph.html b/tests/testdata/outputs_expected/calls.sol.o.graph.html
index 6af2b5fa..cc2b882d 100644
--- a/tests/testdata/outputs_expected/calls.sol.o.graph.html
+++ b/tests/testdata/outputs_expected/calls.sol.o.graph.html
@@ -8,6 +8,7 @@
Mythril / Ethereum LASER Symbolic VM
-
+
Mythril / Ethereum LASER Symbolic VM
-
+
Mythril / Ethereum LASER Symbolic VM
-
+
Mythril / Ethereum LASER Symbolic VM
-
+
Mythril / Ethereum LASER Symbolic VM
-
+
Mythril / Ethereum LASER Symbolic VM
-
+
Mythril / Ethereum LASER Symbolic VM
-
+
Mythril / Ethereum LASER Symbolic VM
-
+
Mythril / Ethereum LASER Symbolic VM
-
+
+
+
+
+
+
+
+
+
+Mythril / Ethereum LASER Symbolic VM
+
+
+
+