From e1bb6848976c7a54baa19e3e61f9aeeb58f55f5a Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Wed, 25 Jul 2018 15:53:03 +0200 Subject: Bugfix entry regarding nested arrays returned by library functions --- docs/bugs.json | 8 ++++++++ docs/bugs_by_version.json | 23 +++++++++++++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/docs/bugs.json b/docs/bugs.json index b464be18..cec6a5cd 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,12 @@ [ + { + "name": "PublicLibFunctionsDoNotReturnNestedArrays", + "summary": "Calls to public library functions (internal functions are safe) that return nested arrays return only zeroes.", + "description": "The compiler does not complain about public library functions (internal functions are safe) returning nested arrays, but it also does not return it correctly. Thus, the function caller receives only zeroes.", + "introduced": "0.4.11", + "fixed": "0.4.22", + "severity": "low" + }, { "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_by_version.json b/docs/bugs_by_version.json index 2fe1d226..07ce57fd 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -345,6 +345,7 @@ }, "0.4.11": { "bugs": [ + "PublicLibFunctionsDoNotReturnNestedArrays", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -354,6 +355,7 @@ }, "0.4.12": { "bugs": [ + "PublicLibFunctionsDoNotReturnNestedArrays", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput" @@ -362,6 +364,7 @@ }, "0.4.13": { "bugs": [ + "PublicLibFunctionsDoNotReturnNestedArrays", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput" @@ -370,6 +373,7 @@ }, "0.4.14": { "bugs": [ + "PublicLibFunctionsDoNotReturnNestedArrays", "ZeroFunctionSelector", "DelegateCallReturnValue" ], @@ -377,28 +381,35 @@ }, "0.4.15": { "bugs": [ + "PublicLibFunctionsDoNotReturnNestedArrays", "ZeroFunctionSelector" ], "released": "2017-08-08" }, "0.4.16": { "bugs": [ + "PublicLibFunctionsDoNotReturnNestedArrays", "ZeroFunctionSelector" ], "released": "2017-08-24" }, "0.4.17": { "bugs": [ + "PublicLibFunctionsDoNotReturnNestedArrays", "ZeroFunctionSelector" ], "released": "2017-09-21" }, "0.4.18": { - "bugs": [], + "bugs": [ + "PublicLibFunctionsDoNotReturnNestedArrays" + ], "released": "2017-10-18" }, "0.4.19": { - "bugs": [], + "bugs": [ + "PublicLibFunctionsDoNotReturnNestedArrays" + ], "released": "2017-11-30" }, "0.4.2": { @@ -415,11 +426,15 @@ "released": "2016-09-17" }, "0.4.20": { - "bugs": [], + "bugs": [ + "PublicLibFunctionsDoNotReturnNestedArrays" + ], "released": "2018-02-14" }, "0.4.21": { - "bugs": [], + "bugs": [ + "PublicLibFunctionsDoNotReturnNestedArrays" + ], "released": "2018-03-07" }, "0.4.22": { -- cgit From 55e67e41f9356e4953a57d8a15808e1c7d391686 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Fri, 3 Aug 2018 13:55:44 +0200 Subject: Update bug list and add regular expression to bug list and add test. --- .circleci/config.yml | 12 ++++++++ docs/bugs.json | 11 +++---- docs/bugs.rst | 8 +++++ docs/bugs_by_version.json | 47 +++++++++++++++++++++++------- test/buglistTests.js | 45 +++++++++++++++++++++++++++++ test/buglist_test_vectors.md | 69 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 176 insertions(+), 16 deletions(-) create mode 100755 test/buglistTests.js create mode 100644 test/buglist_test_vectors.md 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 cec6a5cd..3f20077f 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,11 +1,12 @@ [ { - "name": "PublicLibFunctionsDoNotReturnNestedArrays", - "summary": "Calls to public library functions (internal functions are safe) that return nested arrays return only zeroes.", - "description": "The compiler does not complain about public library functions (internal functions are safe) returning nested arrays, but it also does not return it correctly. Thus, the function caller receives only zeroes.", - "introduced": "0.4.11", + "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": "low" + "severity": "medium", + "check": {"regex-source": "returns[^;{]*\\[\\s*[^\\] \\t\\r\\n\\v\\f][^\\]]*\\]\\s*\\[\\s*[^\\] \\t\\r\\n\\v\\f][^\\]]*\\][^{;]*[;{]"} }, { "name": "OneOfTwoConstructorsSkipped", 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 07ce57fd..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,7 +362,7 @@ }, "0.4.11": { "bugs": [ - "PublicLibFunctionsDoNotReturnNestedArrays", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -355,7 +372,7 @@ }, "0.4.12": { "bugs": [ - "PublicLibFunctionsDoNotReturnNestedArrays", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput" @@ -364,7 +381,7 @@ }, "0.4.13": { "bugs": [ - "PublicLibFunctionsDoNotReturnNestedArrays", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput" @@ -373,7 +390,7 @@ }, "0.4.14": { "bugs": [ - "PublicLibFunctionsDoNotReturnNestedArrays", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue" ], @@ -381,39 +398,40 @@ }, "0.4.15": { "bugs": [ - "PublicLibFunctionsDoNotReturnNestedArrays", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector" ], "released": "2017-08-08" }, "0.4.16": { "bugs": [ - "PublicLibFunctionsDoNotReturnNestedArrays", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector" ], "released": "2017-08-24" }, "0.4.17": { "bugs": [ - "PublicLibFunctionsDoNotReturnNestedArrays", + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector" ], "released": "2017-09-21" }, "0.4.18": { "bugs": [ - "PublicLibFunctionsDoNotReturnNestedArrays" + "NestedArrayFunctionCallDecoder" ], "released": "2017-10-18" }, "0.4.19": { "bugs": [ - "PublicLibFunctionsDoNotReturnNestedArrays" + "NestedArrayFunctionCallDecoder" ], "released": "2017-11-30" }, "0.4.2": { "bugs": [ + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -427,13 +445,13 @@ }, "0.4.20": { "bugs": [ - "PublicLibFunctionsDoNotReturnNestedArrays" + "NestedArrayFunctionCallDecoder" ], "released": "2018-02-14" }, "0.4.21": { "bugs": [ - "PublicLibFunctionsDoNotReturnNestedArrays" + "NestedArrayFunctionCallDecoder" ], "released": "2018-03-07" }, @@ -453,6 +471,7 @@ }, "0.4.3": { "bugs": [ + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -465,6 +484,7 @@ }, "0.4.4": { "bugs": [ + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -476,6 +496,7 @@ }, "0.4.5": { "bugs": [ + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -488,6 +509,7 @@ }, "0.4.6": { "bugs": [ + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -499,6 +521,7 @@ }, "0.4.7": { "bugs": [ + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -509,6 +532,7 @@ }, "0.4.8": { "bugs": [ + "NestedArrayFunctionCallDecoder", "ZeroFunctionSelector", "DelegateCallReturnValue", "ECRecoverMalformedInput", @@ -519,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; } -- cgit