mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Buglist check script supports json paths
This commit is contained in:
		
							parent
							
								
									c57a60833d
								
							
						
					
					
						commit
						9927964d21
					
				| @ -195,6 +195,12 @@ jobs: | |||||||
|       TERM: xterm |       TERM: xterm | ||||||
|     steps: |     steps: | ||||||
|       - checkout |       - checkout | ||||||
|  |       - run: | ||||||
|  |           name: JS deps | ||||||
|  |           command: | | ||||||
|  |             npm install download | ||||||
|  |             npm install JSONPath | ||||||
|  |             npm install mktemp | ||||||
|       - run: |       - run: | ||||||
|           name: Test buglist |           name: Test buglist | ||||||
|           command: ./test/buglistTests.js |           command: ./test/buglistTests.js | ||||||
|  | |||||||
| @ -5,7 +5,8 @@ | |||||||
|         "description": "If a struct is used in an event, the address of the struct is logged instead of the actual data.", |         "description": "If a struct is used in an event, the address of the struct is logged instead of the actual data.", | ||||||
|         "introduced": "0.4.17", |         "introduced": "0.4.17", | ||||||
|         "fixed": "0.5.0", |         "fixed": "0.5.0", | ||||||
| 		"severity": "very low" |         "severity": "very low", | ||||||
|  |         "check": {"ast-compact-json-path": "$..[?(@.nodeType === 'EventDefinition')]..[?(@.nodeType === 'UserDefinedTypeName' && @.typeDescriptions.typeString.startsWith('struct'))]"} | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         "name": "NestedArrayFunctionCallDecoder", |         "name": "NestedArrayFunctionCallDecoder", | ||||||
|  | |||||||
| @ -57,13 +57,18 @@ conditions | |||||||
|     means that the optimizer has to be switched on to enable the bug. |     means that the optimizer has to be switched on to enable the bug. | ||||||
|     If no conditions are given, assume that the bug is present. |     If no conditions are given, assume that the bug is present. | ||||||
| check | check | ||||||
|     This field contains JavaScript regular expressions that are to be matched |     This field contains different checks that report whether the smart contract | ||||||
|     against the source code ("source-regex") to find out if the |     contains the bug or not. The first type of check are Javascript regular | ||||||
|     smart contract contains the bug or not. If there is no match, |     expressions that are to be matched against the source code ("source-regex") | ||||||
|     then the bug is very likely not present. If there is a match, |     if the bug is present.  If there is no match, then the bug is very likely | ||||||
|     the bug might be present. For improved accuracy, the regular |     not present. If there is a match, the bug might be present.  For improved | ||||||
|     expression should be applied to the source code after stripping |     accuracy, the checks should be applied to the source code after stripping | ||||||
|     comments. |     comments. | ||||||
|  |     The second type of check are patterns to be checked on the compact AST of | ||||||
|  |     the Solidity program ("ast-compact-json-path"). The specified search query | ||||||
|  |     is a `JsonPath <https://github.com/json-path/JsonPath>`_ expression. | ||||||
|  |     If at least one path of the Solidity AST matches the query, the bug is | ||||||
|  |     likely present. | ||||||
| 
 | 
 | ||||||
| .. literalinclude:: bugs.json | .. literalinclude:: bugs.json | ||||||
|    :language: js |    :language: js | ||||||
|  | |||||||
| @ -2,6 +2,11 @@ | |||||||
| 
 | 
 | ||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
|  | var util = require('util') | ||||||
|  | var exec = util.promisify(require('child_process').exec) | ||||||
|  | var mktemp = require('mktemp'); | ||||||
|  | var download = require('download') | ||||||
|  | var JSONPath = require('JSONPath') | ||||||
| var fs = require('fs') | var fs = require('fs') | ||||||
| var bugs = JSON.parse(fs.readFileSync(__dirname + '/../docs/bugs.json', 'utf8')) | var bugs = JSON.parse(fs.readFileSync(__dirname + '/../docs/bugs.json', 'utf8')) | ||||||
| 
 | 
 | ||||||
