aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.circleci/config.yml12
-rw-r--r--docs/bugs.json9
-rw-r--r--docs/bugs.rst8
-rw-r--r--docs/bugs_by_version.json48
-rwxr-xr-xtest/buglistTests.js45
-rw-r--r--test/buglist_test_vectors.md69
6 files changed, 187 insertions, 4 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index e3596d2b..4514626b 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -179,6 +179,17 @@ jobs:
name: Check spelling
command: ~/.local/bin/codespell -S "*.enc,.git" -I ./scripts/codespell_whitelist.txt
+ test_buglist:
+ docker:
+ - image: circleci/node
+ environment:
+ TERM: xterm
+ steps:
+ - checkout
+ - run:
+ name: Test buglist
+ command: ./test/buglistTests.js
+
test_x86_linux:
docker:
- image: buildpack-deps:artful
@@ -252,6 +263,7 @@ workflows:
build_all:
jobs:
- test_check_spelling: *build_on_tags
+ - test_buglist: *build_on_tags
- build_emscripten: *build_on_tags
- test_emscripten_solcjs:
<<: *build_on_tags
diff --git a/docs/bugs.json b/docs/bugs.json
index b464be18..3f20077f 100644
--- a/docs/bugs.json
+++ b/docs/bugs.json
@@ -1,4 +1,13 @@
[
+ {
+ "name": "NestedArrayFunctionCallDecoder",
+ "summary": "Calling functions that return multi-dimensional fixed-size arrays can result in memory corruption.",
+ "description": "If Solidity code calls a function that returns a multi-dimensional fixed-size array, array elements are incorrectly interpreted as memory pointers and thus can cause memory corruption if the return values are accessed. Calling functions with multi-dimensional fixed-size arrays is unaffected as is returning fixed-size arrays from function calls. The regular expression only checks if such functions are present, not if they are called, which is required for the contract to be affected.",
+ "introduced": "0.1.4",
+ "fixed": "0.4.22",
+ "severity": "medium",
+ "check": {"regex-source": "returns[^;{]*\\[\\s*[^\\] \\t\\r\\n\\v\\f][^\\]]*\\]\\s*\\[\\s*[^\\] \\t\\r\\n\\v\\f][^\\]]*\\][^{;]*[;{]"}
+ },
{
"name": "OneOfTwoConstructorsSkipped",
"summary": "If a contract has both a new-style constructor (using the constructor keyword) and an old-style constructor (a function with the same name as the contract) at the same time, one of them will be ignored.",
diff --git a/docs/bugs.rst b/docs/bugs.rst
index 7629830d..6f315a65 100644
--- a/docs/bugs.rst
+++ b/docs/bugs.rst
@@ -56,6 +56,14 @@ conditions
is an object that can contain a boolean value ``optimizer``, which
means that the optimizer has to be switched on to enable the bug.
If no conditions are given, assume that the bug is present.
+check
+ This field contains JavaScript regular expressions that are to be matched
+ against the source code ("source-regex") to find out if the
+ smart contract contains the bug or not. If there is no match,
+ then the bug is very likely not present. If there is a match,
+ the bug might be present. For improved accuracy, the regular
+ expression should be applied to the source code after stripping
+ comments.
.. literalinclude:: bugs.json
:language: js
diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json
index 2fe1d226..b400121f 100644
--- a/docs/bugs_by_version.json
+++ b/docs/bugs_by_version.json
@@ -69,6 +69,7 @@
},
"0.1.4": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -86,6 +87,7 @@
},
"0.1.5": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -103,6 +105,7 @@
},
"0.1.6": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -121,6 +124,7 @@
},
"0.1.7": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -139,6 +143,7 @@
},
"0.2.0": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -157,6 +162,7 @@
},
"0.2.1": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -175,6 +181,7 @@
},
"0.2.2": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -193,6 +200,7 @@
},
"0.3.0": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -211,6 +219,7 @@
},
"0.3.1": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -228,6 +237,7 @@
},
"0.3.2": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -245,6 +255,7 @@
},
"0.3.3": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -261,6 +272,7 @@
},
"0.3.4": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -277,6 +289,7 @@
},
"0.3.5": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -293,6 +306,7 @@
},
"0.3.6": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -307,6 +321,7 @@
},
"0.4.0": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -321,6 +336,7 @@
},
"0.4.1": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -335,6 +351,7 @@
},
"0.4.10": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -345,6 +362,7 @@
},
"0.4.11": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -354,6 +372,7 @@
},
"0.4.12": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput"
@@ -362,6 +381,7 @@
},
"0.4.13": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput"
@@ -370,6 +390,7 @@
},
"0.4.14": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue"
],
@@ -377,32 +398,40 @@
},
"0.4.15": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector"
],
"released": "2017-08-08"
},
"0.4.16": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector"
],
"released": "2017-08-24"
},
"0.4.17": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector"
],
"released": "2017-09-21"
},
"0.4.18": {
- "bugs": [],
+ "bugs": [
+ "NestedArrayFunctionCallDecoder"
+ ],
"released": "2017-10-18"
},
"0.4.19": {
- "bugs": [],
+ "bugs": [
+ "NestedArrayFunctionCallDecoder"
+ ],
"released": "2017-11-30"
},
"0.4.2": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -415,11 +444,15 @@
"released": "2016-09-17"
},
"0.4.20": {
- "bugs": [],
+ "bugs": [
+ "NestedArrayFunctionCallDecoder"
+ ],
"released": "2018-02-14"
},
"0.4.21": {
- "bugs": [],
+ "bugs": [
+ "NestedArrayFunctionCallDecoder"
+ ],
"released": "2018-03-07"
},
"0.4.22": {
@@ -438,6 +471,7 @@
},
"0.4.3": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -450,6 +484,7 @@
},
"0.4.4": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -461,6 +496,7 @@
},
"0.4.5": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -473,6 +509,7 @@
},
"0.4.6": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -484,6 +521,7 @@
},
"0.4.7": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -494,6 +532,7 @@
},
"0.4.8": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
@@ -504,6 +543,7 @@
},
"0.4.9": {
"bugs": [
+ "NestedArrayFunctionCallDecoder",
"ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
diff --git a/test/buglistTests.js b/test/buglistTests.js
new file mode 100755
index 00000000..6b7df2f2
--- /dev/null
+++ b/test/buglistTests.js
@@ -0,0 +1,45 @@
+#!/usr/bin/env node
+
+"use strict";
+
+var fs = require('fs')
+var bugs = JSON.parse(fs.readFileSync(__dirname + '/../docs/bugs.json', 'utf8'))
+
+var bugsByName = {}
+for (var i in bugs)
+{
+ if (bugs[i].name in bugsByName)
+ {
+ throw "Duplicate bug name: " + bugs[i].name
+ }
+ bugsByName[bugs[i].name] = bugs[i]
+}
+
+var tests = fs.readFileSync(__dirname + '/buglist_test_vectors.md', 'utf8')
+
+var testVectorParser = /\s*#\s+(\S+)\s+## buggy\n([^#]*)## fine\n([^#]*)/g
+
+var result;
+while ((result = testVectorParser.exec(tests)) !== null)
+{
+ var name = result[1]
+ var buggy = result[2].split('\n--\n')
+ var fine = result[3].split('\n--\n')
+ console.log("Testing " + name + " with " + buggy.length + " buggy and " + fine.length + " fine instances")
+
+ var regex = RegExp(bugsByName[name].check['regex-source'])
+ for (var i in buggy)
+ {
+ if (!regex.exec(buggy[i]))
+ {
+ throw "Bug " + name + ": Buggy source does not match: " + buggy[i]
+ }
+ }
+ for (var i in fine)
+ {
+ if (regex.exec(fine[i]))
+ {
+ throw "Bug " + name + ": Non-buggy source matches: " + fine[i]
+ }
+ }
+}
diff --git a/test/buglist_test_vectors.md b/test/buglist_test_vectors.md
new file mode 100644
index 00000000..ce95403b
--- /dev/null
+++ b/test/buglist_test_vectors.md
@@ -0,0 +1,69 @@
+# NestedArrayFunctionCallDecoder
+
+## buggy
+
+function f() pure returns (uint[2][2]) { }
+
+--
+
+function f() returns (uint[2][2] a) { }
+
+--
+
+function f() returns (uint x, uint[200][2] a) { }
+
+--
+
+function f() returns (uint[200][2] a, uint x) { }
+
+--
+
+function f() returns (uint[200][2] a, uint x);
+
+--
+
+function f() returns (
+ uint
+ [
+ 200
+ ]
+ [2]
+ a, uint x);
+
+--
+
+function f() returns (
+ uint
+ [
+ ContractName.ConstantName
+ ]
+ [2]
+ a, uint x);
+
+## fine
+
+function f() returns (uint[2]) { }
+
+--
+
+function f() public pure returns (uint[2][] a) { }
+
+--
+
+function f() public pure returns (uint[ 2 ] [ ] a) { }
+
+--
+
+function f() public pure returns (uint x, uint[] a) { }
+
+--
+
+function f(uint[2][2]) { }
+
+--
+
+function f() m(uint[2][2]) { }
+
+--
+
+function f() returns (uint, uint) { uint[2][2] memory x; }