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 | ||||
|     steps: | ||||
|       - checkout | ||||
|       - run: | ||||
|           name: JS deps | ||||
|           command: | | ||||
|             npm install download | ||||
|             npm install JSONPath | ||||
|             npm install mktemp | ||||
|       - run: | ||||
|           name: Test buglist | ||||
|           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.", | ||||
|         "introduced": "0.4.17", | ||||
|         "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", | ||||
|  | ||||
| @ -57,13 +57,18 @@ conditions | ||||
|     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 | ||||
|     This field contains different checks that report whether the smart contract | ||||
|     contains the bug or not. The first type of check are Javascript regular | ||||
|     expressions that are to be matched against the source code ("source-regex") | ||||
|     if the bug is present.  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 checks should be applied to the source code after stripping | ||||
|     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 | ||||
|    :language: js | ||||
|  | ||||
| @ -2,6 +2,11 @@ | ||||
| 
 | ||||
| "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 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 | ||||
| 
 | ||||
| runTests() | ||||
| 
 | ||||
| async function runTests() | ||||
| { | ||||
| 	var result; | ||||
| 	while ((result = testVectorParser.exec(tests)) !== null) | ||||
| 	{ | ||||
| @ -27,19 +36,99 @@ while ((result = testVectorParser.exec(tests)) !== null) | ||||
| 		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']) | ||||
| 		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) | ||||
| 			{ | ||||
| 				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) | ||||
| 			{ | ||||
| 				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; } | ||||
| 
 | ||||
| # 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