| @ -19,6 +24,10 @@ var tests = fs.readFileSync(__dirname + '/buglist_test_vectors.md', 'utf8') | |||||||
| 
 | 
 | ||||||
| var testVectorParser = /\s*#\s+(\S+)\s+## buggy\n([^#]*)## fine\n([^#]*)/g | var testVectorParser = /\s*#\s+(\S+)\s+## buggy\n([^#]*)## fine\n([^#]*)/g | ||||||
| 
 | 
 | ||||||
|  | runTests() | ||||||
|  | 
 | ||||||
|  | async function runTests() | ||||||
|  | { | ||||||
| 	var result; | 	var result; | ||||||
| 	while ((result = testVectorParser.exec(tests)) !== null) | 	while ((result = testVectorParser.exec(tests)) !== null) | ||||||
| 	{ | 	{ | ||||||
| @ -27,19 +36,99 @@ while ((result = testVectorParser.exec(tests)) !== null) | |||||||
| 		var fine = result[3].split('\n--\n') | 		var fine = result[3].split('\n--\n') | ||||||
| 		console.log("Testing " + name + " with " + buggy.length + " buggy and " + fine.length + " fine instances") | 		console.log("Testing " + name + " with " + buggy.length + " buggy and " + fine.length + " fine instances") | ||||||
| 
 | 
 | ||||||
|     var regex = RegExp(bugsByName[name].check['regex-source']) | 		try { | ||||||
|  | 			await checkRegex(name, buggy, fine) | ||||||
|  | 			await checkJSONPath(name, buggy, fine) | ||||||
|  | 		} catch (err) { | ||||||
|  | 			console.error("Error: " + err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function checkRegex(name, buggy, fine) | ||||||
|  | { | ||||||
|  |     return new Promise(function(resolve, reject) { | ||||||
|  | 		var regexStr = bugsByName[name].check['regex-source'] | ||||||
|  | 		if (regexStr !== undefined) | ||||||
|  | 		{ | ||||||
|  | 			var regex = RegExp(regexStr) | ||||||
| 			for (var i in buggy) | 			for (var i in buggy) | ||||||
| 			{ | 			{ | ||||||
| 				if (!regex.exec(buggy[i])) | 				if (!regex.exec(buggy[i])) | ||||||
| 				{ | 				{ | ||||||
|             throw "Bug " + name + ": Buggy source does not match: " + buggy[i] | 					reject("Bug " + name + ": Buggy source does not match: " + buggy[i]) | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			for (var i in fine) | 			for (var i in fine) | ||||||
| 			{ | 			{ | ||||||
| 				if (regex.exec(fine[i])) | 				if (regex.exec(fine[i])) | ||||||
| 				{ | 				{ | ||||||
|             throw "Bug " + name + ": Non-buggy source matches: " + fine[i] | 					reject("Bug " + name + ": Non-buggy source matches: " + fine[i]) | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 		resolve() | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | async function checkJSONPath(name, buggy, fine) | ||||||
|  | { | ||||||
|  | 	var jsonPath = bugsByName[name].check['ast-compact-json-path'] | ||||||
|  | 	if (jsonPath !== undefined) | ||||||
|  | 	{ | ||||||
|  | 		var url = "http://github.com/ethereum/solidity/releases/download/v" + bugsByName[name].introduced + "/solc-static-linux" | ||||||
|  | 		try { | ||||||
|  | 			var tmpdir = await mktemp.createDir('XXXXX') | ||||||
|  | 			var binary = tmpdir + "/solc-static-linux" | ||||||
|  | 			await download(url, tmpdir) | ||||||
|  | 			exec("chmod +x " + binary) | ||||||
|  | 			for (var i in buggy) | ||||||
|  | 			{ | ||||||
|  | 				var result = await checkJsonPathTest(buggy[i], tmpdir, binary, jsonPath, i) | ||||||
|  | 				if (!result) | ||||||
|  | 					throw "Bug " + name + ": Buggy source does not contain path: " + buggy[i] | ||||||
|  | 			} | ||||||
|  | 			for (var i in fine) | ||||||
|  | 			{ | ||||||
|  | 				var result = await checkJsonPathTest(fine[i], tmpdir, binary, jsonPath, i + buggy.length) | ||||||
|  | 				if (result) | ||||||
|  | 					throw "Bug " + name + ": Non-buggy source contains path: " + fine[i] | ||||||
|  | 			} | ||||||
|  | 			exec("rm -r " + tmpdir) | ||||||
|  | 		} catch (err) { | ||||||
|  | 			throw err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function checkJsonPathTest(code, tmpdir, binary, query, idx) { | ||||||
|  |     return new Promise(function(resolve, reject) { | ||||||
|  |         var solFile = tmpdir + "/jsonPath" + idx + ".sol" | ||||||
|  |         var astFile = tmpdir + "/ast" + idx + ".json" | ||||||
|  |         writeFilePromise(solFile, code) | ||||||
|  |         .then(() => { | ||||||
|  |             return exec(binary + " --ast-compact-json " + solFile + " > " + astFile) | ||||||
|  |         }) | ||||||
|  |         .then(() => { | ||||||
|  |             var jsonRE = /(\{[\s\S]*\})/ | ||||||
|  |             var ast = JSON.parse(jsonRE.exec(fs.readFileSync(astFile, 'utf8'))[0]) | ||||||
|  |             var result = JSONPath({json: ast, path: query}) | ||||||
|  |             if (result.length > 0) | ||||||
|  |                 resolve(true) | ||||||
|  |             else | ||||||
|  |                 resolve(false) | ||||||
|  |         }) | ||||||
|  |         .catch((err) => { | ||||||
|  |             reject(err) | ||||||
|  |         }) | ||||||
|  |     }) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function writeFilePromise(filename, data) { | ||||||
|  |     return new Promise(function(resolve, reject) { | ||||||
|  |         fs.writeFile(filename, data, 'utf8', function(err) { | ||||||
|  |             if (err) reject(err) | ||||||
|  |             else resolve(data) | ||||||
|  |         }) | ||||||
|  |     }) | ||||||
|  | } | ||||||
|  | |||||||
| @ -67,3 +67,48 @@ function f() m(uint[2][2]) { } | |||||||
| -- | -- | ||||||
| 
 | 
 | ||||||
| function f() returns (uint, uint) { uint[2][2] memory x; } | function f() returns (uint, uint) { uint[2][2] memory x; } | ||||||
|  | 
 | ||||||
|  | # EventStructWrongData | ||||||
|  | 
 | ||||||
|  | ## buggy | ||||||
|  | 
 | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  | contract C | ||||||
|  | { | ||||||
|  | 	struct S { uint x; } | ||||||
|  | 	event E(S); | ||||||
|  | 	event F(S); | ||||||
|  | 	enum A { B, C } | ||||||
|  | 	event G(A); | ||||||
|  | 	function f(S s); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | -- | ||||||
|  | 
 | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  | contract C | ||||||
|  | { | ||||||
|  | 	struct S { uint x; } | ||||||
|  | 	event E(S indexed); | ||||||
|  | 	event F(uint, S, bool); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ## fine | ||||||
|  | 
 | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  | contract C | ||||||
|  | { | ||||||
|  | 	struct S { uint x; } | ||||||
|  | 	enum A { B, C } | ||||||
|  | 	event G(A); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | -- | ||||||
|  | 
 | ||||||
|  | pragma experimental ABIEncoderV2; | ||||||
|  | contract C | ||||||
|  | { | ||||||
|  | 	struct S { uint x; } | ||||||
|  | 	function f(S s); | ||||||
|  | 	S s1; | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user