From 449f56c15bbc4e5b1b8413d5e025d0f845794688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 21 Dec 2021 15:23:03 +0100 Subject: [PATCH 01/77] pylint: Enable and fix consider-using-sys-exit warnings --- scripts/error_codes.py | 18 +++++++++--------- scripts/pylint_all.py | 6 +++--- scripts/pylintrc | 1 - test/lsp.py | 3 ++- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/scripts/error_codes.py b/scripts/error_codes.py index fe9c73b04..65158a0a6 100755 --- a/scripts/error_codes.py +++ b/scripts/error_codes.py @@ -277,7 +277,7 @@ def main(argv): if [check, fix, examine_coverage, next_id].count(True) != 1: print("usage: python error_codes.py --check | --fix [--no-confirm] | --examine-coverage | --next") - exit(1) + sys.exit(1) cwd = os.getcwd() @@ -303,9 +303,9 @@ def main(argv): if examine_coverage: if not ok: print("Incorrect IDs have to be fixed before applying --examine-coverage") - exit(1) + sys.exit(1) res = 0 if examine_id_coverage(cwd, source_id_to_file_names) else 1 - exit(res) + sys.exit(res) ok &= examine_id_coverage(cwd, source_id_to_file_names, new_ids_only=True) @@ -314,18 +314,18 @@ def main(argv): if next_id: if not ok: print("Incorrect IDs have to be fixed before applying --next") - exit(1) + sys.exit(1) available_ids = {str(id) for id in range(1000, 10000)} - source_id_to_file_names.keys() next_id = get_next_id(available_ids) print(f"Next ID: {next_id}") - exit(0) + sys.exit(0) if ok: print("No incorrect IDs found") - exit(0) + sys.exit(0) if check: - exit(1) + sys.exit(1) assert fix, "Unexpected state, should not come here without --fix" @@ -338,14 +338,14 @@ def main(argv): while len(answer) == 0 or answer not in "YNyn": answer = input("[Y/N]? ") if answer not in "yY": - exit(1) + sys.exit(1) # number of appearances for every id source_id_to_count = { id: len(file_names) for id, file_names in source_id_to_file_names.items() } fix_ids_in_source_files(source_file_names, source_id_to_count) print("Fixing completed") - exit(2) + sys.exit(2) if __name__ == "__main__": diff --git a/scripts/pylint_all.py b/scripts/pylint_all.py index 8dbe6a7fc..a60b000ed 100755 --- a/scripts/pylint_all.py +++ b/scripts/pylint_all.py @@ -6,9 +6,9 @@ Runs pylint on all Python files in project directories known to contain Python s from argparse import ArgumentParser from os import path, walk -from sys import exit from textwrap import dedent import subprocess +import sys PROJECT_ROOT = path.dirname(path.dirname(path.realpath(__file__))) PYLINT_RCFILE = f"{PROJECT_ROOT}/scripts/pylintrc" @@ -89,7 +89,7 @@ def main(): success = pylint_all_filenames(options.dev_mode, rootdirs) if not success: - exit(1) + sys.exit(1) else: print("No problems found.") @@ -98,4 +98,4 @@ if __name__ == "__main__": try: main() except KeyboardInterrupt: - exit("Interrupted by user. Exiting.") + sys.exit("Interrupted by user. Exiting.") diff --git a/scripts/pylintrc b/scripts/pylintrc index 50dbebee0..15ad5700f 100644 --- a/scripts/pylintrc +++ b/scripts/pylintrc @@ -20,7 +20,6 @@ disable= bad-continuation, bad-indentation, bad-whitespace, - consider-using-sys-exit, duplicate-code, invalid-name, missing-docstring, diff --git a/test/lsp.py b/test/lsp.py index d558c20d9..fdaab9d88 100755 --- a/test/lsp.py +++ b/test/lsp.py @@ -5,6 +5,7 @@ import fnmatch import json import os import subprocess +import sys import traceback from typing import Any, List, Optional, Tuple, Union @@ -871,4 +872,4 @@ class SolidityLSPTestSuite: # {{{ if __name__ == "__main__": suite = SolidityLSPTestSuite() exit_code = suite.main() - exit(exit_code) + sys.exit(exit_code) From 784ae91b41be23f4059ec538e1a5281c237e1d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 21 Dec 2021 15:23:52 +0100 Subject: [PATCH 02/77] pylint: Enable and fix no-self-use warnings --- scripts/endToEndExtraction/verify-testcases.py | 3 ++- scripts/pylintrc | 1 - scripts/regressions.py | 3 ++- test/formal/rule.py | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/scripts/endToEndExtraction/verify-testcases.py b/scripts/endToEndExtraction/verify-testcases.py index 8e1c60a79..150a1806b 100755 --- a/scripts/endToEndExtraction/verify-testcases.py +++ b/scripts/endToEndExtraction/verify-testcases.py @@ -154,7 +154,8 @@ class TraceAnalyser: print(len(intersection), "test-cases - ", len(mismatches), " mismatche(s)") - def check_traces(self, test_name, left, right, mismatches): + @classmethod + def check_traces(cls, test_name, left, right, mismatches): for trace_id, trace in enumerate(left.traces): left_trace = trace right_trace = right.traces[trace_id] diff --git a/scripts/pylintrc b/scripts/pylintrc index 15ad5700f..a2b5839f5 100644 --- a/scripts/pylintrc +++ b/scripts/pylintrc @@ -24,7 +24,6 @@ disable= invalid-name, missing-docstring, no-else-return, - no-self-use, pointless-string-statement, redefined-builtin, redefined-outer-name, diff --git a/scripts/regressions.py b/scripts/regressions.py index 046044197..e30c0aeb9 100755 --- a/scripts/regressions.py +++ b/scripts/regressions.py @@ -41,7 +41,8 @@ class regressor: "build/test/tools/ossfuzz") self._logpath = os.path.join(self._repo_root, "test_results") - def parseCmdLine(self, description, args): + @classmethod + def parseCmdLine(cls, description, args): argParser = ArgumentParser(description) argParser.add_argument('-o', '--out-dir', required=True, type=str, help="""Directory where test results will be written""") diff --git a/test/formal/rule.py b/test/formal/rule.py index ac0f0c8a6..8fbf00688 100644 --- a/test/formal/rule.py +++ b/test/formal/rule.py @@ -39,6 +39,7 @@ class Rule: self.error('Rule is incorrect.\nModel: ' + str(m)) self.solver.pop() - def error(self, msg): + @classmethod + def error(cls, msg): print(msg) sys.exit(1) From 5b10ff1216696220a99e35841a7b11db6508c187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 21 Dec 2021 15:25:14 +0100 Subject: [PATCH 03/77] pylint: Enable and fix singleton-comparison warnings --- docs/conf.py | 2 +- scripts/error_codes.py | 2 +- scripts/pylintrc | 1 - scripts/splitSources.py | 2 +- test/lsp.py | 6 +++--- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 5fa2e6ab5..4ae4812c5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -73,7 +73,7 @@ copyright = '2016-2021, Ethereum' with open('../CMakeLists.txt', 'r', encoding='utf8') as f: version = re.search('PROJECT_VERSION "([^"]+)"', f.read()).group(1) # The full version, including alpha/beta/rc tags. -if os.path.isfile('../prerelease.txt') != True or os.path.getsize('../prerelease.txt') == 0: +if not os.path.isfile('../prerelease.txt') or os.path.getsize('../prerelease.txt') == 0: release = version else: # This is a prerelease version diff --git a/scripts/error_codes.py b/scripts/error_codes.py index 65158a0a6..402068d14 100755 --- a/scripts/error_codes.py +++ b/scripts/error_codes.py @@ -18,7 +18,7 @@ def read_file(file_name): with open(file_name, "r", encoding="latin-1" if is_latin else ENCODING) as f: content = f.read() finally: - if content == None: + if content is None: print(f"Error reading: {file_name}") return content diff --git a/scripts/pylintrc b/scripts/pylintrc index a2b5839f5..6835806b6 100644 --- a/scripts/pylintrc +++ b/scripts/pylintrc @@ -27,7 +27,6 @@ disable= pointless-string-statement, redefined-builtin, redefined-outer-name, - singleton-comparison, too-few-public-methods, too-many-public-methods, ungrouped-imports diff --git a/scripts/splitSources.py b/scripts/splitSources.py index 181741f9c..d31202fb7 100755 --- a/scripts/splitSources.py +++ b/scripts/splitSources.py @@ -40,7 +40,7 @@ def writeSourceToFile(lines): filePath, srcName = extractSourceName(lines[0]) # print("sourceName is ", srcName) # print("filePath is", filePath) - if filePath != False: + if filePath: os.system("mkdir -p " + filePath) with open(srcName, mode='a+', encoding='utf8', newline='') as f: createdSources.append(srcName) diff --git a/test/lsp.py b/test/lsp.py index fdaab9d88..f03d9bc09 100755 --- a/test/lsp.py +++ b/test/lsp.py @@ -50,7 +50,7 @@ class JsonRpcProcess: # Note, we should make use of timeout to avoid infinite blocking if nothing is received. CONTENT_LENGTH_HEADER = "Content-Length: " CONTENT_TYPE_HEADER = "Content-Type: " - if self.process.stdout == None: + if self.process.stdout is None: return None message_size = None while True: @@ -84,7 +84,7 @@ class JsonRpcProcess: return json_object def send_message(self, method_name: str, params: Optional[dict]) -> None: - if self.process.stdin == None: + if self.process.stdin is None: return message = { 'jsonrpc': '2.0', @@ -246,7 +246,7 @@ class SolidityLSPTestSuite: # {{{ } } } - if expose_project_root == False: + if not expose_project_root: params['rootUri'] = None lsp.call_method('initialize', params) lsp.send_notification('initialized') From dece5f4de2fb66df75ad0803a0295d3055b03907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 21 Dec 2021 15:26:54 +0100 Subject: [PATCH 04/77] pylint: Enable and fix redefined-builtin warnings --- docs/conf.py | 2 +- .../endToEndExtraction/remove-testcases.py | 4 +- .../endToEndExtraction/verify-testcases.py | 36 ++++++------ scripts/error_codes.py | 56 +++++++++---------- scripts/isolate_tests.py | 4 +- scripts/pylintrc | 3 +- .../docker-scripts/isolate_tests.py | 4 +- 7 files changed, 54 insertions(+), 55 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 4ae4812c5..10aa406f2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -63,7 +63,7 @@ master_doc = 'index' # General information about the project. project = 'Solidity' -copyright = '2016-2021, Ethereum' +project_copyright = '2016-2021, Ethereum' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/scripts/endToEndExtraction/remove-testcases.py b/scripts/endToEndExtraction/remove-testcases.py index 28822e044..ca9a63599 100755 --- a/scripts/endToEndExtraction/remove-testcases.py +++ b/scripts/endToEndExtraction/remove-testcases.py @@ -33,12 +33,12 @@ def parse_call(call): return function.strip(), arguments.strip(), results.strip() -def colorize(left, right, id): +def colorize(left, right, index): red = "\x1b[31m" yellow = "\x1b[33m" reset = "\x1b[0m" colors = [red, yellow] - color = colors[id % len(colors)] + color = colors[index % len(colors)] function, _arguments, _results = parse_call(right) left = left.replace("compileAndRun", color + "compileAndRun" + reset) right = right.replace("constructor", color + "constructor" + reset) diff --git a/scripts/endToEndExtraction/verify-testcases.py b/scripts/endToEndExtraction/verify-testcases.py index 150a1806b..87d608607 100755 --- a/scripts/endToEndExtraction/verify-testcases.py +++ b/scripts/endToEndExtraction/verify-testcases.py @@ -32,11 +32,11 @@ class Trace: def get_input(self): return self._input - def set_input(self, input): + def set_input(self, bytecode): if self.kind == "create": # remove cbor encoded metadata from bytecode - length = int(input[-4:], 16) * 2 - self._input = input[:len(input) - length - 4] + length = int(bytecode[-4:], 16) * 2 + self._input = bytecode[:len(bytecode) - length - 4] def get_output(self): return self._output @@ -110,21 +110,21 @@ class TraceAnalyser: @staticmethod def parse_parameters(line, trace): - input = re.search(r'\s*in:\s*([a-fA-F0-9]*)', line, re.M | re.I) - if input: - trace.input = input.group(1) - output = re.search(r'\s*out:\s*([a-fA-F0-9]*)', line, re.M | re.I) - if output: - trace.output = output.group(1) - result = re.search(r'\s*result:\s*([a-fA-F0-9]*)', line, re.M | re.I) - if result: - trace.result = result.group(1) - gas_used = re.search(r'\s*gas\sused:\s*([a-fA-F0-9]*)', line, re.M | re.I) - if gas_used: - trace.gas = gas_used.group(1) - value = re.search(r'\s*value:\s*([a-fA-F0-9]*)', line, re.M | re.I) - if value: - trace.value = value.group(1) + input_match = re.search(r'\s*in:\s*([a-fA-F0-9]*)', line, re.M | re.I) + if input_match: + trace.input = input_match.group(1) + output_match = re.search(r'\s*out:\s*([a-fA-F0-9]*)', line, re.M | re.I) + if output_match: + trace.output = output_match.group(1) + result_match = re.search(r'\s*result:\s*([a-fA-F0-9]*)', line, re.M | re.I) + if result_match: + trace.result = result_match.group(1) + gas_used_match = re.search(r'\s*gas\sused:\s*([a-fA-F0-9]*)', line, re.M | re.I) + if gas_used_match: + trace.gas = gas_used_match.group(1) + value_match = re.search(r'\s*value:\s*([a-fA-F0-9]*)', line, re.M | re.I) + if value_match: + trace.value = value_match.group(1) def diff(self, analyser): if not self.ready: diff --git a/scripts/error_codes.py b/scripts/error_codes.py index 402068d14..a50e34d0b 100755 --- a/scripts/error_codes.py +++ b/scripts/error_codes.py @@ -44,11 +44,11 @@ def find_ids_in_source_file(file_name, id_to_file_names): if in_comment(source, m.start()): continue underscore_pos = m.group(0).index("_") - id = m.group(0)[0:underscore_pos] - if id in id_to_file_names: - id_to_file_names[id].append(file_name) + error_id = m.group(0)[0:underscore_pos] + if error_id in id_to_file_names: + id_to_file_names[error_id].append(file_name) else: - id_to_file_names[id] = [file_name] + id_to_file_names[error_id] = [file_name] def find_ids_in_source_files(file_names): @@ -76,16 +76,16 @@ def fix_ids_in_source_file(file_name, id_to_count, available_ids): destination.extend(source[k:m.start()]) underscore_pos = m.group(0).index("_") - id = m.group(0)[0:underscore_pos] + error_id = m.group(0)[0:underscore_pos] # incorrect id or id has a duplicate somewhere - if not in_comment(source, m.start()) and (len(id) != 4 or id[0] == "0" or id_to_count[id] > 1): - assert id in id_to_count + if not in_comment(source, m.start()) and (len(error_id) != 4 or error_id[0] == "0" or id_to_count[error_id] > 1): + assert error_id in id_to_count new_id = get_next_id(available_ids) assert new_id not in id_to_count - id_to_count[id] -= 1 + id_to_count[error_id] -= 1 else: - new_id = id + new_id = error_id destination.extend(new_id + "_error") k = m.end() @@ -104,7 +104,7 @@ def fix_ids_in_source_files(file_names, id_to_count): id_to_count contains number of appearances of every id in sources """ - available_ids = {str(id) for id in range(1000, 10000)} - id_to_count.keys() + available_ids = {str(error_id) for error_id in range(1000, 10000)} - id_to_count.keys() for file_name in file_names: fix_ids_in_source_file(file_name, id_to_count, available_ids) @@ -113,8 +113,8 @@ def find_files(top_dir, sub_dirs, extensions): """Builds a list of files with given extensions in specified subdirectories""" source_file_names = [] - for dir in sub_dirs: - for root, _, file_names in os.walk(os.path.join(top_dir, dir), onerror=lambda e: exit(f"Walk error: {e}")): + for directory in sub_dirs: + for root, _, file_names in os.walk(os.path.join(top_dir, directory), onerror=lambda e: sys.exit(f"Walk error: {e}")): for file_name in file_names: _, ext = path.splitext(file_name) if ext in extensions: @@ -145,27 +145,27 @@ def find_ids_in_cmdline_test_err(file_name): def print_ids(ids): - for k, id in enumerate(sorted(ids)): + for k, error_id in enumerate(sorted(ids)): if k % 10 > 0: print(" ", end="") elif k > 0: print() - print(id, end="") + print(error_id, end="") def print_ids_per_file(ids, id_to_file_names, top_dir): file_name_to_ids = {} - for id in ids: - for file_name in id_to_file_names[id]: + for error_id in ids: + for file_name in id_to_file_names[error_id]: relpath = path.relpath(file_name, top_dir) if relpath not in file_name_to_ids: file_name_to_ids[relpath] = [] - file_name_to_ids[relpath].append(id) + file_name_to_ids[relpath].append(error_id) for file_name in sorted(file_name_to_ids): print(file_name) - for id in sorted(file_name_to_ids[file_name]): - print(f" {id}", end="") + for error_id in sorted(file_name_to_ids[file_name]): + print(f" {error_id}", end="") print() @@ -289,15 +289,15 @@ def main(argv): source_id_to_file_names = find_ids_in_source_files(source_file_names) ok = True - for id in sorted(source_id_to_file_names): - if len(id) != 4: - print(f"ID {id} length != 4") + for error_id in sorted(source_id_to_file_names): + if len(error_id) != 4: + print(f"ID {error_id} length != 4") ok = False - if id[0] == "0": - print(f"ID {id} starts with zero") + if error_id[0] == "0": + print(f"ID {error_id} starts with zero") ok = False - if len(source_id_to_file_names[id]) > 1: - print(f"ID {id} appears {len(source_id_to_file_names[id])} times") + if len(source_id_to_file_names[error_id]) > 1: + print(f"ID {error_id} appears {len(source_id_to_file_names[error_id])} times") ok = False if examine_coverage: @@ -315,7 +315,7 @@ def main(argv): if not ok: print("Incorrect IDs have to be fixed before applying --next") sys.exit(1) - available_ids = {str(id) for id in range(1000, 10000)} - source_id_to_file_names.keys() + available_ids = {str(error_id) for error_id in range(1000, 10000)} - source_id_to_file_names.keys() next_id = get_next_id(available_ids) print(f"Next ID: {next_id}") sys.exit(0) @@ -341,7 +341,7 @@ def main(argv): sys.exit(1) # number of appearances for every id - source_id_to_count = { id: len(file_names) for id, file_names in source_id_to_file_names.items() } + source_id_to_count = { error_id: len(file_names) for error_id, file_names in source_id_to_file_names.items() } fix_ids_in_source_files(source_file_names, source_id_to_count) print("Fixing completed") diff --git a/scripts/isolate_tests.py b/scripts/isolate_tests.py index 4abe6a0bd..e641d58d1 100755 --- a/scripts/isolate_tests.py +++ b/scripts/isolate_tests.py @@ -106,8 +106,8 @@ def write_cases(f, solidityTests, yulTests): # When code examples are extracted they are indented by 8 spaces, which violates the style guide, # so before checking remove 4 spaces from each line. remainder = dedent(test) - hash = hashlib.sha256(test.encode("utf-8")).hexdigest() - sol_filename = f'test_{hash}_{cleaned_filename}.{language}' + source_code_hash = hashlib.sha256(test.encode("utf-8")).hexdigest() + sol_filename = f'test_{source_code_hash}_{cleaned_filename}.{language}' with open(sol_filename, mode='w', encoding='utf8', newline='') as fi: fi.write(remainder) diff --git a/scripts/pylintrc b/scripts/pylintrc index 6835806b6..e14763c0d 100644 --- a/scripts/pylintrc +++ b/scripts/pylintrc @@ -14,7 +14,7 @@ # ATTENTION: This list should be extended with care, consider using NOLINT comments inside your # python files instead, as the goal is actually to reduce the list of globally disabled checks. # -# TODO: What could be eliminated in future PRs: bad-continuation, invalid-name, redefined-builtin, +# TODO: What could be eliminated in future PRs: bad-continuation, invalid-name, # undefined-variable, unused-*, useless-object-inheritance. disable= bad-continuation, @@ -25,7 +25,6 @@ disable= missing-docstring, no-else-return, pointless-string-statement, - redefined-builtin, redefined-outer-name, too-few-public-methods, too-many-public-methods, diff --git a/scripts/wasm-rebuild/docker-scripts/isolate_tests.py b/scripts/wasm-rebuild/docker-scripts/isolate_tests.py index c447c1e67..41487325e 100755 --- a/scripts/wasm-rebuild/docker-scripts/isolate_tests.py +++ b/scripts/wasm-rebuild/docker-scripts/isolate_tests.py @@ -47,8 +47,8 @@ def write_cases(f, tests): cleaned_filename = f.replace(".","_").replace("-","_").replace(" ","_").lower() for test in tests: remainder = re.sub(r'^ {4}', '', test, 0, re.MULTILINE) - hash = hashlib.sha256(test).hexdigest() - with open(f'test_{hash}_{cleaned_filename}.sol', 'w', encoding='utf8') as _f: + source_code_hash = hashlib.sha256(test).hexdigest() + with open(f'test_{source_code_hash}_{cleaned_filename}.sol', 'w', encoding='utf8') as _f: _f.write(remainder) From 589f4b2a833f1c79ae7844336eb0976a3039b70a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 21 Dec 2021 15:27:41 +0100 Subject: [PATCH 05/77] pylint: Enable bad-continuation and ungrouped-imports warnings and update the list of warnings to eliminate in the future --- scripts/pylintrc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/scripts/pylintrc b/scripts/pylintrc index e14763c0d..ffbd96fe8 100644 --- a/scripts/pylintrc +++ b/scripts/pylintrc @@ -14,10 +14,8 @@ # ATTENTION: This list should be extended with care, consider using NOLINT comments inside your # python files instead, as the goal is actually to reduce the list of globally disabled checks. # -# TODO: What could be eliminated in future PRs: bad-continuation, invalid-name, -# undefined-variable, unused-*, useless-object-inheritance. +# TODO: What could be eliminated in future PRs: invalid-name, pointless-string-statement, redefined-outer-name. disable= - bad-continuation, bad-indentation, bad-whitespace, duplicate-code, @@ -27,8 +25,7 @@ disable= pointless-string-statement, redefined-outer-name, too-few-public-methods, - too-many-public-methods, - ungrouped-imports + too-many-public-methods [BASIC] From de364c566c52b351eb7519b6c947ffda61f76c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 21 Dec 2021 15:19:32 +0100 Subject: [PATCH 06/77] pylint: Disable the opinionated too-many-xyz warnings --- scripts/bytecodecompare/prepare_report.py | 6 +++--- scripts/endToEndExtraction/verify-testcases.py | 2 -- scripts/error_codes.py | 2 -- scripts/pylintrc | 8 +++++++- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/scripts/bytecodecompare/prepare_report.py b/scripts/bytecodecompare/prepare_report.py index 9d35b9988..dd317735f 100755 --- a/scripts/bytecodecompare/prepare_report.py +++ b/scripts/bytecodecompare/prepare_report.py @@ -187,7 +187,7 @@ def parse_cli_output(source_file_name: Path, cli_output: str) -> FileReport: return file_report -def prepare_compiler_input( # pylint: disable=too-many-arguments +def prepare_compiler_input( compiler_path: Path, source_file_name: Path, optimize: bool, @@ -256,7 +256,7 @@ def detect_metadata_cli_option_support(compiler_path: Path): return process.returncode == 0 -def run_compiler( # pylint: disable=too-many-arguments +def run_compiler( compiler_path: Path, source_file_name: Path, optimize: bool, @@ -320,7 +320,7 @@ def run_compiler( # pylint: disable=too-many-arguments return parse_cli_output(Path(source_file_name), process.stdout) -def generate_report( # pylint: disable=too-many-arguments,too-many-locals +def generate_report( source_file_names: List[str], compiler_path: Path, interface: CompilerInterface, diff --git a/scripts/endToEndExtraction/verify-testcases.py b/scripts/endToEndExtraction/verify-testcases.py index 87d608607..b01187042 100755 --- a/scripts/endToEndExtraction/verify-testcases.py +++ b/scripts/endToEndExtraction/verify-testcases.py @@ -9,8 +9,6 @@ # # verify-testcases.py will compare both traces. If these traces are identical, the extracted tests were # identical with the tests specified in SolidityEndToEndTest.cpp. -# -# pylint: disable=too-many-instance-attributes import re import os diff --git a/scripts/error_codes.py b/scripts/error_codes.py index a50e34d0b..f3d35cae4 100755 --- a/scripts/error_codes.py +++ b/scripts/error_codes.py @@ -254,8 +254,6 @@ def examine_id_coverage(top_dir, source_id_to_file_names, new_ids_only=False): def main(argv): - # pylint: disable=too-many-branches, too-many-locals, too-many-statements - check = False fix = False no_confirm = False diff --git a/scripts/pylintrc b/scripts/pylintrc index ffbd96fe8..02d529567 100644 --- a/scripts/pylintrc +++ b/scripts/pylintrc @@ -25,7 +25,13 @@ disable= pointless-string-statement, redefined-outer-name, too-few-public-methods, - too-many-public-methods + too-many-arguments, + too-many-branches, + too-many-instance-attributes, + too-many-locals, + too-many-public-methods, + too-many-statements, + ungrouped-imports [BASIC] From 7e91dba663a738b2053f231ffd355484bbbb1fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 27 Oct 2021 13:02:42 +0200 Subject: [PATCH 07/77] Switch ens external test to ens-contracts repo --- .circleci/config.yml | 4 ++-- test/externalTests/common.sh | 21 +++++++++++++++++++-- test/externalTests/ens.sh | 35 +++++++++++++++++------------------ 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 611675a26..164802b37 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1363,8 +1363,8 @@ workflows: name: t_native_test_ext_ens project: ens binary_type: native - # NOTE: One of the dependencies (fsevents) fails to build its native extension on node.js 12+. - nodejs_version: '10' + # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" + nodejs_version: '16' # Windows build and tests - b_win: *workflow_trigger_on_tags diff --git a/test/externalTests/common.sh b/test/externalTests/common.sh index 400304f3b..d394a0b5f 100644 --- a/test/externalTests/common.sh +++ b/test/externalTests/common.sh @@ -117,6 +117,19 @@ function neutralize_package_json_hooks sed -i 's|"prepare": *".*"|"prepare": ""|g' package.json } +function neutralize_packaged_contracts +{ + # Frameworks will build contracts from any package that contains a configuration file. + # This is both unnecessary (any files imported from these packages will get compiled again as a + # part of the main project anyway) and trips up our version check because it won't use our + # custom compiler binary. + printLog "Removing framework config and artifacts from npm packages..." + find node_modules/ -type f '(' -name 'hardhat.config.*' -o -name 'truffle-config.*' ')' -delete + + # Some npm packages also come packaged with pre-built artifacts. + find node_modules/ -path '*artifacts/build-info/*.json' -delete +} + function force_solc_modules { local custom_solcjs_path="${1:-solc/}" @@ -216,8 +229,12 @@ function hardhat_verify_compiler_version local full_solc_version="$2" printLog "Verify that the correct version (${solc_version}/${full_solc_version}) of the compiler was used to compile the contracts..." - grep '"solcVersion": "'"${solc_version}"'"' --with-filename artifacts/build-info/*.json || fail "Wrong compiler version detected." - grep '"solcLongVersion": "'"${full_solc_version}"'"' --with-filename artifacts/build-info/*.json || fail "Wrong compiler version detected." + local build_info_files + build_info_files=$(find . -path '*artifacts/build-info/*.json') + for build_info_file in $build_info_files; do + grep '"solcVersion": "'"${solc_version}"'"' --with-filename "$build_info_file" || fail "Wrong compiler version detected in ${build_info_file}." + grep '"solcLongVersion": "'"${full_solc_version}"'"' --with-filename "$build_info_file" || fail "Wrong compiler version detected in ${build_info_file}." + done } function truffle_clean diff --git a/test/externalTests/ens.sh b/test/externalTests/ens.sh index f425f97cf..2b663cf84 100755 --- a/test/externalTests/ens.sh +++ b/test/externalTests/ens.sh @@ -28,22 +28,23 @@ verify_input "$@" BINARY_TYPE="$1" BINARY_PATH="$2" -function compile_fn { npx truffle compile; } -function test_fn { npm run test; } +function compile_fn { yarn build; } +function test_fn { yarn test; } function ens_test { - local repo="https://github.com/ensdomains/ens.git" - local branch=master - local config_file="truffle.js" + local repo="https://github.com/ensdomains/ens-contracts.git" + local branch="v0.0.8" # The project is in flux right now and master might be too unstable for us + local config_file="hardhat.config.js" - local compile_only_presets=() + local compile_only_presets=( + legacy-no-optimize # Compiles but tests fail to deploy GovernorCompatibilityBravo (code too large). + ) local settings_presets=( "${compile_only_presets[@]}" - #ir-no-optimize # "YulException: Variable var_ttl_236 is 1 slot(s) too deep inside the stack." - #ir-optimize-evm-only # "YulException: Variable var_ttl_236 is 1 slot(s) too deep inside the stack." - ir-optimize-evm+yul - legacy-no-optimize + #ir-no-optimize # Compilation fails with "YulException: Variable var__945 is 1 slot(s) too deep inside the stack." + #ir-optimize-evm-only # Compilation fails with "YulException: Variable var__945 is 1 slot(s) too deep inside the stack." + #ir-optimize-evm+yul # Compilation fails with "YulException: Variable _5 is 1 too deep in the stack [ _5 usr$i usr$h _7 usr$scratch usr$k usr$f _4 usr$len usr$j_2 RET _2 _1 var_data_mpos usr$totallen usr$x _12 ]" legacy-optimize-evm-only legacy-optimize-evm+yul ) @@ -56,20 +57,18 @@ function ens_test download_project "$repo" "$branch" "$DIR" [[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH" - # Use latest Truffle. Older versions crash on the output from 0.8.0. - force_truffle_version ^5.1.55 - neutralize_package_lock neutralize_package_json_hooks - force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$(first_word "$selected_optimizer_presets")" - npm install + force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" + force_hardhat_compiler_settings "$config_file" "$(first_word "$selected_optimizer_presets")" + yarn install replace_version_pragmas - [[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc" + neutralize_packaged_contracts for preset in $selected_optimizer_presets; do - truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$preset" "${compile_only_presets[*]}" compile_fn test_fn + hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn done } -external_test Ens ens_test +external_test ENS ens_test From 4fa8eee6830aeed60f551d34c197f89d227b2604 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 20 Dec 2021 13:38:03 +0100 Subject: [PATCH 08/77] Use function names instead of members. --- libsolidity/ast/Types.cpp | 86 +++++++++++++++++++-------------------- libsolidity/ast/Types.h | 2 +- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index aa1d5820f..ed16d2b35 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2942,11 +2942,11 @@ string FunctionType::richIdentifier() const } id += "_" + stateMutabilityToString(m_stateMutability); id += identifierList(m_parameterTypes) + "returns" + identifierList(m_returnParameterTypes); - if (m_gasSet) + if (gasSet()) id += "gas"; - if (m_valueSet) + if (valueSet()) id += "value"; - if (m_saltSet) + if (saltSet()) id += "salt"; if (bound()) id += "bound_to" + identifierList(selfType()); @@ -3094,11 +3094,11 @@ bool FunctionType::nameable() const { return (m_kind == Kind::Internal || m_kind == Kind::External) && - !m_bound && - !m_arbitraryParameters && - !m_gasSet && - !m_valueSet && - !m_saltSet; + !bound() && + !takesArbitraryParameters() && + !gasSet() && + !valueSet() && + !saltSet(); } vector> FunctionType::makeStackItems() const @@ -3140,11 +3140,11 @@ vector> FunctionType::makeStackItems() const break; } - if (m_gasSet) + if (gasSet()) slots.emplace_back("gas", TypeProvider::uint256()); - if (m_valueSet) + if (valueSet()) slots.emplace_back("value", TypeProvider::uint256()); - if (m_saltSet) + if (saltSet()) slots.emplace_back("salt", TypeProvider::fixedBytes(32)); if (bound()) slots.emplace_back("self", m_parameterTypes.front()); @@ -3182,7 +3182,7 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const m_parameterNames, m_returnParameterNames, m_kind, - m_arbitraryParameters, + takesArbitraryParameters(), m_stateMutability, m_declaration ); @@ -3240,9 +3240,9 @@ MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const false, StateMutability::Pure, nullptr, - m_gasSet, - m_valueSet, - m_saltSet + gasSet(), + valueSet(), + saltSet() ) ); } @@ -3258,9 +3258,9 @@ MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const false, StateMutability::Pure, nullptr, - m_gasSet, - m_valueSet, - m_saltSet + gasSet(), + valueSet(), + saltSet() ) ); return members; @@ -3288,7 +3288,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const Type const* FunctionType::encodingType() const { - if (m_gasSet || m_valueSet) + if (gasSet() || valueSet()) return nullptr; // Only external functions can be encoded, internal functions cannot leave code boundaries. if (m_kind == Kind::External) @@ -3307,7 +3307,7 @@ TypeResult FunctionType::interfaceType(bool /*_inLibrary*/) const Type const* FunctionType::mobileType() const { - if (m_valueSet || m_gasSet || m_saltSet || m_bound) + if (valueSet() || gasSet() || saltSet() || bound()) return nullptr; // return function without parameter names @@ -3317,13 +3317,13 @@ Type const* FunctionType::mobileType() const strings(m_parameterTypes.size()), strings(m_returnParameterNames.size()), m_kind, - m_arbitraryParameters, + takesArbitraryParameters(), m_stateMutability, m_declaration, - m_gasSet, - m_valueSet, - m_bound, - m_saltSet + gasSet(), + valueSet(), + bound(), + saltSet() ); } @@ -3409,7 +3409,7 @@ bool FunctionType::equalExcludingStateMutability(FunctionType const& _other) con return false; //@todo this is ugly, but cannot be prevented right now - if (m_gasSet != _other.m_gasSet || m_valueSet != _other.m_valueSet || m_saltSet != _other.m_saltSet) + if (gasSet() != _other.gasSet() || valueSet() != _other.valueSet() || saltSet() != _other.saltSet()) return false; if (bound() != _other.bound()) @@ -3526,34 +3526,34 @@ Type const* FunctionType::copyAndSetCallOptions(bool _setGas, bool _setValue, bo m_parameterNames, m_returnParameterNames, m_kind, - m_arbitraryParameters, + takesArbitraryParameters(), m_stateMutability, m_declaration, - m_gasSet || _setGas, - m_valueSet || _setValue, - m_saltSet || _setSalt, - m_bound + gasSet() || _setGas, + valueSet() || _setValue, + saltSet() || _setSalt, + bound() ); } FunctionTypePointer FunctionType::asBoundFunction() const { solAssert(!m_parameterTypes.empty(), ""); - solAssert(!m_gasSet, ""); - solAssert(!m_valueSet, ""); - solAssert(!m_saltSet, ""); + solAssert(!gasSet(), ""); + solAssert(!valueSet(), ""); + solAssert(!saltSet(), ""); return TypeProvider::function( m_parameterTypes, m_returnParameterTypes, m_parameterNames, m_returnParameterNames, m_kind, - m_arbitraryParameters, + takesArbitraryParameters(), m_stateMutability, m_declaration, - m_gasSet, - m_valueSet, - m_saltSet, + gasSet(), + valueSet(), + saltSet(), true ); } @@ -3592,13 +3592,13 @@ FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary) m_parameterNames, m_returnParameterNames, kind, - m_arbitraryParameters, + takesArbitraryParameters(), m_stateMutability, m_declaration, - m_gasSet, - m_valueSet, - m_saltSet, - m_bound + gasSet(), + valueSet(), + saltSet(), + bound() ); } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 8b3826ca0..94ee41052 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -1314,7 +1314,7 @@ public: "Return parameter names list must match return parameter types list!" ); solAssert( - !m_bound || !m_parameterTypes.empty(), + !bound() || !m_parameterTypes.empty(), "Attempted construction of bound function without self type" ); } From f94279a4374a05ec3c253449ed3b11e2d8ee0c54 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 20 Dec 2021 12:40:43 +0100 Subject: [PATCH 09/77] Use options struct for function type factory function. --- libsolidity/analysis/GlobalContext.cpp | 32 ++++----- libsolidity/analysis/TypeChecker.cpp | 1 - libsolidity/ast/TypeProvider.cpp | 29 ++++---- libsolidity/ast/TypeProvider.h | 10 +-- libsolidity/ast/Types.cpp | 94 +++++++++++--------------- libsolidity/ast/Types.h | 32 +++++++++ 6 files changed, 107 insertions(+), 91 deletions(-) diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index 17d5b8c3e..58ebea7b1 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -73,24 +73,24 @@ inline vector> constructMagicVariable return { magicVarDecl("abi", TypeProvider::magic(MagicType::Kind::ABI)), - magicVarDecl("addmod", TypeProvider::function(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, false, StateMutability::Pure)), - magicVarDecl("assert", TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Assert, false, StateMutability::Pure)), + magicVarDecl("addmod", TypeProvider::function(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, StateMutability::Pure)), + magicVarDecl("assert", TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Assert, StateMutability::Pure)), magicVarDecl("block", TypeProvider::magic(MagicType::Kind::Block)), - magicVarDecl("blockhash", TypeProvider::function(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)), - magicVarDecl("ecrecover", TypeProvider::function(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, false, StateMutability::Pure)), - magicVarDecl("gasleft", TypeProvider::function(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, false, StateMutability::View)), - magicVarDecl("keccak256", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)), + magicVarDecl("blockhash", TypeProvider::function(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, StateMutability::View)), + magicVarDecl("ecrecover", TypeProvider::function(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, StateMutability::Pure)), + magicVarDecl("gasleft", TypeProvider::function(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, StateMutability::View)), + magicVarDecl("keccak256", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, StateMutability::Pure)), magicVarDecl("msg", TypeProvider::magic(MagicType::Kind::Message)), - magicVarDecl("mulmod", TypeProvider::function(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod, false, StateMutability::Pure)), + magicVarDecl("mulmod", TypeProvider::function(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::MulMod, StateMutability::Pure)), magicVarDecl("now", TypeProvider::uint256()), - magicVarDecl("require", TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)), - magicVarDecl("require", TypeProvider::function(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, false, StateMutability::Pure)), - magicVarDecl("revert", TypeProvider::function(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), - magicVarDecl("revert", TypeProvider::function(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), - magicVarDecl("ripemd160", TypeProvider::function(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, false, StateMutability::Pure)), + magicVarDecl("require", TypeProvider::function(strings{"bool"}, strings{}, FunctionType::Kind::Require, StateMutability::Pure)), + magicVarDecl("require", TypeProvider::function(strings{"bool", "string memory"}, strings{}, FunctionType::Kind::Require, StateMutability::Pure)), + magicVarDecl("revert", TypeProvider::function(strings(), strings(), FunctionType::Kind::Revert, StateMutability::Pure)), + magicVarDecl("revert", TypeProvider::function(strings{"string memory"}, strings(), FunctionType::Kind::Revert, StateMutability::Pure)), + magicVarDecl("ripemd160", TypeProvider::function(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, StateMutability::Pure)), magicVarDecl("selfdestruct", TypeProvider::function(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)), - magicVarDecl("sha256", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)), - magicVarDecl("sha3", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)), + magicVarDecl("sha256", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, StateMutability::Pure)), + magicVarDecl("sha3", TypeProvider::function(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, StateMutability::Pure)), magicVarDecl("suicide", TypeProvider::function(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)), magicVarDecl("tx", TypeProvider::magic(MagicType::Kind::Transaction)), // Accepts a MagicType that can be any contract type or an Integer type and returns a @@ -99,8 +99,8 @@ inline vector> constructMagicVariable strings{}, strings{}, FunctionType::Kind::MetaType, - true, - StateMutability::Pure + StateMutability::Pure, + FunctionType::Options::withArbitraryParameters() )), }; } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index d6c589f75..be8275a93 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -2866,7 +2866,6 @@ void TypeChecker::endVisit(NewExpression const& _newExpression) strings(1, ""), strings(1, ""), FunctionType::Kind::ObjectCreation, - false, StateMutability::Pure ); _newExpression.annotation().isPure = true; diff --git a/libsolidity/ast/TypeProvider.cpp b/libsolidity/ast/TypeProvider.cpp index 6183493b4..f5af82f94 100644 --- a/libsolidity/ast/TypeProvider.cpp +++ b/libsolidity/ast/TypeProvider.cpp @@ -445,13 +445,18 @@ FunctionType const* TypeProvider::function( strings const& _parameterTypes, strings const& _returnParameterTypes, FunctionType::Kind _kind, - bool _arbitraryParameters, - StateMutability _stateMutability + StateMutability _stateMutability, + FunctionType::Options _options ) { + // Can only use this constructor for "arbitraryParameters". + solAssert(!_options.valueSet && !_options.gasSet && !_options.saltSet && !_options.bound); return createAndGet( - _parameterTypes, _returnParameterTypes, - _kind, _arbitraryParameters, _stateMutability + _parameterTypes, + _returnParameterTypes, + _kind, + _options.arbitraryParameters, + _stateMutability ); } @@ -461,13 +466,9 @@ FunctionType const* TypeProvider::function( strings _parameterNames, strings _returnParameterNames, FunctionType::Kind _kind, - bool _arbitraryParameters, StateMutability _stateMutability, Declaration const* _declaration, - bool _gasSet, - bool _valueSet, - bool _bound, - bool _saltSet + FunctionType::Options _options ) { return createAndGet( @@ -476,13 +477,13 @@ FunctionType const* TypeProvider::function( _parameterNames, _returnParameterNames, _kind, - _arbitraryParameters, + _options.arbitraryParameters, _stateMutability, _declaration, - _gasSet, - _valueSet, - _bound, - _saltSet + _options.gasSet, + _options.valueSet, + _options.saltSet, + _options.bound ); } diff --git a/libsolidity/ast/TypeProvider.h b/libsolidity/ast/TypeProvider.h index 78b8378ca..b089ff1ef 100644 --- a/libsolidity/ast/TypeProvider.h +++ b/libsolidity/ast/TypeProvider.h @@ -149,8 +149,8 @@ public: strings const& _parameterTypes, strings const& _returnParameterTypes, FunctionType::Kind _kind = FunctionType::Kind::Internal, - bool _arbitraryParameters = false, - StateMutability _stateMutability = StateMutability::NonPayable + StateMutability _stateMutability = StateMutability::NonPayable, + FunctionType::Options _options = {} ); /// @returns a highly customized FunctionType, use with care. @@ -160,13 +160,9 @@ public: strings _parameterNames = strings{}, strings _returnParameterNames = strings{}, FunctionType::Kind _kind = FunctionType::Kind::Internal, - bool _arbitraryParameters = false, StateMutability _stateMutability = StateMutability::NonPayable, Declaration const* _declaration = nullptr, - bool _gasSet = false, - bool _valueSet = false, - bool _bound = false, - bool _saltSet = false + FunctionType::Options _options = {} ); /// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index ed16d2b35..da2811a21 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -470,15 +470,15 @@ MemberList::MemberMap AddressType::nativeMembers(ASTNode const*) const {"balance", TypeProvider::uint256()}, {"code", TypeProvider::array(DataLocation::Memory)}, {"codehash", TypeProvider::fixedBytes(32)}, - {"call", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, false, StateMutability::Payable)}, - {"callcode", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCallCode, false, StateMutability::Payable)}, - {"delegatecall", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareDelegateCall, false, StateMutability::NonPayable)}, - {"staticcall", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, false, StateMutability::View)} + {"call", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCall, StateMutability::Payable)}, + {"callcode", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareCallCode, StateMutability::Payable)}, + {"delegatecall", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareDelegateCall, StateMutability::NonPayable)}, + {"staticcall", TypeProvider::function(strings{"bytes memory"}, strings{"bool", "bytes memory"}, FunctionType::Kind::BareStaticCall, StateMutability::View)} }; if (m_stateMutability == StateMutability::Payable) { - members.emplace_back(MemberList::Member{"send", TypeProvider::function(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send, false, StateMutability::NonPayable)}); - members.emplace_back(MemberList::Member{"transfer", TypeProvider::function(strings{"uint"}, strings(), FunctionType::Kind::Transfer, false, StateMutability::NonPayable)}); + members.emplace_back(MemberList::Member{"send", TypeProvider::function(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send, StateMutability::NonPayable)}); + members.emplace_back(MemberList::Member{"transfer", TypeProvider::function(strings{"uint"}, strings(), FunctionType::Kind::Transfer, StateMutability::NonPayable)}); } return members; } @@ -2848,7 +2848,6 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c parameterNames, strings{""}, Kind::Creation, - false, stateMutability ); } @@ -3176,13 +3175,13 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const if (variable && retParamTypes.get().empty()) return FunctionTypePointer(); + solAssert(!takesArbitraryParameters()); return TypeProvider::function( paramTypes, retParamTypes, m_parameterNames, m_returnParameterNames, m_kind, - takesArbitraryParameters(), m_stateMutability, m_declaration ); @@ -3237,12 +3236,9 @@ MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const strings(1, ""), strings(1, ""), Kind::SetValue, - false, StateMutability::Pure, nullptr, - gasSet(), - valueSet(), - saltSet() + Options::fromFunctionType(*this) ) ); } @@ -3255,12 +3251,9 @@ MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const strings(1, ""), strings(1, ""), Kind::SetGas, - false, StateMutability::Pure, nullptr, - gasSet(), - valueSet(), - saltSet() + Options::fromFunctionType(*this) ) ); return members; @@ -3317,13 +3310,9 @@ Type const* FunctionType::mobileType() const strings(m_parameterTypes.size()), strings(m_returnParameterNames.size()), m_kind, - takesArbitraryParameters(), m_stateMutability, m_declaration, - gasSet(), - valueSet(), - bound(), - saltSet() + Options::fromFunctionType(*this) ); } @@ -3520,19 +3509,19 @@ TypePointers FunctionType::parseElementaryTypeVector(strings const& _types) Type const* FunctionType::copyAndSetCallOptions(bool _setGas, bool _setValue, bool _setSalt) const { solAssert(m_kind != Kind::Declaration, ""); + Options options = Options::fromFunctionType(*this); + if (_setGas) options.gasSet = true; + if (_setValue) options.valueSet = true; + if (_setSalt) options.saltSet = true; return TypeProvider::function( m_parameterTypes, m_returnParameterTypes, m_parameterNames, m_returnParameterNames, m_kind, - takesArbitraryParameters(), m_stateMutability, m_declaration, - gasSet() || _setGas, - valueSet() || _setValue, - saltSet() || _setSalt, - bound() + options ); } @@ -3542,19 +3531,17 @@ FunctionTypePointer FunctionType::asBoundFunction() const solAssert(!gasSet(), ""); solAssert(!valueSet(), ""); solAssert(!saltSet(), ""); + Options options = Options::fromFunctionType(*this); + options.bound = true; return TypeProvider::function( m_parameterTypes, m_returnParameterTypes, m_parameterNames, m_returnParameterNames, m_kind, - takesArbitraryParameters(), m_stateMutability, m_declaration, - gasSet(), - valueSet(), - saltSet(), - true + options ); } @@ -3592,13 +3579,9 @@ FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary) m_parameterNames, m_returnParameterNames, kind, - takesArbitraryParameters(), m_stateMutability, m_declaration, - gasSet(), - valueSet(), - saltSet(), - bound() + Options::fromFunctionType(*this) ); } @@ -3803,7 +3786,6 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons strings{string{}}, strings{string{}}, FunctionType::Kind::Wrap, - false, /*_arbitraryParameters */ StateMutability::Pure ) ); @@ -3815,7 +3797,6 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons strings{string{}}, strings{string{}}, FunctionType::Kind::Unwrap, - false, /* _arbitraryParameters */ StateMutability::Pure ) ); @@ -3830,8 +3811,9 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons strings{}, strings{string()}, FunctionType::Kind::BytesConcat, - /* _arbitraryParameters */ true, - StateMutability::Pure + StateMutability::Pure, + nullptr, + FunctionType::Options::withArbitraryParameters() )); return members; @@ -3954,7 +3936,7 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const return MemberList::MemberMap({ {"coinbase", TypeProvider::payableAddress()}, {"timestamp", TypeProvider::uint256()}, - {"blockhash", TypeProvider::function(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)}, + {"blockhash", TypeProvider::function(strings{"uint"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, StateMutability::View)}, {"difficulty", TypeProvider::uint256()}, {"number", TypeProvider::uint256()}, {"gaslimit", TypeProvider::uint256()}, @@ -3982,8 +3964,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const strings{}, strings{1, ""}, FunctionType::Kind::ABIEncode, - true, - StateMutability::Pure + StateMutability::Pure, + nullptr, + FunctionType::Options::withArbitraryParameters() )}, {"encodePacked", TypeProvider::function( TypePointers{}, @@ -3991,8 +3974,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const strings{}, strings{1, ""}, FunctionType::Kind::ABIEncodePacked, - true, - StateMutability::Pure + StateMutability::Pure, + nullptr, + FunctionType::Options::withArbitraryParameters() )}, {"encodeWithSelector", TypeProvider::function( TypePointers{TypeProvider::fixedBytes(4)}, @@ -4000,8 +3984,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const strings{1, ""}, strings{1, ""}, FunctionType::Kind::ABIEncodeWithSelector, - true, - StateMutability::Pure + StateMutability::Pure, + nullptr, + FunctionType::Options::withArbitraryParameters() )}, {"encodeCall", TypeProvider::function( TypePointers{}, @@ -4009,8 +3994,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const strings{}, strings{1, ""}, FunctionType::Kind::ABIEncodeCall, - true, - StateMutability::Pure + StateMutability::Pure, + nullptr, + FunctionType::Options::withArbitraryParameters() )}, {"encodeWithSignature", TypeProvider::function( TypePointers{TypeProvider::array(DataLocation::Memory, true)}, @@ -4018,8 +4004,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const strings{1, ""}, strings{1, ""}, FunctionType::Kind::ABIEncodeWithSignature, - true, - StateMutability::Pure + StateMutability::Pure, + nullptr, + FunctionType::Options::withArbitraryParameters() )}, {"decode", TypeProvider::function( TypePointers(), @@ -4027,8 +4014,9 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const strings{}, strings{}, FunctionType::Kind::ABIDecode, - true, - StateMutability::Pure + StateMutability::Pure, + nullptr, + FunctionType::Options::withArbitraryParameters() )} }); case Kind::MetaType: diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 94ee41052..dc6bda477 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -1247,6 +1247,38 @@ public: /// Cannot be called. Declaration, }; + struct Options + { + /// true iff the function takes an arbitrary number of arguments of arbitrary types + bool arbitraryParameters = false; + /// true iff the gas value to be used is on the stack + bool gasSet = false; + /// true iff the value to be sent is on the stack + bool valueSet = false; + /// iff the salt value (for create2) to be used is on the stack + bool saltSet = false; + /// true iff the function is called as arg1.fun(arg2, ..., argn). + /// This is achieved through the "using for" directive. + bool bound = false; + + static Options withArbitraryParameters() + { + Options result; + result.arbitraryParameters = true; + return result; + } + static Options fromFunctionType(FunctionType const& _type) + { + Options result; + result.arbitraryParameters = _type.takesArbitraryParameters(); + result.gasSet = _type.gasSet(); + result.valueSet = _type.valueSet(); + result.saltSet = _type.saltSet(); + result.bound = _type.bound(); + return result; + } + }; + /// Creates the type of a function. /// @arg _kind must be Kind::Internal, Kind::External or Kind::Declaration. From 7620bfaad8adb9b21a8826c7bcc02a424fbbea39 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 20 Dec 2021 13:23:40 +0100 Subject: [PATCH 10/77] Add option member for function type. --- libsolidity/ast/TypeProvider.cpp | 10 ++---- libsolidity/ast/Types.h | 42 ++++++++-------------- libsolidity/codegen/ExpressionCompiler.cpp | 9 +++-- 3 files changed, 24 insertions(+), 37 deletions(-) diff --git a/libsolidity/ast/TypeProvider.cpp b/libsolidity/ast/TypeProvider.cpp index f5af82f94..97d230d2e 100644 --- a/libsolidity/ast/TypeProvider.cpp +++ b/libsolidity/ast/TypeProvider.cpp @@ -455,8 +455,8 @@ FunctionType const* TypeProvider::function( _parameterTypes, _returnParameterTypes, _kind, - _options.arbitraryParameters, - _stateMutability + _stateMutability, + std::move(_options) ); } @@ -477,13 +477,9 @@ FunctionType const* TypeProvider::function( _parameterNames, _returnParameterNames, _kind, - _options.arbitraryParameters, _stateMutability, _declaration, - _options.gasSet, - _options.valueSet, - _options.saltSet, - _options.bound + std::move(_options) ); } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index dc6bda477..2f7e6005b 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -1295,18 +1295,21 @@ public: strings const& _parameterTypes, strings const& _returnParameterTypes, Kind _kind, - bool _arbitraryParameters = false, - StateMutability _stateMutability = StateMutability::NonPayable + StateMutability _stateMutability = StateMutability::NonPayable, + Options _options = Options{false, false, false, false, false} ): FunctionType( parseElementaryTypeVector(_parameterTypes), parseElementaryTypeVector(_returnParameterTypes), strings(_parameterTypes.size(), ""), strings(_returnParameterTypes.size(), ""), _kind, - _arbitraryParameters, - _stateMutability + _stateMutability, + nullptr, + std::move(_options) ) { + // In this constructor, only the "arbitrary Parameters" option should be used. + solAssert(!bound() && !gasSet() && !valueSet() && !saltSet()); } /// Detailed constructor, use with care. @@ -1316,13 +1319,9 @@ public: strings _parameterNames = strings(), strings _returnParameterNames = strings(), Kind _kind = Kind::Internal, - bool _arbitraryParameters = false, StateMutability _stateMutability = StateMutability::NonPayable, Declaration const* _declaration = nullptr, - bool _gasSet = false, - bool _valueSet = false, - bool _saltSet = false, - bool _bound = false + Options _options = Options{false, false, false, false, false} ): m_parameterTypes(std::move(_parameterTypes)), m_returnParameterTypes(std::move(_returnParameterTypes)), @@ -1330,12 +1329,8 @@ public: m_returnParameterNames(std::move(_returnParameterNames)), m_kind(_kind), m_stateMutability(_stateMutability), - m_arbitraryParameters(_arbitraryParameters), - m_gasSet(_gasSet), - m_valueSet(_valueSet), - m_bound(_bound), m_declaration(_declaration), - m_saltSet(_saltSet) + m_options(std::move(_options)) { solAssert( m_parameterNames.size() == m_parameterTypes.size(), @@ -1440,7 +1435,7 @@ public: /// The only functions that do not pad are hash functions, the low-level call functions /// and abi.encodePacked. bool padArguments() const; - bool takesArbitraryParameters() const { return m_arbitraryParameters; } + bool takesArbitraryParameters() const { return m_options.arbitraryParameters; } /// true iff the function takes a single bytes parameter and it is passed on without padding. bool takesSinglePackedBytesParameter() const { @@ -1459,10 +1454,10 @@ public: } } - bool gasSet() const { return m_gasSet; } - bool valueSet() const { return m_valueSet; } - bool saltSet() const { return m_saltSet; } - bool bound() const { return m_bound; } + bool gasSet() const { return m_options.gasSet; } + bool valueSet() const { return m_options.valueSet; } + bool saltSet() const { return m_options.saltSet; } + bool bound() const { return m_options.bound; } /// @returns a copy of this type, where gas or value are set manually. This will never set one /// of the parameters to false. @@ -1490,15 +1485,8 @@ private: std::vector m_returnParameterNames; Kind const m_kind; StateMutability m_stateMutability = StateMutability::NonPayable; - /// true if the function takes an arbitrary number of arguments of arbitrary types - bool const m_arbitraryParameters = false; - bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack - bool const m_valueSet = false; ///< true iff the value to be sent is on the stack - /// true iff the function is called as arg1.fun(arg2, ..., argn). - /// This is achieved through the "using for" directive. - bool const m_bound = false; Declaration const* m_declaration = nullptr; - bool m_saltSet = false; ///< true iff the salt value to be used is on the stack + Options const m_options; }; /** diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 5a633d2e6..a54a2dd4f 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -780,6 +780,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) break; case FunctionType::Kind::Send: case FunctionType::Kind::Transfer: + { _functionCall.expression().accept(*this); // Provide the gas stipend manually at first because we may send zero ether. // Will be zeroed if we send more than zero ether. @@ -788,6 +789,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) // gas <- gas * !value m_context << Instruction::SWAP1 << Instruction::DUP2; m_context << Instruction::ISZERO << Instruction::MUL << Instruction::SWAP1; + FunctionType::Options callOptions; + callOptions.valueSet = true; + callOptions.gasSet = true; appendExternalFunctionCall( FunctionType( TypePointers{}, @@ -795,11 +799,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) strings(), strings(), FunctionType::Kind::BareCall, - false, StateMutability::NonPayable, nullptr, - true, - true + callOptions ), {}, false @@ -812,6 +814,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context.appendConditionalRevert(true); } break; + } case FunctionType::Kind::Selfdestruct: acceptAndConvert(*arguments.front(), *function.parameterTypes().front(), true); m_context << Instruction::SELFDESTRUCT; From fb8c138b8bb85d603f0ce4aef3170b63129d8887 Mon Sep 17 00:00:00 2001 From: Leo Alt Date: Fri, 24 Dec 2021 00:44:15 +0100 Subject: [PATCH 11/77] Do not analyze unecessary contracts --- libsolidity/formal/CHC.cpp | 9 +++++++++ libsolidity/formal/SMTEncoder.cpp | 6 ++++++ libsolidity/formal/SMTEncoder.h | 2 ++ .../blockchain_state/balance_receive_ext_calls.sol | 2 +- .../this_does_not_change_external_call.sol | 3 +-- .../constructor_state_variable_init_chain_alternate.sol | 3 ++- .../external_calls/external_call_with_value_2.sol | 2 +- .../smtCheckerTests/functions/functions_external_2.sol | 2 +- .../operators/conditional_assignment_6.sol | 2 +- .../smtCheckerTests/special/tx_vars_reentrancy_1.sol | 2 +- .../smtCheckerTests/special/tx_vars_reentrancy_2.sol | 2 +- 11 files changed, 26 insertions(+), 9 deletions(-) diff --git a/libsolidity/formal/CHC.cpp b/libsolidity/formal/CHC.cpp index 0edfc27ff..9e31d7fc9 100644 --- a/libsolidity/formal/CHC.cpp +++ b/libsolidity/formal/CHC.cpp @@ -78,6 +78,9 @@ CHC::CHC( void CHC::analyze(SourceUnit const& _source) { + if (!shouldAnalyze(_source)) + return; + if (!m_settings.solvers.z3 && !m_settings.solvers.smtlib2) { if (!m_noSolverWarning) @@ -137,6 +140,9 @@ vector CHC::unhandledQueries() const bool CHC::visit(ContractDefinition const& _contract) { + if (!shouldAnalyze(_contract)) + return false; + resetContractAnalysis(); initContract(_contract); clearIndices(&_contract); @@ -152,6 +158,9 @@ bool CHC::visit(ContractDefinition const& _contract) void CHC::endVisit(ContractDefinition const& _contract) { + if (!shouldAnalyze(_contract)) + return; + for (auto base: _contract.annotation().linearizedBaseContracts) { if (auto constructor = base->constructor()) diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index 68545f4f6..b42e9b355 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -1035,6 +1035,12 @@ void SMTEncoder::visitPublicGetter(FunctionCall const& _funCall) } } +bool SMTEncoder::shouldAnalyze(SourceUnit const& _source) const +{ + return m_settings.contracts.isDefault() || + m_settings.contracts.has(*_source.annotation().path); +} + bool SMTEncoder::shouldAnalyze(ContractDefinition const& _contract) const { if (!_contract.canBeDeployed()) diff --git a/libsolidity/formal/SMTEncoder.h b/libsolidity/formal/SMTEncoder.h index 7ca19358d..fe84189be 100644 --- a/libsolidity/formal/SMTEncoder.h +++ b/libsolidity/formal/SMTEncoder.h @@ -223,6 +223,8 @@ protected: /// @returns true if @param _contract is set for analysis in the settings /// and it is not abstract. bool shouldAnalyze(ContractDefinition const& _contract) const; + /// @returns true if @param _source is set for analysis in the settings. + bool shouldAnalyze(SourceUnit const& _source) const; bool isPublicGetter(Expression const& _expr); diff --git a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_ext_calls.sol b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_ext_calls.sol index 96223b7e9..313da678e 100644 --- a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_ext_calls.sol +++ b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_ext_calls.sol @@ -16,5 +16,5 @@ contract C { // ---- // Warning 1218: (131-165): CHC: Error trying to invoke SMT solver. // Warning 6328: (131-165): CHC: Assertion violation might happen here. -// Info 1180: Reentrancy property(ies) for :C:\n(!( >= 2) && (((:var 1).balances[address(this)] + ((- 1) * (:var 0).balances[address(this)])) <= 0))\n = 0 -> no errors\n = 1 -> Assertion failed at assert(address(this).balance == x)\n = 2 -> Assertion failed at assert(address(this).balance >= x)\n +// Info 1180: Reentrancy property(ies) for :C:\n(!( >= 2) && (((:var 0).balances[address(this)] + ((- 1) * (:var 1).balances[address(this)])) >= 0))\n = 0 -> no errors\n = 1 -> Assertion failed at assert(address(this).balance == x)\n = 2 -> Assertion failed at assert(address(this).balance >= x)\n // Warning 4661: (131-165): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/blockchain_state/this_does_not_change_external_call.sol b/test/libsolidity/smtCheckerTests/blockchain_state/this_does_not_change_external_call.sol index f16964501..49d2eb33b 100644 --- a/test/libsolidity/smtCheckerTests/blockchain_state/this_does_not_change_external_call.sol +++ b/test/libsolidity/smtCheckerTests/blockchain_state/this_does_not_change_external_call.sol @@ -17,5 +17,4 @@ contract C { // ==== // SMTEngine: all // SMTIgnoreOS: macos -// ---- -// Info 1180: Contract invariant(s) for :C:\n(((address(this) + ((- 1) * t)) <= 0) && ((address(this) + ((- 1) * t)) >= 0))\nReentrancy property(ies) for :C:\n((!((t + ((- 1) * address(this))) = 0) || ( <= 0)) && (!((t + ((- 1) * address(this))) <= 0) || ((t' + ((- 1) * address(this))) <= 0)) && (!((t + ((- 1) * address(this))) >= 0) || ((address(this) + ((- 1) * t')) <= 0)))\n((!( >= 2) || !((t + ((- 1) * address(this))) = 0)) && (!((t + ((- 1) * address(this))) <= 0) || ((t' + ((- 1) * address(this))) <= 0)) && (!((t + ((- 1) * address(this))) >= 0) || ((address(this) + ((- 1) * t')) <= 0)))\n = 0 -> no errors\n = 1 -> Assertion failed at assert(address(this) == t)\n = 2 -> Assertion failed at assert(a == t)\n +// SMTIgnoreInv: yes diff --git a/test/libsolidity/smtCheckerTests/control_flow/branches_with_return/constructor_state_variable_init_chain_alternate.sol b/test/libsolidity/smtCheckerTests/control_flow/branches_with_return/constructor_state_variable_init_chain_alternate.sol index f0b5d48e1..805a75bbb 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/branches_with_return/constructor_state_variable_init_chain_alternate.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/branches_with_return/constructor_state_variable_init_chain_alternate.sol @@ -24,5 +24,6 @@ contract D is C { } // ==== // SMTEngine: all +// SMTIgnoreCex: yes // ---- -// Warning 6328: (286-300): CHC: Assertion violation happens here.\nCounterexample:\nx = 2\na = 1\n\nTransaction trace:\nD.constructor(1) +// Warning 6328: (286-300): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_2.sol b/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_2.sol index 4b51d9d9e..f6c833858 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_2.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_2.sol @@ -14,5 +14,5 @@ contract C { // SMTEngine: all // ---- // Warning 6328: (150-186): CHC: Assertion violation might happen here. -// Warning 6328: (205-240): CHC: Assertion violation happens here. +// Warning 6328: (205-240): CHC: Assertion violation happens here.\nCounterexample:\n\ni = 0\n\nTransaction trace:\nC.constructor()\nC.g(0)\n i.f{value: 0}() -- untrusted external call // Warning 4661: (150-186): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/functions_external_2.sol b/test/libsolidity/smtCheckerTests/functions/functions_external_2.sol index 3a3b295e4..c2f55fa98 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_external_2.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_external_2.sol @@ -25,4 +25,4 @@ contract C // SMTIgnoreOS: macos // ---- // Warning 6328: (234-253): CHC: Assertion violation happens here. -// Info 1180: Reentrancy property(ies) for :C:\n!( = 1)\n((!((map[1] + ((- 1) * map[0])) >= 0) || ((map'[0] + ((- 1) * map'[1])) <= 0)) && !( = 2) && (!((map[1] + ((- 1) * map[0])) <= 0) || ((map'[1] + ((- 1) * map'[0])) <= 0)))\n = 0 -> no errors\n = 1 -> Assertion failed at assert(map[0] == map[1])\n = 2 -> Assertion failed at assert(map[0] == map[1])\n = 3 -> Assertion failed at assert(map[0] == 0)\n +// Info 1180: Reentrancy property(ies) for :C:\n!( = 1)\n((!((map[1] + ((- 1) * map[0])) >= 0) || ((map'[0] + ((- 1) * map'[1])) <= 0)) && (((map'[1] + ((- 1) * map'[0])) <= 0) || !((map[1] + ((- 1) * map[0])) <= 0)) && !( = 2))\n = 0 -> no errors\n = 1 -> Assertion failed at assert(map[0] == map[1])\n = 2 -> Assertion failed at assert(map[0] == map[1])\n = 3 -> Assertion failed at assert(map[0] == 0)\n diff --git a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_6.sol b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_6.sol index 1affbb6ca..923147d49 100644 --- a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_6.sol +++ b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_6.sol @@ -25,4 +25,4 @@ contract C { // SMTIgnoreOS: macos // ---- // Warning 2072: (255-261): Unused local variable. -// Info 1180: Reentrancy property(ies) for :C:\n((!(x' >= 3) || (a' = a)) && (!(x' <= 0) || !(x >= 2)) && ( <= 0) && (!(x <= 2) || !(x' >= 3)))\n = 0 -> no errors\n = 1 -> Assertion failed at assert(x == 2 || x == 1)\n +// Info 1180: Reentrancy property(ies) for :C:\n((!(x <= 2) || !(x' >= 3)) && ( <= 0) && (!(x' <= 0) || !(x >= 2)))\n = 0 -> no errors\n = 1 -> Assertion failed at assert(x == 2 || x == 1)\n diff --git a/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_1.sol b/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_1.sol index 71608eabd..175b68410 100644 --- a/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_1.sol +++ b/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_1.sol @@ -13,4 +13,4 @@ contract C { // SMTEngine: all // SMTIgnoreOS: macos // ---- -// Warning 6328: (135-169): CHC: Assertion violation happens here.\nCounterexample:\n\n_i = 0\nx = 1236\n\nTransaction trace:\nC.constructor()\nC.g(0){ msg.value: 38 }\n _i.f() -- untrusted external call, synthesized as:\n C.g(0){ msg.value: 1 } -- reentrant call\n _i.f() -- untrusted external call +// Warning 6328: (135-169): CHC: Assertion violation happens here.\nCounterexample:\n\n_i = 0\nx = 2997\n\nTransaction trace:\nC.constructor()\nC.g(0){ msg.value: 2803 }\n _i.f() -- untrusted external call, synthesized as:\n C.g(0){ msg.value: 32278 } -- reentrant call\n _i.f() -- untrusted external call diff --git a/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_2.sol b/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_2.sol index 206d95c46..81de958b3 100644 --- a/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_2.sol +++ b/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_2.sol @@ -13,4 +13,4 @@ contract C { // SMTEngine: all // SMTIgnoreOS: macos // ---- -// Warning 6328: (157-191): CHC: Assertion violation happens here.\nCounterexample:\n\n_i = 0\nx = 101\n\nTransaction trace:\nC.constructor()\nC.g(0){ msg.value: 69 }\n _i.f{ value: 100 }() -- untrusted external call +// Warning 6328: (157-191): CHC: Assertion violation happens here.\nCounterexample:\n\n_i = 0\nx = 101\n\nTransaction trace:\nC.constructor()\nC.g(0){ msg.value: 83 }\n _i.f{ value: 100 }() -- untrusted external call From 4c838d9cf5394535b5bb0f179ca0c80b01967338 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 20 Dec 2021 19:30:53 +0100 Subject: [PATCH 12/77] abi.encodeCall for declarations. --- Changelog.md | 4 + libsolidity/analysis/TypeChecker.cpp | 25 +++++- libsolidity/codegen/ExpressionCompiler.cpp | 18 +++- .../codegen/ir/IRGeneratorForStatements.cpp | 19 +++- .../abi_encode_call_declaration.sol | 54 ++++++++++++ .../specialFunctions/encodeCall.sol | 88 ++++++------------- .../specialFunctions/encodeCall_fail_args.sol | 27 ++++++ .../encodeCall_fail_funType.sol | 78 ++++++++++++++++ 8 files changed, 241 insertions(+), 72 deletions(-) create mode 100644 test/libsolidity/semanticTests/abiencodedecode/abi_encode_call_declaration.sol create mode 100644 test/libsolidity/syntaxTests/specialFunctions/encodeCall_fail_args.sol create mode 100644 test/libsolidity/syntaxTests/specialFunctions/encodeCall_fail_funType.sol diff --git a/Changelog.md b/Changelog.md index e4022b2b1..b88e1a971 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,9 @@ ### 0.8.12 (unreleased) +Language Features: + * General: Support ``ContractName.functionName`` for ``abi.encodeCall``, in addition to external function pointers. + + Compiler Features: diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index d6c589f75..d4cffc00e 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -2122,16 +2122,35 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa return; } - if (functionPointerType->kind() != FunctionType::Kind::External) + if ( + functionPointerType->kind() != FunctionType::Kind::External && + functionPointerType->kind() != FunctionType::Kind::Declaration + ) { - string msg = "Function must be \"public\" or \"external\"."; + string msg = "Expected regular external function type, or external view on public function."; + if (functionPointerType->kind() == FunctionType::Kind::Internal) + msg += " Provided internal function."; + else if (functionPointerType->kind() == FunctionType::Kind::DelegateCall) + msg += " Cannot use library functions for abi.encodeCall."; + else if (functionPointerType->kind() == FunctionType::Kind::Creation) + msg += " Provided creation function."; + else + msg += " Cannot use special function."; SecondarySourceLocation ssl{}; if (functionPointerType->hasDeclaration()) { ssl.append("Function is declared here:", functionPointerType->declaration().location()); - if (functionPointerType->declaration().scope() == m_currentContract) + if ( + functionPointerType->declaration().visibility() == Visibility::Public && + functionPointerType->declaration().scope() == m_currentContract + ) msg += " Did you forget to prefix \"this.\"?"; + else if (contains( + m_currentContract->annotation().linearizedBaseContracts, + functionPointerType->declaration().scope() + ) && functionPointerType->declaration().scope() != m_currentContract) + msg += " Functions from base contracts have to be external."; } m_errorReporter.typeError(3509_error, arguments[0]->location(), ssl, msg); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 5a633d2e6..78b6f02b6 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1255,7 +1255,6 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) auto const functionPtr = dynamic_cast(arguments[0]->annotation().type); solAssert(functionPtr); - solAssert(functionPtr->sizeOnStack() == 2); // Account for tuples with one component which become that component if (auto const tupleType = dynamic_cast(arguments[1]->annotation().type)) @@ -1330,9 +1329,20 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) } else if (function.kind() == FunctionType::Kind::ABIEncodeCall) { - // stack: - // Extract selector from the stack - m_context << Instruction::SWAP1 << Instruction::POP; + auto const& funType = dynamic_cast(*selectorType); + if (funType.kind() == FunctionType::Kind::Declaration) + { + solAssert(funType.hasDeclaration()); + solAssert(selectorType->sizeOnStack() == 0); + m_context << funType.externalIdentifier(); + } + else + { + solAssert(selectorType->sizeOnStack() == 2); + // stack: + // Extract selector from the stack + m_context << Instruction::SWAP1 << Instruction::POP; + } // Conversion will be done below dataOnStack = TypeProvider::uint(32); } diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 179b3e739..d35685037 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1150,10 +1150,21 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) } if (functionType->kind() == FunctionType::Kind::ABIEncodeCall) - selector = convert( - IRVariable(*arguments[0]).part("functionSelector"), - *TypeProvider::fixedBytes(4) - ).name(); + { + auto const& selectorType = dynamic_cast(type(*arguments.front())); + if (selectorType.kind() == FunctionType::Kind::Declaration) + { + solAssert(selectorType.hasDeclaration()); + selector = formatNumber(selectorType.externalIdentifier() << (256 - 32)); + } + else + { + selector = convert( + IRVariable(*arguments[0]).part("functionSelector"), + *TypeProvider::fixedBytes(4) + ).name(); + } + } else if (functionType->kind() == FunctionType::Kind::ABIEncodeWithSignature) { // hash the signature diff --git a/test/libsolidity/semanticTests/abiencodedecode/abi_encode_call_declaration.sol b/test/libsolidity/semanticTests/abiencodedecode/abi_encode_call_declaration.sol new file mode 100644 index 000000000..a70c6b903 --- /dev/null +++ b/test/libsolidity/semanticTests/abiencodedecode/abi_encode_call_declaration.sol @@ -0,0 +1,54 @@ +pragma abicoder v2; + +contract X { + // no "returns" on purpose + function a(uint) public pure {} + function b(uint) external pure {} +} + +contract Base { + function a(uint x) external pure returns (uint) { return x + 1; } +} + +contract C is Base { + function test() public view returns (uint r) { + bool success; + bytes memory result; + (success, result) = address(this).staticcall(abi.encodeCall(X.a, 1)); + require(success && result.length == 32); + r += abi.decode(result, (uint)); + require(r == 2); + + (success, result) = address(this).staticcall(abi.encodeCall(X.b, 10)); + require(success && result.length == 32); + r += abi.decode(result, (uint)); + require(r == 13); + + (success, result) = address(this).staticcall(abi.encodeCall(Base.a, 100)); + require(success && result.length == 32); + r += abi.decode(result, (uint)); + require(r == 114); + + (success, result) = address(this).staticcall(abi.encodeCall(this.a, 1000)); + require(success && result.length == 32); + r += abi.decode(result, (uint)); + require(r == 1115); + + (success, result) = address(this).staticcall(abi.encodeCall(C.b, 10000)); + require(success && result.length == 32); + r += abi.decode(result, (uint)); + require(r == 11116); + + return r; + } + function b(uint x) external view returns (uint) { + return this.a(x); + } + +} + +// ==== +// compileViaYul: also +// EVMVersion: >=byzantium +// ---- +// test() -> 11116 diff --git a/test/libsolidity/syntaxTests/specialFunctions/encodeCall.sol b/test/libsolidity/syntaxTests/specialFunctions/encodeCall.sol index 41b8f16cc..6cf39cfae 100644 --- a/test/libsolidity/syntaxTests/specialFunctions/encodeCall.sol +++ b/test/libsolidity/syntaxTests/specialFunctions/encodeCall.sol @@ -2,81 +2,47 @@ interface I { function fExternal(uint256 p, string memory t) external; } -library L { - function fExternal(uint256 p, string memory t) external {} +contract Other { + function fExternal(uint) external pure {} + function fPublic(uint) public pure {} + function fInternal(uint) internal pure {} } -contract C { - using L for uint256; +library L { + function fExternal(uint256 p, string memory t) external {} + function fInternal(uint256 p, string memory t) internal {} +} +contract Base { + function baseFunctionExternal(uint) external pure {} +} + +contract C is Base { function f(int a) public {} function f2(int a, string memory b) public {} - function f3(int a, int b) public {} function f4() public {} - function fInternal(uint256 p, string memory t) internal {} - function failFunctionArgsWrongType() public returns(bytes memory) { - return abi.encodeCall(this.f, ("test")); - } - function failFunctionArgsTooMany() public returns(bytes memory) { - return abi.encodeCall(this.f, (1, 2)); - } - function failFunctionArgsTooFew0() public returns(bytes memory) { - return abi.encodeCall(this.f, ()); - } - function failFunctionArgsTooFew1() public returns(bytes memory) { - return abi.encodeCall(this.f); - } - function failFunctionPtrMissing() public returns(bytes memory) { - return abi.encodeCall(1, this.f); - } - function failFunctionPtrWrongType() public returns(bytes memory) { - return abi.encodeCall(abi.encodeCall, (1, 2, 3, "test")); - } - function failFunctionInternal() public returns(bytes memory) { - return abi.encodeCall(fInternal, (1, "123")); - } - function failFunctionInternalFromVariable() public returns(bytes memory) { - function(uint256, string memory) internal localFunctionPointer = fInternal; - return abi.encodeCall(localFunctionPointer, (1, "123")); - } - function failFunctionArgsArrayLiteral() public returns(bytes memory) { - return abi.encodeCall(this.f3, [1, 2]); - } - function failLibraryPointerCall() public returns (bytes memory) { - return abi.encodeCall(L.fExternal, (1, "123")); - } - function failBoundLibraryPointerCall() public returns (bytes memory) { - uint256 x = 1; - return abi.encodeCall(x.fExternal, (1, "123")); - } - function failInterfacePointerCall() public returns (bytes memory) { - return abi.encodeCall(I.fExternal, (1, "123")); - } - function successFunctionArgsIntLiteralTuple() public returns(bytes memory) { + function successFunctionArgsIntLiteralTuple() public view returns(bytes memory) { return abi.encodeCall(this.f, (1)); } - function successFunctionArgsIntLiteral() public returns(bytes memory) { + function successFunctionArgsIntLiteral() public view returns(bytes memory) { return abi.encodeCall(this.f, 1); } - function successFunctionArgsLiteralTuple() public returns(bytes memory) { + function successFunctionArgsLiteralTuple() public view returns(bytes memory) { return abi.encodeCall(this.f2, (1, "test")); } - function successFunctionArgsEmptyTuple() public returns(bytes memory) { + function successFunctionArgsEmptyTuple() public view returns(bytes memory) { return abi.encodeCall(this.f4, ()); } + function viaDeclaration() public pure returns (bytes memory) { + return bytes.concat( + abi.encodeCall(Other.fExternal, (1)), + abi.encodeCall(Other.fPublic, (1)), + abi.encodeCall(I.fExternal, (1, "123")) + ); + } + function viaBaseDeclaration() public pure returns (bytes memory) { + return abi.encodeCall(Base.baseFunctionExternal, (1)); + } } // ---- -// TypeError 5407: (486-494): Cannot implicitly convert component at position 0 from "literal_string "test"" to "int256". -// TypeError 7788: (576-606): Expected 1 instead of 2 components for the tuple parameter. -// TypeError 7788: (687-713): Expected 1 instead of 0 components for the tuple parameter. -// TypeError 6219: (794-816): Expected two arguments: a function pointer followed by a tuple. -// TypeError 5511: (911-912): Expected first argument to be a function pointer, not "int_const 1". -// TypeError 3509: (1018-1032): Function must be "public" or "external". -// TypeError 3509: (1145-1154): Function must be "public" or "external". Did you forget to prefix "this."? -// TypeError 3509: (1350-1370): Function must be "public" or "external". -// TypeError 7515: (1469-1500): Expected a tuple with 2 components instead of a single non-tuple parameter. -// TypeError 5407: (1493-1499): Cannot implicitly convert component at position 0 from "uint8[2]" to "int256". -// TypeError 3509: (1596-1607): Function must be "public" or "external". -// TypeError 3509: (1738-1749): Function must be "public" or "external". -// TypeError 3509: (1860-1871): Function must be "public" or "external". diff --git a/test/libsolidity/syntaxTests/specialFunctions/encodeCall_fail_args.sol b/test/libsolidity/syntaxTests/specialFunctions/encodeCall_fail_args.sol new file mode 100644 index 000000000..a1c20f9bd --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/encodeCall_fail_args.sol @@ -0,0 +1,27 @@ +contract C { + function f(int a) public {} + function f3(int a, int b) public {} + + function failFunctionArgsWrongType() public returns(bytes memory) { + return abi.encodeCall(this.f, ("test")); + } + function failFunctionArgsTooMany() public returns(bytes memory) { + return abi.encodeCall(this.f, (1, 2)); + } + function failFunctionArgsTooFew0() public returns(bytes memory) { + return abi.encodeCall(this.f, ()); + } + function failFunctionArgsTooFew1() public returns(bytes memory) { + return abi.encodeCall(this.f); + } + function failFunctionArgsArrayLiteral() public returns(bytes memory) { + return abi.encodeCall(this.f3, [1, 2]); + } +} +// ---- +// TypeError 5407: (181-189): Cannot implicitly convert component at position 0 from "literal_string "test"" to "int256". +// TypeError 7788: (271-301): Expected 1 instead of 2 components for the tuple parameter. +// TypeError 7788: (382-408): Expected 1 instead of 0 components for the tuple parameter. +// TypeError 6219: (489-511): Expected two arguments: a function pointer followed by a tuple. +// TypeError 7515: (597-628): Expected a tuple with 2 components instead of a single non-tuple parameter. +// TypeError 5407: (621-627): Cannot implicitly convert component at position 0 from "uint8[2]" to "int256". diff --git a/test/libsolidity/syntaxTests/specialFunctions/encodeCall_fail_funType.sol b/test/libsolidity/syntaxTests/specialFunctions/encodeCall_fail_funType.sol new file mode 100644 index 000000000..e2de48387 --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/encodeCall_fail_funType.sol @@ -0,0 +1,78 @@ +interface I { + function fExternal(uint256 p, string memory t) external; +} + +contract Other { + function fExternal(uint) external pure {} + function fPublic(uint) public pure {} + function fInternal(uint) internal pure {} +} + +library L { + function fExternal(uint256 p, string memory t) external {} + function fInternal(uint256 p, string memory t) internal {} +} + +contract Base { + function baseFunctionInternal(uint) internal pure {} + function baseFunctionPublic(uint) public pure {} +} + +function fileLevel(uint) pure {} + +contract C is Base { + using L for uint256; + + function fPublic(int a) public {} + function fInternal(uint256 p, string memory t) internal {} + + function failFunctionPtrMissing() public returns(bytes memory) { + return abi.encodeCall(1, this.fPublic); + } + function failFunctionPtrWrongType() public returns(bytes memory) { + return abi.encodeCall(abi.encodeCall, (1, 2, 3, "test")); + } + function failFunctionInternal() public returns(bytes memory) { + return abi.encodeCall(fInternal, (1, "123")); + } + function failFunctionInternalFromVariable() public returns(bytes memory) { + function(uint256, string memory) internal localFunctionPointer = fInternal; + return abi.encodeCall(localFunctionPointer, (1, "123")); + } + function failLibraryPointerCall() public { + abi.encodeCall(L.fInternal, (1, "123")); + abi.encodeCall(L.fExternal, (1, "123")); + } + function failBoundLibraryPointerCall() public returns (bytes memory) { + uint256 x = 1; + return abi.encodeCall(x.fExternal, (1, "123")); + } + function viaBaseDeclaration() public pure returns (bytes memory) { + return abi.encodeCall(C.fPublic, (2)); + } + function viaBaseDeclaration2() public pure returns (bytes memory) { + return bytes.concat( + abi.encodeCall(Base.baseFunctionPublic, (1)), + abi.encodeCall(Base.baseFunctionInternal, (1)) + ); + } + function fileLevelFunction() public pure returns (bytes memory) { + return abi.encodeCall(fileLevel, (2)); + } + function createFunction() public pure returns (bytes memory) { + return abi.encodeCall(new Other, (2)); + } +} +// ---- +// TypeError 5511: (742-743): Expected first argument to be a function pointer, not "int_const 1". +// TypeError 3509: (855-869): Expected regular external function type, or external view on public function. Cannot use special function. +// TypeError 3509: (982-991): Expected regular external function type, or external view on public function. Provided internal function. +// TypeError 3509: (1187-1207): Expected regular external function type, or external view on public function. Provided internal function. +// TypeError 3509: (1286-1297): Expected regular external function type, or external view on public function. Provided internal function. +// TypeError 3509: (1329-1340): Expected regular external function type, or external view on public function. Cannot use library functions for abi.encodeCall. +// TypeError 3509: (1471-1482): Expected regular external function type, or external view on public function. Cannot use library functions for abi.encodeCall. +// TypeError 3509: (1592-1601): Expected regular external function type, or external view on public function. Provided internal function. Did you forget to prefix "this."? +// TypeError 3509: (1722-1745): Expected regular external function type, or external view on public function. Provided internal function. Functions from base contracts have to be external. +// TypeError 3509: (1771-1796): Expected regular external function type, or external view on public function. Provided internal function. Functions from base contracts have to be external. +// TypeError 3509: (1902-1911): Expected regular external function type, or external view on public function. Provided internal function. +// TypeError 3509: (2010-2019): Expected regular external function type, or external view on public function. Provided creation function. From b95db2db5eff4bb40779c048411b0752ab0ad298 Mon Sep 17 00:00:00 2001 From: Marenz Date: Tue, 28 Dec 2021 18:29:20 +0100 Subject: [PATCH 13/77] Remove unnecessary checks in modifier resolve function --- libsolidity/ast/AST.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index c36aee5b3..f2b7369b7 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -511,23 +511,20 @@ ModifierDefinition const& ModifierDefinition::resolveVirtual( ContractDefinition const* _searchStart ) const { + // Super is not possible with modifiers solAssert(_searchStart == nullptr, "Used super in connection with modifiers."); - // If we are not doing super-lookup and the modifier is not virtual, we can stop here. - if (_searchStart == nullptr && !virtualSemantics()) + // The modifier is not virtual, we can stop here. + if (!virtualSemantics()) return *this; solAssert(!dynamic_cast(*scope()).isLibrary(), ""); for (ContractDefinition const* c: _mostDerivedContract.annotation().linearizedBaseContracts) - { - if (_searchStart != nullptr && c != _searchStart) - continue; - _searchStart = nullptr; for (ModifierDefinition const* modifier: c->functionModifiers()) if (modifier->name() == name()) return *modifier; - } + solAssert(false, "Virtual modifier " + name() + " not found."); return *this; // not reached } From 4456eeb6bbad5b2ae826a577318458eebb62d962 Mon Sep 17 00:00:00 2001 From: Franziska Heintel <41991517+franzihei@users.noreply.github.com> Date: Wed, 29 Dec 2021 16:06:05 +0100 Subject: [PATCH 14/77] [DOCS] update contributing section meeting link --- docs/contributing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index 4844eaae3..2895744ef 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -33,7 +33,7 @@ the team and contributors are working on, you can join our public team calls: - Mondays at 3pm CET/CEST. - Wednesdays at 2pm CET/CEST. -Both calls take place on `Jitsi `_. +Both calls take place on `Jitsi `_. How to Report Issues ==================== From bd819c87fa12ee8a3a5aa164bd2f44fed731416b Mon Sep 17 00:00:00 2001 From: nishant-sachdeva Date: Fri, 24 Dec 2021 23:23:51 +0530 Subject: [PATCH 15/77] added warning if isoltest gas-cost-expectations are not enforced --- test/boostTest.cpp | 3 +++ test/tools/isoltest.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/test/boostTest.cpp b/test/boostTest.cpp index 6fcd684f4..c9d70dc1c 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -191,6 +191,9 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] ) if (solidity::test::CommonOptions::get().disableSemanticTests) cout << endl << "--- SKIPPING ALL SEMANTICS TESTS ---" << endl << endl; + if (!solidity::test::CommonOptions::get().enforceGasTest) + cout << endl << "WARNING :: Gas Cost Expectations are not being enforced" << endl << endl; + // Include the interactive tests in the automatic tests as well for (auto const& ts: g_interactiveTestsuites) { diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp index 5ae1a3f99..149eaaffa 100644 --- a/test/tools/isoltest.cpp +++ b/test/tools/isoltest.cpp @@ -437,6 +437,9 @@ int main(int argc, char const *argv[]) if (options.disableSemanticTests) cout << endl << "--- SKIPPING ALL SEMANTICS TESTS ---" << endl << endl; + if (!options.enforceGasTest) + cout << "WARNING :: Gas Cost Expectations are not being enforced" << endl << endl; + TestStats global_stats{0, 0}; cout << "Running tests..." << endl << endl; From 2a7f26e2c09d630d484774145cd9c62702b1c9d8 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 20 Dec 2021 19:03:48 +0100 Subject: [PATCH 16/77] Test batcher. --- .circleci/config.yml | 8 ++- .circleci/soltest.sh | 41 ++++++++++++--- .circleci/soltest_all.sh | 46 +++++++---------- test/Common.cpp | 13 +++++ test/Common.h | 26 ++++++++++ test/boostTest.cpp | 107 ++++++++++++++++++++++++++++++--------- test/tools/isoltest.cpp | 32 +++++++++--- 7 files changed, 204 insertions(+), 69 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 164802b37..6edfc2d3a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -897,7 +897,7 @@ jobs: t_ubu_soltest_all: &t_ubu_soltest_all <<: *base_ubuntu2004 - parallelism: 15 # 7 EVM versions, each with/without optimization + 1 ABIv1/@nooptions run + parallelism: 50 <<: *steps_soltest_all t_ubu_lsp: &t_ubu_lsp @@ -906,6 +906,7 @@ jobs: t_archlinux_soltest: &t_archlinux_soltest <<: *base_archlinux + parallelism: 20 environment: EVM: << pipeline.parameters.evm-version >> OPTIMIZE: 0 @@ -924,6 +925,7 @@ jobs: t_ubu_soltest_enforce_yul: &t_ubu_soltest_enforce_yul <<: *base_ubuntu2004 + parallelism: 20 environment: EVM: << pipeline.parameters.evm-version >> SOLTEST_FLAGS: --enforce-via-yul @@ -933,6 +935,7 @@ jobs: t_ubu_clang_soltest: &t_ubu_clang_soltest <<: *base_ubuntu2004_clang + parallelism: 20 environment: EVM: << pipeline.parameters.evm-version >> OPTIMIZE: 0 @@ -960,6 +963,7 @@ jobs: t_ubu_asan_soltest: <<: *base_ubuntu2004 + parallelism: 20 environment: EVM: << pipeline.parameters.evm-version >> OPTIMIZE: 0 @@ -969,6 +973,7 @@ jobs: t_ubu_asan_clang_soltest: <<: *base_ubuntu2004_clang + parallelism: 20 environment: EVM: << pipeline.parameters.evm-version >> OPTIMIZE: 0 @@ -978,6 +983,7 @@ jobs: t_ubu_ubsan_clang_soltest: <<: *base_ubuntu2004_clang + parallelism: 20 environment: EVM: << pipeline.parameters.evm-version >> <<: *steps_soltest diff --git a/.circleci/soltest.sh b/.circleci/soltest.sh index 1814b8728..30bd1274c 100755 --- a/.circleci/soltest.sh +++ b/.circleci/soltest.sh @@ -50,19 +50,48 @@ mkdir -p test_results ulimit -s 16384 get_logfile_basename() { + local run="$1" local filename="${EVM}" test "${OPTIMIZE}" = "1" && filename="${filename}_opt" test "${ABI_ENCODER_V1}" = "1" && filename="${filename}_abiv1" + filename="${filename}_${run}" echo -ne "${filename}" } -BOOST_TEST_ARGS=("--color_output=no" "--show_progress=yes" "--logger=JUNIT,error,test_results/$(get_logfile_basename).xml" "${BOOST_TEST_ARGS[@]}") -SOLTEST_ARGS=("--evm-version=$EVM" "${SOLTEST_FLAGS[@]}") +[ -z "$CIRCLE_NODE_TOTAL" ] || [ "$CIRCLE_NODE_TOTAL" = 0 ] && CIRCLE_NODE_TOTAL=1 +[ -z "$CIRCLE_NODE_INDEX" ] && CIRCLE_NODE_INDEX=0 +[ -z "$INDEX_SHIFT" ] && INDEX_SHIFT=0 -test "${OPTIMIZE}" = "1" && SOLTEST_ARGS+=(--optimize) -test "${ABI_ENCODER_V1}" = "1" && SOLTEST_ARGS+=(--abiencoderv1) +# Multiply by a prime number to get better spread, just in case +# long-running test cases are next to each other. +CIRCLE_NODE_INDEX=$(((CIRCLE_NODE_INDEX + 23 * INDEX_SHIFT) % CIRCLE_NODE_TOTAL)) -echo "Running ${REPODIR}/build/test/soltest ${BOOST_TEST_ARGS[*]} -- ${SOLTEST_ARGS[*]}" +CPUs=3 +PIDs=() +for run in $(seq 0 $((CPUs - 1))) +do + BOOST_TEST_ARGS_RUN=( + "--color_output=no" + "--show_progress=yes" + "--logger=JUNIT,error,test_results/$(get_logfile_basename "$run").xml" + "${BOOST_TEST_ARGS[@]}" + ) + SOLTEST_ARGS=("--evm-version=$EVM" "${SOLTEST_FLAGS[@]}") -"${REPODIR}/build/test/soltest" "${BOOST_TEST_ARGS[@]}" -- "${SOLTEST_ARGS[@]}" + test "${OPTIMIZE}" = "1" && SOLTEST_ARGS+=(--optimize) + test "${ABI_ENCODER_V1}" = "1" && SOLTEST_ARGS+=(--abiencoderv1) + + BATCH_ARGS=("--batches" "$((CPUs * CIRCLE_NODE_TOTAL))" "--selected-batch" "$((CPUs * CIRCLE_NODE_INDEX + run))") + + echo "Running ${REPODIR}/build/test/soltest ${BOOST_TEST_ARGS_RUN[*]} -- ${SOLTEST_ARGS[*]}" + + "${REPODIR}/build/test/soltest" -l test_suite "${BOOST_TEST_ARGS_RUN[@]}" -- "${SOLTEST_ARGS[@]}" "${BATCH_ARGS[@]}" & + PIDs+=($!) +done + +# wait for individual processes to get their exit status +for pid in ${PIDs[*]} +do + wait "$pid" +done diff --git a/.circleci/soltest_all.sh b/.circleci/soltest_all.sh index 5bd5ed9f1..3e29d1d2e 100755 --- a/.circleci/soltest_all.sh +++ b/.circleci/soltest_all.sh @@ -31,30 +31,21 @@ REPODIR="$(realpath "$(dirname "$0")"/..)" # shellcheck source=scripts/common.sh source "${REPODIR}/scripts/common.sh" -# NOTE: If you add/remove values, remember to update `parallelism` setting in CircleCI config. EVM_VALUES=(homestead byzantium constantinople petersburg istanbul berlin london) DEFAULT_EVM=london [[ " ${EVM_VALUES[*]} " =~ $DEFAULT_EVM ]] OPTIMIZE_VALUES=(0 1) -STEPS=$(( 1 + ${#EVM_VALUES[@]} * ${#OPTIMIZE_VALUES[@]} )) - -RUN_STEPS=$(circleci_select_steps "$(seq "$STEPS")") -printTask "Running steps $RUN_STEPS..." - -STEP=1 - # Run for ABI encoder v1, without SMTChecker tests. -if circleci_step_selected "$RUN_STEPS" "$STEP" -then - EVM="${DEFAULT_EVM}" \ - OPTIMIZE=1 \ - ABI_ENCODER_V1=1 \ - BOOST_TEST_ARGS="-t !smtCheckerTests" \ - "${REPODIR}/.circleci/soltest.sh" -fi -((++STEP)) +EVM="${DEFAULT_EVM}" \ +OPTIMIZE=1 \ +ABI_ENCODER_V1=1 \ +BOOST_TEST_ARGS="-t !smtCheckerTests" \ +"${REPODIR}/.circleci/soltest.sh" +# We shift the batch index so that long-running tests +# do not always run in the same executor for all EVM versions +INDEX_SHIFT=0 for OPTIMIZE in "${OPTIMIZE_VALUES[@]}" do for EVM in "${EVM_VALUES[@]}" @@ -68,16 +59,13 @@ do DISABLE_SMTCHECKER="" [ "${OPTIMIZE}" != "0" ] && DISABLE_SMTCHECKER="-t !smtCheckerTests" - if circleci_step_selected "$RUN_STEPS" "$STEP" - then - EVM="$EVM" \ - OPTIMIZE="$OPTIMIZE" \ - SOLTEST_FLAGS="$SOLTEST_FLAGS $ENFORCE_GAS_ARGS $EWASM_ARGS" \ - BOOST_TEST_ARGS="-t !@nooptions $DISABLE_SMTCHECKER" \ - "${REPODIR}/.circleci/soltest.sh" - fi - ((++STEP)) - done -done + EVM="$EVM" \ + OPTIMIZE="$OPTIMIZE" \ + SOLTEST_FLAGS="$SOLTEST_FLAGS $ENFORCE_GAS_ARGS $EWASM_ARGS" \ + BOOST_TEST_ARGS="-t !@nooptions $DISABLE_SMTCHECKER" \ + INDEX_SHIFT="$INDEX_SHIFT" \ + "${REPODIR}/.circleci/soltest.sh" -((STEP == STEPS + 1)) || assertFail "Step counter not properly adjusted!" + INDEX_SHIFT=$((INDEX_SHIFT + 1)) + done +done \ No newline at end of file diff --git a/test/Common.cpp b/test/Common.cpp index 2a663aa1b..a702cddd6 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -102,6 +102,8 @@ void CommonOptions::addOptions() ("testpath", po::value(&this->testPath)->default_value(solidity::test::testPath()), "path to test files") ("vm", po::value>(&vmPaths), "path to evmc library, can be supplied multiple times.") ("ewasm", po::bool_switch(&ewasm)->default_value(ewasm), "tries to automatically find an ewasm vm and enable ewasm test-execution.") + ("batches", po::value(&this->batches)->default_value(1), "set number of batches to split the tests into") + ("selected-batch", po::value(&this->selectedBatch)->default_value(0), "zero-based number of batch to execute") ("no-semantic-tests", po::bool_switch(&disableSemanticTests)->default_value(disableSemanticTests), "disable semantic tests") ("no-smt", po::bool_switch(&disableSMT)->default_value(disableSMT), "disable SMT checker") ("optimize", po::bool_switch(&optimize)->default_value(optimize), "enables optimization") @@ -126,6 +128,17 @@ void CommonOptions::validate() const ConfigException, "Invalid test path specified." ); + assertThrow( + batches > 0, + ConfigException, + "Batches needs to be at least 1." + ); + assertThrow( + selectedBatch < batches, + ConfigException, + "Selected batch has to be less than number of batches." + ); + if (enforceGasTest) { assertThrow( diff --git a/test/Common.h b/test/Common.h index f7c8fa733..f3ea9e6f4 100644 --- a/test/Common.h +++ b/test/Common.h @@ -20,6 +20,7 @@ #include #include +#include #include @@ -67,6 +68,8 @@ struct CommonOptions bool useABIEncoderV1 = false; bool showMessages = false; bool showMetadata = false; + size_t batches = 1; + size_t selectedBatch = 0; langutil::EVMVersion evmVersion() const; @@ -96,4 +99,27 @@ bool isValidSemanticTestPath(boost::filesystem::path const& _testPath); bool loadVMs(CommonOptions const& _options); +/** + * Component to help with splitting up all tests into batches. + */ +class Batcher +{ +public: + Batcher(size_t _offset, size_t _batches): + m_offset(_offset), + m_batches(_batches) + { + solAssert(m_batches > 0 && m_offset < m_batches); + } + Batcher(Batcher const&) = delete; + Batcher& operator=(Batcher const&) = delete; + + bool checkAndAdvance() { return (m_counter++) % m_batches == m_offset; } + +private: + size_t const m_offset; + size_t const m_batches; + size_t m_counter = 0; +}; + } diff --git a/test/boostTest.cpp b/test/boostTest.cpp index c9d70dc1c..bfb546736 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -30,6 +30,7 @@ #pragma warning(disable:4535) // calling _set_se_translator requires /EHa #endif #include +#include #if defined(_MSC_VER) #pragma warning(pop) #endif @@ -60,6 +61,41 @@ void removeTestSuite(std::string const& _name) master.remove(id); } +/** + * Class that traverses the boost test tree and removes unit tests that are + * not in the current batch. + */ +class BoostBatcher: public test_tree_visitor +{ +public: + BoostBatcher(solidity::test::Batcher& _batcher): + m_batcher(_batcher) + {} + + void visit(test_case const& _testCase) override + { + if (!m_batcher.checkAndAdvance()) + // disabling them would be nicer, but it does not work like this: + // const_cast(_testCase).p_run_status.value = test_unit::RS_DISABLED; + m_path.back()->remove(_testCase.p_id); + } + bool test_suite_start(test_suite const& _testSuite) override + { + m_path.push_back(&const_cast(_testSuite)); + return test_tree_visitor::test_suite_start(_testSuite); + } + void test_suite_finish(test_suite const& _testSuite) override + { + m_path.pop_back(); + test_tree_visitor::test_suite_finish(_testSuite); + } + +private: + solidity::test::Batcher& m_batcher; + std::vector m_path; +}; + + void runTestCase(TestCase::Config const& _config, TestCase::TestCaseCreator const& _testCaseCreator) { try @@ -100,7 +136,8 @@ int registerTests( bool _enforceViaYul, bool _enforceCompileToEwasm, vector const& _labels, - TestCase::TestCaseCreator _testCaseCreator + TestCase::TestCaseCreator _testCaseCreator, + solidity::test::Batcher& _batcher ) { int numTestsAdded = 0; @@ -131,33 +168,38 @@ int registerTests( _enforceViaYul, _enforceCompileToEwasm, _labels, - _testCaseCreator + _testCaseCreator, + _batcher ); _suite.add(sub_suite); } else { - // This must be a vector of unique_ptrs because Boost.Test keeps the equivalent of a string_view to the filename - // that is passed in. If the strings were stored directly in the vector, pointers/references to them would be - // invalidated on reallocation. - static vector> filenames; + // TODO would be better to set the test to disabled. + if (_batcher.checkAndAdvance()) + { + // This must be a vector of unique_ptrs because Boost.Test keeps the equivalent of a string_view to the filename + // that is passed in. If the strings were stored directly in the vector, pointers/references to them would be + // invalidated on reallocation. + static vector> filenames; - filenames.emplace_back(make_unique(_path.string())); - auto test_case = make_test_case( - [config, _testCaseCreator] - { - BOOST_REQUIRE_NO_THROW({ - runTestCase(config, _testCaseCreator); - }); - }, - _path.stem().string(), - *filenames.back(), - 0 - ); - for (auto const& _label: _labels) - test_case->add_label(_label); - _suite.add(test_case); - numTestsAdded = 1; + filenames.emplace_back(make_unique(_path.string())); + auto test_case = make_test_case( + [config, _testCaseCreator] + { + BOOST_REQUIRE_NO_THROW({ + runTestCase(config, _testCaseCreator); + }); + }, + _path.stem().string(), + *filenames.back(), + 0 + ); + for (auto const& _label: _labels) + test_case->add_label(_label); + _suite.add(test_case); + numTestsAdded = 1; + } } return numTestsAdded; } @@ -172,6 +214,7 @@ void initializeOptions() solidity::test::CommonOptions::setSingleton(std::move(options)); } + } // TODO: Prototype -- why isn't this declared in the boost headers? @@ -180,6 +223,8 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] ); test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] ) { + using namespace solidity::test; + master_test_suite_t& master = framework::master_test_suite(); master.p_name.value = "SolidityTests"; @@ -194,6 +239,14 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] ) if (!solidity::test::CommonOptions::get().enforceGasTest) cout << endl << "WARNING :: Gas Cost Expectations are not being enforced" << endl << endl; + Batcher batcher(CommonOptions::get().selectedBatch, CommonOptions::get().batches); + if (CommonOptions::get().batches > 1) + cout << "Batch " << CommonOptions::get().selectedBatch << " out of " << CommonOptions::get().batches << endl; + + // Batch the boost tests + BoostBatcher boostBatcher(batcher); + traverse_test_tree(master, boostBatcher, true); + // Include the interactive tests in the automatic tests as well for (auto const& ts: g_interactiveTestsuites) { @@ -205,15 +258,19 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] ) if (ts.needsVM && solidity::test::CommonOptions::get().disableSemanticTests) continue; - solAssert(registerTests( + //TODO + //solAssert( + registerTests( master, options.testPath / ts.path, ts.subpath, options.enforceViaYul, options.enforceCompileToEwasm, ts.labels, - ts.testCaseCreator - ) > 0, std::string("no ") + ts.title + " tests found"); + ts.testCaseCreator, + batcher + ); + // > 0, std::string("no ") + ts.title + " tests found"); } if (solidity::test::CommonOptions::get().disableSemanticTests) diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp index 149eaaffa..ae2ce6e24 100644 --- a/test/tools/isoltest.cpp +++ b/test/tools/isoltest.cpp @@ -119,7 +119,8 @@ public: TestCreator _testCaseCreator, TestOptions const& _options, fs::path const& _basepath, - fs::path const& _path + fs::path const& _path, + solidity::test::Batcher& _batcher ); private: enum class Request @@ -269,7 +270,8 @@ TestStats TestTool::processPath( TestCreator _testCaseCreator, TestOptions const& _options, fs::path const& _basepath, - fs::path const& _path + fs::path const& _path, + solidity::test::Batcher& _batcher ) { std::queue paths; @@ -298,6 +300,11 @@ TestStats TestTool::processPath( ++testCount; paths.pop(); } + else if (!_batcher.checkAndAdvance()) + { + paths.pop(); + ++skippedCount; + } else { ++testCount; @@ -373,7 +380,8 @@ std::optional runTestSuite( TestOptions const& _options, fs::path const& _basePath, fs::path const& _subdirectory, - string const& _name + string const& _name, + solidity::test::Batcher& _batcher ) { fs::path testPath{_basePath / _subdirectory}; @@ -389,7 +397,8 @@ std::optional runTestSuite( _testCaseCreator, _options, _basePath, - _subdirectory + _subdirectory, + _batcher ); if (stats.skippedCount != stats.testCount) @@ -415,21 +424,23 @@ std::optional runTestSuite( int main(int argc, char const *argv[]) { + using namespace solidity::test; + try { setupTerminal(); { - auto options = std::make_unique(); + auto options = std::make_unique(); if (!options->parse(argc, argv)) return -1; options->validate(); - solidity::test::CommonOptions::setSingleton(std::move(options)); + CommonOptions::setSingleton(std::move(options)); } - auto& options = dynamic_cast(solidity::test::CommonOptions::get()); + auto& options = dynamic_cast(CommonOptions::get()); if (!solidity::test::loadVMs(options)) return 1; @@ -443,6 +454,10 @@ int main(int argc, char const *argv[]) TestStats global_stats{0, 0}; cout << "Running tests..." << endl << endl; + Batcher batcher(CommonOptions::get().selectedBatch, CommonOptions::get().batches); + if (CommonOptions::get().batches > 1) + cout << "Batch " << CommonOptions::get().selectedBatch << " out of " << CommonOptions::get().batches << endl; + // Actually run the tests. // Interactive tests are added in InteractiveTests.h for (auto const& ts: g_interactiveTestsuites) @@ -458,7 +473,8 @@ int main(int argc, char const *argv[]) options, options.testPath / ts.path, ts.subpath, - ts.title + ts.title, + batcher ); if (stats) global_stats += *stats; From 0010027e17b133266e86963ee003aa42c8883c84 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 30 Dec 2021 12:31:20 +0100 Subject: [PATCH 17/77] Fix mapping example. --- docs/types/mapping-types.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/types/mapping-types.rst b/docs/types/mapping-types.rst index c026d73f2..18f3bf827 100644 --- a/docs/types/mapping-types.rst +++ b/docs/types/mapping-types.rst @@ -84,23 +84,24 @@ The example below uses ``_allowances`` to record the amount someone else is allo } function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { + require(_allowances[sender][msg.sender] >= amount, "ERC20: Allowance not high enough."); + _allowances[sender][msg.sender] -= amount; _transfer(sender, recipient, amount); - approve(sender, msg.sender, amount); return true; } - function approve(address owner, address spender, uint256 amount) public returns (bool) { - require(owner != address(0), "ERC20: approve from the zero address"); + function approve(address spender, uint256 amount) public returns (bool) { require(spender != address(0), "ERC20: approve to the zero address"); - _allowances[owner][spender] = amount; - emit Approval(owner, spender, amount); + _allowances[msg.sender][spender] = amount; + emit Approval(msg.sender, spender, amount); return true; } function _transfer(address sender, address recipient, uint256 amount) internal { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); + require(_balances[sender] >= amount, "ERC20: Not enough funds."); _balances[sender] -= amount; _balances[recipient] += amount; From f30130888e0daf706c23b2a0026c56cfbc9092ee Mon Sep 17 00:00:00 2001 From: Pranay Reddy Date: Mon, 3 Jan 2022 11:20:52 +0530 Subject: [PATCH 18/77] Added specificity to data location. Added the specificity that bytes1[] and bytes differ because of padding only in memory data location. Added extra sentence that they are similar when used in storage data location. --- docs/types/reference-types.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/types/reference-types.rst b/docs/types/reference-types.rst index cc6fe2d8a..126440321 100644 --- a/docs/types/reference-types.rst +++ b/docs/types/reference-types.rst @@ -153,7 +153,8 @@ third-party string libraries. You can also compare two strings by their keccak25 concatenate two strings using ``bytes.concat(bytes(s1), bytes(s2))``. You should use ``bytes`` over ``bytes1[]`` because it is cheaper, -since ``bytes1[]`` adds 31 padding bytes between the elements. As a general rule, +since using ``bytes1[]`` in ``memory`` adds 31 padding bytes between the elements. Note that in ``storage``, the +padding is absent due to tight packing, see :ref:`bytes and string `. As a general rule, use ``bytes`` for arbitrary-length raw byte data and ``string`` for arbitrary-length string (UTF-8) data. If you can limit the length to a certain number of bytes, always use one of the value types ``bytes1`` to ``bytes32`` because they are much cheaper. From 5597d43635df0c1df09be6c13d326f7ef6cf9d3a Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 3 Jan 2022 14:03:40 +0100 Subject: [PATCH 19/77] Add impish to static Z3 PPA script. --- scripts/deps-ppa/static_z3.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/deps-ppa/static_z3.sh b/scripts/deps-ppa/static_z3.sh index e8dec0fae..733f9bf3d 100755 --- a/scripts/deps-ppa/static_z3.sh +++ b/scripts/deps-ppa/static_z3.sh @@ -27,7 +27,7 @@ email=builds@ethereum.org packagename=z3-static version=4.8.13 -DISTRIBUTIONS="focal groovy hirsute" +DISTRIBUTIONS="focal groovy hirsute impish" for distribution in $DISTRIBUTIONS do From e5f912ec89b2a695d783ea6ac80502480254d7d4 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 3 Jan 2022 15:33:51 +0100 Subject: [PATCH 20/77] Add static z3 build and version check to release checklist. --- ReleaseChecklist.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ReleaseChecklist.md b/ReleaseChecklist.md index eaa859fe7..7bfea128a 100644 --- a/ReleaseChecklist.md +++ b/ReleaseChecklist.md @@ -54,7 +54,8 @@ - [ ] Run ``./scripts/docker_deploy_manual.sh v$VERSION``). ### PPA - - [ ] Change ``scripts/release_ppa.sh`` to match your key's email and key id. + - [ ] Make sure the ``ethereum/cpp-build-deps`` PPA repository contains libz3-static-dev builds for all current versions of ubuntu. If not run ``scripts/deps-ppa/static-z3.sh`` (after changing email address and key id and adding the missing ubuntu version) and wait for the builds to succeed before continuing. + - [ ] Change ``scripts/release_ppa.sh`` to match your key's email and key id; double-check that ``DISTRIBUTIONS`` contains the most recent versions. - [ ] Run ``scripts/release_ppa.sh v$VERSION`` to create the PPA release (you need the relevant openssl key). - [ ] Wait for the ``~ethereum/ubuntu/ethereum-static`` PPA build to be finished and published for *all platforms*. SERIOUSLY: DO NOT PROCEED EARLIER!!! *After* the static builds are *published*, copy the static package to the ``~ethereum/ubuntu/ethereum`` PPA for the destination series ``Trusty``, ``Xenial`` and ``Bionic`` while selecting ``Copy existing binaries``. From 57474917a097f32a94a2e8f06574ade6fc3bd36d Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 3 Jan 2022 15:37:29 +0100 Subject: [PATCH 21/77] Clarify which functions are added. --- docs/contracts/libraries.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/contracts/libraries.rst b/docs/contracts/libraries.rst index 4f0f03fec..76bedba49 100644 --- a/docs/contracts/libraries.rst +++ b/docs/contracts/libraries.rst @@ -34,7 +34,8 @@ contracts (using qualified access like ``L.f()``). Of course, calls to internal functions use the internal calling convention, which means that all internal types can be passed and types :ref:`stored in memory ` will be passed by reference and not copied. -To realize this in the EVM, code of internal library functions +To realize this in the EVM, the code of internal library functions +that are called from a contract and all functions called from therein will at compile time be included in the calling contract, and a regular ``JUMP`` call will be used instead of a ``DELEGATECALL``. From 772e1008136fe571c62679c32e2ede5e80965c13 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 11 Nov 2021 15:54:38 +0100 Subject: [PATCH 22/77] Equal store eliminator. --- Changelog.md | 1 + libsolidity/interface/OptimiserSettings.h | 2 +- libyul/CMakeLists.txt | 2 + libyul/optimiser/EqualStoreEliminator.cpp | 77 +++++++++++++++++++ libyul/optimiser/EqualStoreEliminator.h | 60 +++++++++++++++ libyul/optimiser/OptimizerUtilities.cpp | 15 ++++ libyul/optimiser/OptimizerUtilities.h | 11 +++ libyul/optimiser/Suite.cpp | 3 + libyul/optimiser/UnusedAssignEliminator.cpp | 1 + libyul/optimiser/UnusedStoreBase.cpp | 16 +--- libyul/optimiser/UnusedStoreBase.h | 10 --- test/libyul/YulOptimizerTestCommon.cpp | 6 ++ .../mstore_with_keccak.yul | 31 ++++++++ test/yulPhaser/Chromosome.cpp | 2 +- 14 files changed, 210 insertions(+), 27 deletions(-) create mode 100644 libyul/optimiser/EqualStoreEliminator.cpp create mode 100644 libyul/optimiser/EqualStoreEliminator.h create mode 100644 test/libyul/yulOptimizerTests/equalStoreEliminator/mstore_with_keccak.yul diff --git a/Changelog.md b/Changelog.md index b88e1a971..6e3602c1f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,6 +5,7 @@ Language Features: Compiler Features: + * Yul Optimizer: Remove ``mstore`` and ``sstore`` operations if the slot already contains the same value. diff --git a/libsolidity/interface/OptimiserSettings.h b/libsolidity/interface/OptimiserSettings.h index 5317acee4..e1c35e9ea 100644 --- a/libsolidity/interface/OptimiserSettings.h +++ b/libsolidity/interface/OptimiserSettings.h @@ -44,7 +44,7 @@ struct OptimiserSettings static char constexpr DefaultYulOptimiserSteps[] = "dhfoDgvulfnTUtnIf" // None of these can make stack problems worse "[" - "xa[r]scLM" // Turn into SSA and simplify + "xa[r]EscLM" // Turn into SSA and simplify "cCTUtTOntnfDIul" // Perform structural simplification "Lcul" // Simplify again "Vcul [j]" // Reverse SSA diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index 16b68535a..fde673e3d 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -120,6 +120,8 @@ add_library(yul optimiser/DeadCodeEliminator.h optimiser/Disambiguator.cpp optimiser/Disambiguator.h + optimiser/EqualStoreEliminator.cpp + optimiser/EqualStoreEliminator.h optimiser/EquivalentFunctionDetector.cpp optimiser/EquivalentFunctionDetector.h optimiser/EquivalentFunctionCombiner.cpp diff --git a/libyul/optimiser/EqualStoreEliminator.cpp b/libyul/optimiser/EqualStoreEliminator.cpp new file mode 100644 index 000000000..c89567868 --- /dev/null +++ b/libyul/optimiser/EqualStoreEliminator.cpp @@ -0,0 +1,77 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * Optimisation stage that removes mstore and sstore operations if they store the same + * value that is already known to be in that slot. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +using namespace std; +using namespace solidity; +using namespace solidity::util; +using namespace solidity::evmasm; +using namespace solidity::yul; + +void EqualStoreEliminator::run(OptimiserStepContext const& _context, Block& _ast) +{ + EqualStoreEliminator eliminator{ + _context.dialect, + SideEffectsPropagator::sideEffects(_context.dialect, CallGraphGenerator::callGraph(_ast)) + }; + eliminator(_ast); + + StatementRemover remover{eliminator.m_pendingRemovals}; + remover(_ast); +} + +void EqualStoreEliminator::visit(Statement& _statement) +{ + // No need to consider potential changes through complex arguments since + // isSimpleStore only returns something if the arguments are identifiers. + if (ExpressionStatement const* expression = get_if(&_statement)) + { + if (auto vars = isSimpleStore(StoreLoadLocation::Storage, *expression)) + { + if (auto const* currentValue = valueOrNullptr(m_storage, vars->first)) + if (*currentValue == vars->second) + m_pendingRemovals.insert(&_statement); + } + else if (auto vars = isSimpleStore(StoreLoadLocation::Memory, *expression)) + { + if (auto const* currentValue = valueOrNullptr(m_memory, vars->first)) + if (*currentValue == vars->second) + m_pendingRemovals.insert(&_statement); + } + } + + DataFlowAnalyzer::visit(_statement); +} diff --git a/libyul/optimiser/EqualStoreEliminator.h b/libyul/optimiser/EqualStoreEliminator.h new file mode 100644 index 000000000..796fcc538 --- /dev/null +++ b/libyul/optimiser/EqualStoreEliminator.h @@ -0,0 +1,60 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * Optimisation stage that removes mstore and sstore operations if they store the same + * value that is already known to be in that slot. + */ + +#pragma once + +#include +#include + +namespace solidity::yul +{ + +/** + * Optimisation stage that removes mstore and sstore operations if they store the same + * value that is already known to be in that slot. + * + * Works best if the code is in SSA form - without literal arguments. + * + * Prerequisite: Disambiguator, ForLoopInitRewriter. + */ +class EqualStoreEliminator: public DataFlowAnalyzer +{ +public: + static constexpr char const* name{"EqualStoreEliminator"}; + static void run(OptimiserStepContext const&, Block& _ast); + +private: + EqualStoreEliminator( + Dialect const& _dialect, + std::map _functionSideEffects + ): + DataFlowAnalyzer(_dialect, std::move(_functionSideEffects)) + {} + +protected: + using ASTModifier::visit; + void visit(Statement& _statement) override; + + std::set m_pendingRemovals; +}; + +} diff --git a/libyul/optimiser/OptimizerUtilities.cpp b/libyul/optimiser/OptimizerUtilities.cpp index 23596a745..ba06b2180 100644 --- a/libyul/optimiser/OptimizerUtilities.cpp +++ b/libyul/optimiser/OptimizerUtilities.cpp @@ -57,3 +57,18 @@ optional yul::toEVMInstruction(Dialect const& _dialect, Yul return builtin->instruction; return nullopt; } + +void StatementRemover::operator()(Block& _block) +{ + util::iterateReplacing( + _block.statements, + [&](Statement& _statement) -> std::optional> + { + if (m_toRemove.count(&_statement)) + return {vector{}}; + else + return nullopt; + } + ); + ASTModifier::operator()(_block); +} diff --git a/libyul/optimiser/OptimizerUtilities.h b/libyul/optimiser/OptimizerUtilities.h index d80b16316..b491e57e1 100644 --- a/libyul/optimiser/OptimizerUtilities.h +++ b/libyul/optimiser/OptimizerUtilities.h @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -48,4 +49,14 @@ bool isRestrictedIdentifier(Dialect const& _dialect, YulString const& _identifie /// Helper function that returns the instruction, if the `_name` is a BuiltinFunction std::optional toEVMInstruction(Dialect const& _dialect, YulString const& _name); +class StatementRemover: public ASTModifier +{ +public: + explicit StatementRemover(std::set const& _toRemove): m_toRemove(_toRemove) {} + + void operator()(Block& _block) override; +private: + std::set const& m_toRemove; +}; + } diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index 4012fa970..0f2194061 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -204,6 +205,7 @@ map> const& OptimiserSuite::allSteps() ConditionalUnsimplifier, ControlFlowSimplifier, DeadCodeEliminator, + EqualStoreEliminator, EquivalentFunctionCombiner, ExpressionInliner, ExpressionJoiner, @@ -244,6 +246,7 @@ map const& OptimiserSuite::stepNameToAbbreviationMap() {ConditionalUnsimplifier::name, 'U'}, {ControlFlowSimplifier::name, 'n'}, {DeadCodeEliminator::name, 'D'}, + {EqualStoreEliminator::name, 'E'}, {EquivalentFunctionCombiner::name, 'v'}, {ExpressionInliner::name, 'e'}, {ExpressionJoiner::name, 'j'}, diff --git a/libyul/optimiser/UnusedAssignEliminator.cpp b/libyul/optimiser/UnusedAssignEliminator.cpp index 74dd599a1..273aa6b79 100644 --- a/libyul/optimiser/UnusedAssignEliminator.cpp +++ b/libyul/optimiser/UnusedAssignEliminator.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include diff --git a/libyul/optimiser/UnusedStoreBase.cpp b/libyul/optimiser/UnusedStoreBase.cpp index 27700bdf7..73f957ecc 100644 --- a/libyul/optimiser/UnusedStoreBase.cpp +++ b/libyul/optimiser/UnusedStoreBase.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -156,18 +157,3 @@ void UnusedStoreBase::merge(TrackedStores& _target, vector&& _sou merge(_target, move(ts)); _source.clear(); } - -void StatementRemover::operator()(Block& _block) -{ - util::iterateReplacing( - _block.statements, - [&](Statement& _statement) -> std::optional> - { - if (m_toRemove.count(&_statement)) - return {vector{}}; - else - return nullopt; - } - ); - ASTModifier::operator()(_block); -} diff --git a/libyul/optimiser/UnusedStoreBase.h b/libyul/optimiser/UnusedStoreBase.h index 3bd4e4297..15dccb04a 100644 --- a/libyul/optimiser/UnusedStoreBase.h +++ b/libyul/optimiser/UnusedStoreBase.h @@ -105,14 +105,4 @@ protected: size_t m_forLoopNestingDepth = 0; }; -class StatementRemover: public ASTModifier -{ -public: - explicit StatementRemover(std::set const& _toRemove): m_toRemove(_toRemove) {} - - void operator()(Block& _block) override; -private: - std::set const& m_toRemove; -}; - } diff --git a/test/libyul/YulOptimizerTestCommon.cpp b/test/libyul/YulOptimizerTestCommon.cpp index cc315c4b9..bb8458d78 100644 --- a/test/libyul/YulOptimizerTestCommon.cpp +++ b/test/libyul/YulOptimizerTestCommon.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -236,6 +237,11 @@ YulOptimizerTestCommon::YulOptimizerTestCommon( ForLoopInitRewriter::run(*m_context, *m_ast); UnusedAssignEliminator::run(*m_context, *m_ast); }}, + {"equalStoreEliminator", [&]() { + disambiguate(); + ForLoopInitRewriter::run(*m_context, *m_ast); + EqualStoreEliminator::run(*m_context, *m_ast); + }}, {"ssaPlusCleanup", [&]() { disambiguate(); ForLoopInitRewriter::run(*m_context, *m_ast); diff --git a/test/libyul/yulOptimizerTests/equalStoreEliminator/mstore_with_keccak.yul b/test/libyul/yulOptimizerTests/equalStoreEliminator/mstore_with_keccak.yul new file mode 100644 index 000000000..395fea6d0 --- /dev/null +++ b/test/libyul/yulOptimizerTests/equalStoreEliminator/mstore_with_keccak.yul @@ -0,0 +1,31 @@ +{ + let var_k := calldataload(0) + let _1 := 0x00 + let _2 := 0x20 + mstore(_1, var_k) + mstore(_2, _1) + sstore(keccak256(_1, 0x40), 0x01) + mstore(_1, var_k) + mstore(_2, _1) + sstore(add(keccak256(_1, 0x40), 0x01), 0x03) + mstore(_1, var_k) + mstore(_2, _1) + sstore(add(keccak256(_1, 0x40), 2), 0x04) + mstore(_1, var_k) + mstore(_2, _1) + sstore(add(keccak256(_1, 0x40), 0x03), 2) +} +// ---- +// step: equalStoreEliminator +// +// { +// let var_k := calldataload(0) +// let _1 := 0x00 +// let _2 := 0x20 +// mstore(_1, var_k) +// mstore(_2, _1) +// sstore(keccak256(_1, 0x40), 0x01) +// sstore(add(keccak256(_1, 0x40), 0x01), 0x03) +// sstore(add(keccak256(_1, 0x40), 2), 0x04) +// sstore(add(keccak256(_1, 0x40), 0x03), 2) +// } diff --git a/test/yulPhaser/Chromosome.cpp b/test/yulPhaser/Chromosome.cpp index 19616cde0..d3e31b5e8 100644 --- a/test/yulPhaser/Chromosome.cpp +++ b/test/yulPhaser/Chromosome.cpp @@ -138,7 +138,7 @@ BOOST_AUTO_TEST_CASE(output_operator_should_create_concise_and_unambiguous_strin BOOST_TEST(chromosome.length() == allSteps.size()); BOOST_TEST(chromosome.optimisationSteps() == allSteps); - BOOST_TEST(toString(chromosome) == "flcCUnDvejsxIOoighFTLMRmVatrpud"); + BOOST_TEST(toString(chromosome) == "flcCUnDEvejsxIOoighFTLMRrmVatpud"); } BOOST_AUTO_TEST_CASE(optimisationSteps_should_translate_chromosomes_genes_to_optimisation_step_names) From e7fc2a176acd0d13e8e7a1df0ae12f2a2bcec0d5 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 11 Nov 2021 16:39:13 +0100 Subject: [PATCH 23/77] Test updates. --- .../functionCall/mapping_array_internal_argument.sol | 2 +- test/libsolidity/semanticTests/structs/struct_copy.sol | 4 ++-- .../yulOptimizerTests/fullSuite/stack_compressor_msize.yul | 1 - .../fullSuite/unusedFunctionParameterPruner_loop.yul | 2 -- .../fullSuite/unusedFunctionParameterPruner_simple.yul | 2 -- 5 files changed, 3 insertions(+), 8 deletions(-) diff --git a/test/libsolidity/semanticTests/functionCall/mapping_array_internal_argument.sol b/test/libsolidity/semanticTests/functionCall/mapping_array_internal_argument.sol index f01a590eb..d3e2ba075 100644 --- a/test/libsolidity/semanticTests/functionCall/mapping_array_internal_argument.sol +++ b/test/libsolidity/semanticTests/functionCall/mapping_array_internal_argument.sol @@ -20,7 +20,7 @@ contract test { // compileViaYul: also // ---- // set(uint8,uint8,uint8,uint8,uint8): 1, 21, 22, 42, 43 -> 0, 0, 0, 0 -// gas irOptimized: 111965 +// gas irOptimized: 111896 // gas legacy: 113806 // gas legacyOptimized: 111781 // get(uint8): 1 -> 21, 22, 42, 43 diff --git a/test/libsolidity/semanticTests/structs/struct_copy.sol b/test/libsolidity/semanticTests/structs/struct_copy.sol index 0bbb6489e..f170dca3f 100644 --- a/test/libsolidity/semanticTests/structs/struct_copy.sol +++ b/test/libsolidity/semanticTests/structs/struct_copy.sol @@ -38,12 +38,12 @@ contract c { // compileViaYul: also // ---- // set(uint256): 7 -> true -// gas irOptimized: 110011 +// gas irOptimized: 110119 // gas legacy: 110616 // gas legacyOptimized: 110006 // retrieve(uint256): 7 -> 1, 3, 4, 2 // copy(uint256,uint256): 7, 8 -> true -// gas irOptimized: 118707 +// gas irOptimized: 118698 // gas legacy: 119166 // gas legacyOptimized: 118622 // retrieve(uint256): 7 -> 1, 3, 4, 2 diff --git a/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul b/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul index d670f002f..13683e8e6 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/stack_compressor_msize.yul @@ -55,7 +55,6 @@ // sstore(0, 0) // sstore(2, _1) // extcodecopy(_1, msize(), _1, _1) -// sstore(0, 0) // sstore(3, _1) // } // function gcd(_a, _b) -> out diff --git a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_loop.yul b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_loop.yul index b531842db..ee648f80f 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_loop.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_loop.yul @@ -20,9 +20,7 @@ // f() // sstore(0, 1) // f() -// sstore(0, 1) // f() -// sstore(0, 1) // } // function f() // { diff --git a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_simple.yul b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_simple.yul index 531b1a6ce..68620cc96 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_simple.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/unusedFunctionParameterPruner_simple.yul @@ -18,9 +18,7 @@ // f() // sstore(0, 1) // f() -// sstore(0, 1) // f() -// sstore(0, 1) // } // function f() // { From b354c81a638e0abd2e5b4e29ee05c10d405807bd Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 24 Nov 2021 10:14:59 +0100 Subject: [PATCH 24/77] Documentation --- docs/internals/optimizer.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/internals/optimizer.rst b/docs/internals/optimizer.rst index 19bca791e..a7eff7346 100644 --- a/docs/internals/optimizer.rst +++ b/docs/internals/optimizer.rst @@ -290,6 +290,7 @@ on the individual steps and their sequence below. - :ref:`conditional-unsimplifier`. - :ref:`control-flow-simplifier`. - :ref:`dead-code-eliminator`. +- :ref:`equal-store-eliminator`. - :ref:`equivalent-function-combiner`. - :ref:`expression-joiner`. - :ref:`expression-simplifier`. @@ -938,6 +939,22 @@ we require ForLoopInitRewriter to run before this step. Prerequisite: ForLoopInitRewriter, Function Hoister, Function Grouper +.. _equal-store-eliminator: + +EqualStoreEliminator +^^^^^^^^^^^^^^^^^^^^ + +This steps removes ``mstore(k, v)`` and ``sstore(k, v)`` calls if +there was a previous call to ``mstore(k, v)`` / ``sstore(k, v)``, +no other store in between and the values of ``k`` and ``v`` did not change. + +This simple step is effective if run after the SSA transform and the +Common Subexpression Eliminator, because SSA will make sure that the variables +will not change and the Common Subexpression Eliminator re-uses exactly the same +variable if the value is known to be the same. + +Prerequisites: Disambiguator, ForLoopInitRewriter + .. _unused-pruner: UnusedPruner From 259a98b82c84d40714dc8f250092a572947f014f Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Mon, 3 Jan 2022 18:22:42 +0100 Subject: [PATCH 25/77] Impose stricter upper bound on memory accesses in order to prevent overflow/wrap around. --- test/tools/yulInterpreter/EVMInstructionInterpreter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp b/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp index 1e030d098..067e00a9e 100644 --- a/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp +++ b/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp @@ -476,7 +476,9 @@ bool EVMInstructionInterpreter::accessMemory(u256 const& _offset, u256 const& _s { u256 newSize = (_offset + _size + 0x1f) & ~u256(0x1f); m_state.msize = max(m_state.msize, newSize); - return _size <= 0xffff; + // We only record accesses to contiguous memory chunks that are at most 0xffff bytes + // in size and at an offset of at most numeric_limits::max() - 0xffff + return _size <= 0xffff && _offset <= u256(numeric_limits::max() - 0xffff); } else m_state.msize = u256(-1); From 6fe1ee6a8ae344c0767ecfd08c3ff391140ae463 Mon Sep 17 00:00:00 2001 From: Braden Watling Date: Mon, 3 Jan 2022 17:22:23 -0500 Subject: [PATCH 26/77] Fix typo in control-structures.rst I'm learning Solidity by reading these docs and found this statement confusing. I'm fairly certain that the correct description here is that the *callee* changes get reverted, but the caller is able to react to the failures. I tested this with the following snippet in Remix, which resulted in a successful transaction when deployed: ``` // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.7; contract A { uint public value; function a(uint newValue, bool shouldRevert) external { value = newValue; if (shouldRevert) { revert(); } } } contract B { function b() external { A a = new A(); try a.a(50, false) { assert(a.value() == 50); } catch { assert(false); } a = new A(); try a.a(50, true) { assert(false); } catch { assert(a.value() == 0); } } } ``` --- docs/control-structures.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 7881a22ec..879901e44 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -699,7 +699,7 @@ safest action is to revert all changes and make the whole transaction (or at least call) without effect. In both cases, the caller can react on such failures using ``try``/``catch``, but -the changes in the caller will always be reverted. +the changes in the callee will always be reverted. .. note:: From 85d1a57e65a1490db812a4531fc0b85d42ad8669 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 3 Jan 2022 15:19:25 +0530 Subject: [PATCH 27/77] Added more tests. Updated chromosome. Remove unused headers. --- libyul/optimiser/EqualStoreEliminator.cpp | 7 --- libyul/optimiser/UnusedStoreBase.cpp | 1 - .../externalContracts/deposit_contract.sol | 2 +- .../equalStoreEliminator/branching.yul | 25 +++++++++ .../equalStoreEliminator/forloop.yul | 20 +++++++ .../equalStoreEliminator/functionbody.yul | 56 +++++++++++++++++++ .../indirect_inferrence.yul | 24 ++++++++ .../equalStoreEliminator/value_change.yul | 18 ++++++ .../equalStoreEliminator/verbatim.yul | 27 +++++++++ test/yulPhaser/Chromosome.cpp | 2 +- 10 files changed, 172 insertions(+), 10 deletions(-) create mode 100644 test/libyul/yulOptimizerTests/equalStoreEliminator/branching.yul create mode 100644 test/libyul/yulOptimizerTests/equalStoreEliminator/forloop.yul create mode 100644 test/libyul/yulOptimizerTests/equalStoreEliminator/functionbody.yul create mode 100644 test/libyul/yulOptimizerTests/equalStoreEliminator/indirect_inferrence.yul create mode 100644 test/libyul/yulOptimizerTests/equalStoreEliminator/value_change.yul create mode 100644 test/libyul/yulOptimizerTests/equalStoreEliminator/verbatim.yul diff --git a/libyul/optimiser/EqualStoreEliminator.cpp b/libyul/optimiser/EqualStoreEliminator.cpp index c89567868..dcba98ce4 100644 --- a/libyul/optimiser/EqualStoreEliminator.cpp +++ b/libyul/optimiser/EqualStoreEliminator.cpp @@ -25,16 +25,9 @@ #include #include #include -#include -#include #include #include -#include -#include - -#include - using namespace std; using namespace solidity; using namespace solidity::util; diff --git a/libyul/optimiser/UnusedStoreBase.cpp b/libyul/optimiser/UnusedStoreBase.cpp index 73f957ecc..8e34d172f 100644 --- a/libyul/optimiser/UnusedStoreBase.cpp +++ b/libyul/optimiser/UnusedStoreBase.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include diff --git a/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol b/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol index ed9a07f7f..7f5799805 100644 --- a/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol +++ b/test/libsolidity/semanticTests/externalContracts/deposit_contract.sol @@ -178,7 +178,7 @@ contract DepositContract is IDepositContract, ERC165 { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 1558001 +// gas irOptimized: 1557137 // gas legacy: 2436584 // gas legacyOptimized: 1776483 // supportsInterface(bytes4): 0x0 -> 0 diff --git a/test/libyul/yulOptimizerTests/equalStoreEliminator/branching.yul b/test/libyul/yulOptimizerTests/equalStoreEliminator/branching.yul new file mode 100644 index 000000000..63f0d38e4 --- /dev/null +++ b/test/libyul/yulOptimizerTests/equalStoreEliminator/branching.yul @@ -0,0 +1,25 @@ +{ + let a := calldataload(0) + let b := 20 + sstore(a, b) + if calldataload(32) { + sstore(a, b) + pop(staticcall(0, 0, 0, 0, 0, 0)) + sstore(a, b) + } + sstore(a, b) +} +// ==== +// EVMVersion: >=byzantium +// ---- +// step: equalStoreEliminator +// +// { +// let a := calldataload(0) +// let b := 20 +// sstore(a, b) +// if calldataload(32) +// { +// pop(staticcall(0, 0, 0, 0, 0, 0)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/equalStoreEliminator/forloop.yul b/test/libyul/yulOptimizerTests/equalStoreEliminator/forloop.yul new file mode 100644 index 000000000..ccd7dd40b --- /dev/null +++ b/test/libyul/yulOptimizerTests/equalStoreEliminator/forloop.yul @@ -0,0 +1,20 @@ +{ + let x := calldataload(0) + let y := calldataload(1) + + sstore(x, y) + for {let a := 1} lt(a, 10) {a := add(a, 1) } { + sstore(x, y) + } +} +// ---- +// step: equalStoreEliminator +// +// { +// let x := calldataload(0) +// let y := calldataload(1) +// sstore(x, y) +// let a := 1 +// for { } lt(a, 10) { a := add(a, 1) } +// { sstore(x, y) } +// } diff --git a/test/libyul/yulOptimizerTests/equalStoreEliminator/functionbody.yul b/test/libyul/yulOptimizerTests/equalStoreEliminator/functionbody.yul new file mode 100644 index 000000000..68839721c --- /dev/null +++ b/test/libyul/yulOptimizerTests/equalStoreEliminator/functionbody.yul @@ -0,0 +1,56 @@ +{ + f(calldataload(0), calldataload(32)) + h(calldataload(64), calldataload(96)) + + function f(a, b) { + // gets removed + sstore(a, b) + g() + sstore(a, b) + } + + function g() { + pop(staticcall(0, 0, 0, 0, 0, 0)) + } + + function h(a_, b_) { + // cannot be removed + sstore(a_, b_) + i() + sstore(a_, b_) + } + + function i() { + pop(delegatecall(0, 0, 0, 0, 0, 0)) + } + + +} +// ==== +// EVMVersion: >=byzantium +// ---- +// step: equalStoreEliminator +// +// { +// f(calldataload(0), calldataload(32)) +// h(calldataload(64), calldataload(96)) +// function f(a, b) +// { +// sstore(a, b) +// g() +// } +// function g() +// { +// pop(staticcall(0, 0, 0, 0, 0, 0)) +// } +// function h(a_, b_) +// { +// sstore(a_, b_) +// i() +// sstore(a_, b_) +// } +// function i() +// { +// pop(delegatecall(0, 0, 0, 0, 0, 0)) +// } +// } diff --git a/test/libyul/yulOptimizerTests/equalStoreEliminator/indirect_inferrence.yul b/test/libyul/yulOptimizerTests/equalStoreEliminator/indirect_inferrence.yul new file mode 100644 index 000000000..2b68e6310 --- /dev/null +++ b/test/libyul/yulOptimizerTests/equalStoreEliminator/indirect_inferrence.yul @@ -0,0 +1,24 @@ +{ + let x := calldataload(0) + let y := sload(x) + // both of these can be removed + sstore(x, y) + sstore(x, y) + + let a := x + let b := mload(a) + // both of these can be removed + mstore(a, b) + mstore(a, b) +} +// ==== +// EVMVersion: >=byzantium +// ---- +// step: equalStoreEliminator +// +// { +// let x := calldataload(0) +// let y := sload(x) +// let a := x +// let b := mload(a) +// } diff --git a/test/libyul/yulOptimizerTests/equalStoreEliminator/value_change.yul b/test/libyul/yulOptimizerTests/equalStoreEliminator/value_change.yul new file mode 100644 index 000000000..bd1e08bcd --- /dev/null +++ b/test/libyul/yulOptimizerTests/equalStoreEliminator/value_change.yul @@ -0,0 +1,18 @@ +{ + let x := calldataload(0) + let y := calldataload(32) + sstore(x, y) + y := calldataload(64) + // cannot be removed + sstore(x, y) +} +// ---- +// step: equalStoreEliminator +// +// { +// let x := calldataload(0) +// let y := calldataload(32) +// sstore(x, y) +// y := calldataload(64) +// sstore(x, y) +// } diff --git a/test/libyul/yulOptimizerTests/equalStoreEliminator/verbatim.yul b/test/libyul/yulOptimizerTests/equalStoreEliminator/verbatim.yul new file mode 100644 index 000000000..fcaddd121 --- /dev/null +++ b/test/libyul/yulOptimizerTests/equalStoreEliminator/verbatim.yul @@ -0,0 +1,27 @@ +{ + let a := calldataload(0) + let b := 20 + sstore(a, b) + if calldataload(32) { + sstore(a, b) + pop(staticcall(0, 0, 0, 0, 0, 0)) + verbatim_0i_0o("xyz") + } + sstore(a, b) +} +// ==== +// EVMVersion: >=byzantium +// ---- +// step: equalStoreEliminator +// +// { +// let a := calldataload(0) +// let b := 20 +// sstore(a, b) +// if calldataload(32) +// { +// pop(staticcall(0, 0, 0, 0, 0, 0)) +// verbatim_0i_0o("xyz") +// } +// sstore(a, b) +// } diff --git a/test/yulPhaser/Chromosome.cpp b/test/yulPhaser/Chromosome.cpp index d3e31b5e8..1b1e8bed5 100644 --- a/test/yulPhaser/Chromosome.cpp +++ b/test/yulPhaser/Chromosome.cpp @@ -138,7 +138,7 @@ BOOST_AUTO_TEST_CASE(output_operator_should_create_concise_and_unambiguous_strin BOOST_TEST(chromosome.length() == allSteps.size()); BOOST_TEST(chromosome.optimisationSteps() == allSteps); - BOOST_TEST(toString(chromosome) == "flcCUnDEvejsxIOoighFTLMRrmVatpud"); + BOOST_TEST(toString(chromosome) == "flcCUnDEvejsxIOoighFTLMRmVatrpud"); } BOOST_AUTO_TEST_CASE(optimisationSteps_should_translate_chromosomes_genes_to_optimisation_step_names) From bb16c1943c6b2a09855c5734f8f5c30cb6c7c9d9 Mon Sep 17 00:00:00 2001 From: Braden Watling Date: Mon, 3 Jan 2022 17:46:12 -0500 Subject: [PATCH 28/77] Fix gas retaining statement. According to https://docs.soliditylang.org/en/v0.8.11/introduction-to-smart-contracts.html?highlight=63%2F64#message-calls, the caller forwards 63/64th of its gas, but here we seem to contradict that by saying the caller retains 63/64th of its gas. --- docs/control-structures.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 879901e44..0ce7d21e3 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -895,6 +895,6 @@ in scope in the block that follows. The error might have happened deeper down in the call chain and the called contract just forwarded it. Also, it could be due to an out-of-gas situation and not a deliberate error condition: - The caller always retains 63/64th of the gas in a call and thus + The caller always retains at least 1/64th of the gas in a call and thus even if the called contract goes out of gas, the caller still has some gas left. From b8ad2b2718f6aa7ca2e418a1a0e2cc36c029db03 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Mon, 20 Sep 2021 22:05:03 +0200 Subject: [PATCH 29/77] Yul interpreter: Add flag to disable memory tracing and dump for fuzzing. Model revert in yul interpreter. Add logTrace for a few more instructions and clear trace on revert. --- test/libyul/EwasmTranslationTest.cpp | 9 +++- test/libyul/YulInterpreterTest.cpp | 9 +++- test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp | 10 +++- test/tools/ossfuzz/yulFuzzerCommon.cpp | 5 +- test/tools/ossfuzz/yulFuzzerCommon.h | 7 +++ test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp | 17 ++++-- .../EVMInstructionInterpreter.cpp | 54 ++++++++++++++----- .../EVMInstructionInterpreter.h | 28 ++++++++-- test/tools/yulInterpreter/Interpreter.cpp | 36 ++++++++----- test/tools/yulInterpreter/Interpreter.h | 29 ++++++++-- test/tools/yulrun.cpp | 4 +- 11 files changed, 158 insertions(+), 50 deletions(-) diff --git a/test/libyul/EwasmTranslationTest.cpp b/test/libyul/EwasmTranslationTest.cpp index 9bd80f4b1..17b7f1868 100644 --- a/test/libyul/EwasmTranslationTest.cpp +++ b/test/libyul/EwasmTranslationTest.cpp @@ -108,13 +108,18 @@ string EwasmTranslationTest::interpret() state.maxExprNesting = 64; try { - Interpreter::run(state, WasmDialect{}, *m_object->code); + Interpreter::run( + state, + WasmDialect{}, + *m_object->code, + /*disableMemoryTracing=*/false + ); } catch (InterpreterTerminatedGeneric const&) { } stringstream result; - state.dumpTraceAndState(result); + state.dumpTraceAndState(result, false); return result.str(); } diff --git a/test/libyul/YulInterpreterTest.cpp b/test/libyul/YulInterpreterTest.cpp index ba47b4c08..3e7de4d17 100644 --- a/test/libyul/YulInterpreterTest.cpp +++ b/test/libyul/YulInterpreterTest.cpp @@ -94,13 +94,18 @@ string YulInterpreterTest::interpret() state.maxExprNesting = 64; try { - Interpreter::run(state, EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion{}), *m_ast); + Interpreter::run( + state, + EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion{}), + *m_ast, + /*disableMemoryTracing=*/false + ); } catch (InterpreterTerminatedGeneric const&) { } stringstream result; - state.dumpTraceAndState(result); + state.dumpTraceAndState(result, false); return result.str(); } diff --git a/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp b/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp index a3a789bc9..c6d52a62e 100644 --- a/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp +++ b/test/tools/ossfuzz/strictasm_diff_ossfuzz.cpp @@ -81,10 +81,15 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) ostringstream os1; ostringstream os2; + // Disable memory tracing to avoid false positive reports + // such as unused write to memory e.g., + // { mstore(0, 1) } + // that would be removed by the redundant store eliminator. yulFuzzerUtil::TerminationReason termReason = yulFuzzerUtil::interpret( os1, stack.parserResult()->code, - EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()) + EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()), + /*disableMemoryTracing=*/true ); if (yulFuzzerUtil::resourceLimitsExceeded(termReason)) return 0; @@ -93,7 +98,8 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size) termReason = yulFuzzerUtil::interpret( os2, stack.parserResult()->code, - EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()) + EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()), + /*disableMemoryTracing=*/true ); if (yulFuzzerUtil::resourceLimitsExceeded(termReason)) diff --git a/test/tools/ossfuzz/yulFuzzerCommon.cpp b/test/tools/ossfuzz/yulFuzzerCommon.cpp index 890aad3b8..cfbbbaa48 100644 --- a/test/tools/ossfuzz/yulFuzzerCommon.cpp +++ b/test/tools/ossfuzz/yulFuzzerCommon.cpp @@ -26,6 +26,7 @@ yulFuzzerUtil::TerminationReason yulFuzzerUtil::interpret( ostream& _os, shared_ptr _ast, Dialect const& _dialect, + bool _disableMemoryTracing, bool _outputStorageOnly, size_t _maxSteps, size_t _maxTraceSize, @@ -52,7 +53,7 @@ yulFuzzerUtil::TerminationReason yulFuzzerUtil::interpret( TerminationReason reason = TerminationReason::None; try { - Interpreter::run(state, _dialect, *_ast); + Interpreter::run(state, _dialect, *_ast, _disableMemoryTracing); } catch (StepLimitReached const&) { @@ -74,7 +75,7 @@ yulFuzzerUtil::TerminationReason yulFuzzerUtil::interpret( if (_outputStorageOnly) state.dumpStorage(_os); else - state.dumpTraceAndState(_os); + state.dumpTraceAndState(_os, _disableMemoryTracing); return reason; } diff --git a/test/tools/ossfuzz/yulFuzzerCommon.h b/test/tools/ossfuzz/yulFuzzerCommon.h index 71411a708..4c8f665f6 100644 --- a/test/tools/ossfuzz/yulFuzzerCommon.h +++ b/test/tools/ossfuzz/yulFuzzerCommon.h @@ -32,10 +32,17 @@ struct yulFuzzerUtil None }; + /// Interprets the Yul AST pointed to by @param _ast. Flag @param _outputStorageOnly + /// (unset by default) outputs an execution trace of both memory and storage; + /// if set, only storage contents are output as part of the execution trace. The + /// latter avoids false positives that will be produced by the fuzzer when certain + /// optimizer steps are activated e.g., Redundant store eliminator, Equal store + /// eliminator. static TerminationReason interpret( std::ostream& _os, std::shared_ptr _ast, Dialect const& _dialect, + bool _disableMemoryTracing = false, bool _outputStorageOnly = false, size_t _maxSteps = maxSteps, size_t _maxTraceSize = maxTraceSize, diff --git a/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp b/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp index 22f67e1cf..4cafccb28 100644 --- a/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp +++ b/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp @@ -88,10 +88,15 @@ DEFINE_PROTO_FUZZER(Program const& _input) ostringstream os1; ostringstream os2; + // Disable memory tracing to avoid false positive reports + // such as unused write to memory e.g., + // { mstore(0, 1) } + // that would be removed by the redundant store eliminator. yulFuzzerUtil::TerminationReason termReason = yulFuzzerUtil::interpret( os1, stack.parserResult()->code, - EVMDialect::strictAssemblyForEVMObjects(version) + EVMDialect::strictAssemblyForEVMObjects(version), + /*disableMemoryTracing=*/true ); if (yulFuzzerUtil::resourceLimitsExceeded(termReason)) @@ -107,12 +112,18 @@ DEFINE_PROTO_FUZZER(Program const& _input) termReason = yulFuzzerUtil::interpret( os2, astBlock, - EVMDialect::strictAssemblyForEVMObjects(version) + EVMDialect::strictAssemblyForEVMObjects(version), + true ); if (yulFuzzerUtil::resourceLimitsExceeded(termReason)) return; bool isTraceEq = (os1.str() == os2.str()); - yulAssert(isTraceEq, "Interpreted traces for optimized and unoptimized code differ."); + if (!isTraceEq) + { + cout << os1.str() << endl; + cout << os2.str() << endl; + yulAssert(false, "Interpreted traces for optimized and unoptimized code differ."); + } return; } diff --git a/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp b/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp index 067e00a9e..810cf9d18 100644 --- a/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp +++ b/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -35,6 +36,7 @@ using namespace std; using namespace solidity; +using namespace solidity::evmasm; using namespace solidity::yul; using namespace solidity::yul::test; @@ -99,6 +101,7 @@ u256 EVMInstructionInterpreter::eval( switch (_instruction) { case Instruction::STOP: + logTrace(_instruction); BOOST_THROW_EXCEPTION(ExplicitlyTerminated()); // --------------- arithmetic --------------- case Instruction::ADD: @@ -204,6 +207,7 @@ u256 EVMInstructionInterpreter::eval( case Instruction::CALLDATASIZE: return m_state.calldata.size(); case Instruction::CALLDATACOPY: + logTrace(_instruction, arg); if (accessMemory(arg[0], arg[2])) copyZeroExtended( m_state.memory, m_state.calldata, @@ -213,6 +217,7 @@ u256 EVMInstructionInterpreter::eval( case Instruction::CODESIZE: return m_state.code.size(); case Instruction::CODECOPY: + logTrace(_instruction, arg); if (accessMemory(arg[0], arg[2])) copyZeroExtended( m_state.memory, m_state.code, @@ -339,12 +344,18 @@ u256 EVMInstructionInterpreter::eval( case Instruction::REVERT: accessMemory(arg[0], arg[1]); logTrace(_instruction, arg); + m_state.storage.clear(); + m_state.trace.clear(); BOOST_THROW_EXCEPTION(ExplicitlyTerminated()); case Instruction::INVALID: logTrace(_instruction); + m_state.storage.clear(); + m_state.trace.clear(); BOOST_THROW_EXCEPTION(ExplicitlyTerminated()); case Instruction::SELFDESTRUCT: logTrace(_instruction, arg); + m_state.storage.clear(); + m_state.trace.clear(); BOOST_THROW_EXCEPTION(ExplicitlyTerminated()); case Instruction::POP: break; @@ -507,23 +518,40 @@ void EVMInstructionInterpreter::writeMemoryWord(u256 const& _offset, u256 const& } -void EVMInstructionInterpreter::logTrace(evmasm::Instruction _instruction, std::vector const& _arguments, bytes const& _data) +void EVMInstructionInterpreter::logTrace( + evmasm::Instruction _instruction, + std::vector const& _arguments, + bytes const& _data +) { - logTrace(evmasm::instructionInfo(_instruction).name, _arguments, _data); + logTrace( + evmasm::instructionInfo(_instruction).name, + SemanticInformation::memory(_instruction) == SemanticInformation::Effect::Write, + _arguments, + _data + ); } -void EVMInstructionInterpreter::logTrace(std::string const& _pseudoInstruction, std::vector const& _arguments, bytes const& _data) +void EVMInstructionInterpreter::logTrace( + std::string const& _pseudoInstruction, + bool _writesToMemory, + std::vector const& _arguments, + bytes const& _data +) { - string message = _pseudoInstruction + "("; - for (size_t i = 0; i < _arguments.size(); ++i) - message += (i > 0 ? ", " : "") + formatNumber(_arguments[i]); - message += ")"; - if (!_data.empty()) - message += " [" + util::toHex(_data) + "]"; - m_state.trace.emplace_back(std::move(message)); - if (m_state.maxTraceSize > 0 && m_state.trace.size() >= m_state.maxTraceSize) + if (!(_writesToMemory && memWriteTracingDisabled())) { - m_state.trace.emplace_back("Trace size limit reached."); - BOOST_THROW_EXCEPTION(TraceLimitReached()); + string message = _pseudoInstruction + "("; + for (size_t i = 0; i < _arguments.size(); ++i) + message += (i > 0 ? ", " : "") + formatNumber(_arguments[i]); + message += ")"; + if (!_data.empty()) + message += " [" + util::toHex(_data) + "]"; + m_state.trace.emplace_back(std::move(message)); + if (m_state.maxTraceSize > 0 && m_state.trace.size() >= m_state.maxTraceSize) + { + m_state.trace.emplace_back("Trace size limit reached."); + BOOST_THROW_EXCEPTION(TraceLimitReached()); + } } } diff --git a/test/tools/yulInterpreter/EVMInstructionInterpreter.h b/test/tools/yulInterpreter/EVMInstructionInterpreter.h index 2da5b45e5..c05af8c1a 100644 --- a/test/tools/yulInterpreter/EVMInstructionInterpreter.h +++ b/test/tools/yulInterpreter/EVMInstructionInterpreter.h @@ -66,8 +66,9 @@ struct InterpreterState; class EVMInstructionInterpreter { public: - explicit EVMInstructionInterpreter(InterpreterState& _state): - m_state(_state) + explicit EVMInstructionInterpreter(InterpreterState& _state, bool _disableMemWriteTrace): + m_state(_state), + m_disableMemoryWriteInstructions(_disableMemWriteTrace) {} /// Evaluate instruction u256 eval(evmasm::Instruction _instruction, std::vector const& _arguments); @@ -93,12 +94,29 @@ private: /// Does not adjust msize, use @a accessMemory for that void writeMemoryWord(u256 const& _offset, u256 const& _value); - void logTrace(evmasm::Instruction _instruction, std::vector const& _arguments = {}, bytes const& _data = {}); + void logTrace( + evmasm::Instruction _instruction, + std::vector const& _arguments = {}, + bytes const& _data = {} + ); /// Appends a log to the trace representing an instruction or similar operation by string, - /// with arguments and auxiliary data (if nonempty). - void logTrace(std::string const& _pseudoInstruction, std::vector const& _arguments = {}, bytes const& _data = {}); + /// with arguments and auxiliary data (if nonempty). Flag @param _writesToMemory indicates + /// whether the instruction writes to (true) or does not write to (false) memory. + void logTrace( + std::string const& _pseudoInstruction, + bool _writesToMemory, + std::vector const& _arguments = {}, + bytes const& _data = {} + ); + /// @returns disable trace flag. + bool memWriteTracingDisabled() + { + return m_disableMemoryWriteInstructions; + } InterpreterState& m_state; + /// Flag to disable trace of instructions that write to memory. + bool m_disableMemoryWriteInstructions; }; } // solidity::yul::test diff --git a/test/tools/yulInterpreter/Interpreter.cpp b/test/tools/yulInterpreter/Interpreter.cpp index 08c6aafd6..bf0ad820b 100644 --- a/test/tools/yulInterpreter/Interpreter.cpp +++ b/test/tools/yulInterpreter/Interpreter.cpp @@ -55,26 +55,34 @@ void InterpreterState::dumpStorage(ostream& _out) const _out << " " << slot.first.hex() << ": " << slot.second.hex() << endl; } -void InterpreterState::dumpTraceAndState(ostream& _out) const +void InterpreterState::dumpTraceAndState(ostream& _out, bool _disableMemoryTrace) const { _out << "Trace:" << endl; for (auto const& line: trace) _out << " " << line << endl; - _out << "Memory dump:\n"; - map words; - for (auto const& [offset, value]: memory) - words[(offset / 0x20) * 0x20] |= u256(uint32_t(value)) << (256 - 8 - 8 * static_cast(offset % 0x20)); - for (auto const& [offset, value]: words) - if (value != 0) - _out << " " << std::uppercase << std::hex << std::setw(4) << offset << ": " << h256(value).hex() << endl; + if (!_disableMemoryTrace) + { + _out << "Memory dump:\n"; + map words; + for (auto const& [offset, value]: memory) + words[(offset / 0x20) * 0x20] |= u256(uint32_t(value)) << (256 - 8 - 8 * static_cast(offset % 0x20)); + for (auto const& [offset, value]: words) + if (value != 0) + _out << " " << std::uppercase << std::hex << std::setw(4) << offset << ": " << h256(value).hex() << endl; + } _out << "Storage dump:" << endl; dumpStorage(_out); } -void Interpreter::run(InterpreterState& _state, Dialect const& _dialect, Block const& _ast) +void Interpreter::run( + InterpreterState& _state, + Dialect const& _dialect, + Block const& _ast, + bool _disableMemoryTrace +) { Scope scope; - Interpreter{_state, _dialect, scope}(_ast); + Interpreter{_state, _dialect, scope, _disableMemoryTrace}(_ast); } void Interpreter::operator()(ExpressionStatement const& _expressionStatement) @@ -209,14 +217,14 @@ void Interpreter::operator()(Block const& _block) u256 Interpreter::evaluate(Expression const& _expression) { - ExpressionEvaluator ev(m_state, m_dialect, *m_scope, m_variables); + ExpressionEvaluator ev(m_state, m_dialect, *m_scope, m_variables, m_disableMemoryTrace); ev.visit(_expression); return ev.value(); } vector Interpreter::evaluateMulti(Expression const& _expression) { - ExpressionEvaluator ev(m_state, m_dialect, *m_scope, m_variables); + ExpressionEvaluator ev(m_state, m_dialect, *m_scope, m_variables, m_disableMemoryTrace); ev.visit(_expression); return ev.values(); } @@ -279,7 +287,7 @@ void ExpressionEvaluator::operator()(FunctionCall const& _funCall) { if (BuiltinFunctionForEVM const* fun = dialect->builtin(_funCall.functionName.name)) { - EVMInstructionInterpreter interpreter(m_state); + EVMInstructionInterpreter interpreter(m_state, m_disableMemoryTrace); setValue(interpreter.evalBuiltin(*fun, _funCall.arguments, values())); return; } @@ -308,7 +316,7 @@ void ExpressionEvaluator::operator()(FunctionCall const& _funCall) variables[fun->returnVariables.at(i).name] = 0; m_state.controlFlowState = ControlFlowState::Default; - Interpreter interpreter(m_state, m_dialect, *scope, std::move(variables)); + Interpreter interpreter(m_state, m_dialect, *scope, m_disableMemoryTrace, std::move(variables)); interpreter(fun->body); m_state.controlFlowState = ControlFlowState::Default; diff --git a/test/tools/yulInterpreter/Interpreter.h b/test/tools/yulInterpreter/Interpreter.h index 621305422..cdc454401 100644 --- a/test/tools/yulInterpreter/Interpreter.h +++ b/test/tools/yulInterpreter/Interpreter.h @@ -102,7 +102,10 @@ struct InterpreterState ControlFlowState controlFlowState = ControlFlowState::Default; /// Prints execution trace and non-zero storage to @param _out. - void dumpTraceAndState(std::ostream& _out) const; + /// Flag @param _disableMemoryTrace, if set, does not produce a memory dump. This + /// avoids false positives reports by the fuzzer when certain optimizer steps are + /// activated e.g., Redundant store eliminator, Equal store eliminator. + void dumpTraceAndState(std::ostream& _out, bool _disableMemoryTrace) const; /// Prints non-zero storage to @param _out. void dumpStorage(std::ostream& _out) const; }; @@ -124,18 +127,29 @@ struct Scope class Interpreter: public ASTWalker { public: - static void run(InterpreterState& _state, Dialect const& _dialect, Block const& _ast); + /// Executes the Yul interpreter. Flag @param _disableMemoryTracing if set ensures that + /// instructions that write to memory do not affect @param _state. This + /// avoids false positives reports by the fuzzer when certain optimizer steps are + /// activated e.g., Redundant store eliminator, Equal store eliminator. + static void run( + InterpreterState& _state, + Dialect const& _dialect, + Block const& _ast, + bool _disableMemoryTracing + ); Interpreter( InterpreterState& _state, Dialect const& _dialect, Scope& _scope, + bool _disableMemoryTracing, std::map _variables = {} ): m_dialect(_dialect), m_state(_state), m_variables(std::move(_variables)), - m_scope(&_scope) + m_scope(&_scope), + m_disableMemoryTrace(_disableMemoryTracing) { } @@ -173,6 +187,7 @@ private: /// Values of variables. std::map m_variables; Scope* m_scope; + bool m_disableMemoryTrace; }; /** @@ -185,12 +200,14 @@ public: InterpreterState& _state, Dialect const& _dialect, Scope& _scope, - std::map const& _variables + std::map const& _variables, + bool _disableMemoryTrace ): m_state(_state), m_dialect(_dialect), m_variables(_variables), - m_scope(_scope) + m_scope(_scope), + m_disableMemoryTrace(_disableMemoryTrace) {} void operator()(Literal const&) override; @@ -226,6 +243,8 @@ private: std::vector m_values; /// Current expression nesting level unsigned m_nestingLevel = 0; + /// Flag to disable memory tracing + bool m_disableMemoryTrace; }; } diff --git a/test/tools/yulrun.cpp b/test/tools/yulrun.cpp index cb90a3f43..570299768 100644 --- a/test/tools/yulrun.cpp +++ b/test/tools/yulrun.cpp @@ -87,13 +87,13 @@ void interpret(string const& _source) try { Dialect const& dialect(EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion{})); - Interpreter::run(state, dialect, *ast); + Interpreter::run(state, dialect, *ast, /*disableMemoryTracing=*/false); } catch (InterpreterTerminatedGeneric const&) { } - state.dumpTraceAndState(cout); + state.dumpTraceAndState(cout, /*disableMemoryTracing=*/false); } } From 671064b60981f49171b26080ca3926651d965ac4 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 4 Jan 2022 18:27:31 +0100 Subject: [PATCH 30/77] Use fixed seed for flaky phaser test for now. --- test/yulPhaser/Mutations.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/yulPhaser/Mutations.cpp b/test/yulPhaser/Mutations.cpp index c42ff4e35..8e1d0238b 100644 --- a/test/yulPhaser/Mutations.cpp +++ b/test/yulPhaser/Mutations.cpp @@ -644,6 +644,8 @@ BOOST_AUTO_TEST_CASE(uniformCrossover_should_swap_tail_with_uniform_probability) Chromosome chromosome1("aaaaa"); Chromosome chromosome2("cccccccccc"); + SimulationRNG::reset(1); + vector bernoulliTrials; for (size_t i = 0; i < operationCount; ++i) { From c798ac472e28e5dbd27143706d78a70d1ea7e972 Mon Sep 17 00:00:00 2001 From: William Entriken Date: Tue, 4 Jan 2022 18:59:40 -0500 Subject: [PATCH 31/77] Typo: SemVer --- Changelog.md | 2 +- docs/installing-solidity.rst | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Changelog.md b/Changelog.md index b88e1a971..da977bc28 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2156,7 +2156,7 @@ Features: * Internal: Inline assembly usable by the code generator. * Commandline interface: Using ``-`` as filename allows reading from stdin. * Interface JSON: Fallback function is now part of the ABI. - * Interface: Version string now *semver* compatible. + * Interface: Version string now *SemVer* compatible. * Code generator: Do not provide "new account gas" if we know the called account exists. Bugfixes: diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst index dbfa7a4c5..d3f9015a2 100644 --- a/docs/installing-solidity.rst +++ b/docs/installing-solidity.rst @@ -537,8 +537,8 @@ The Solidity version string contains four parts: If there are local modifications, the commit will be postfixed with ``.mod``. -These parts are combined as required by Semver, where the Solidity pre-release tag equals to the Semver pre-release -and the Solidity commit and platform combined make up the Semver build metadata. +These parts are combined as required by SemVer, where the Solidity pre-release tag equals to the SemVer pre-release +and the Solidity commit and platform combined make up the SemVer build metadata. A release example: ``0.4.8+commit.60cc1668.Emscripten.clang``. @@ -549,7 +549,7 @@ Important Information About Versioning After a release is made, the patch version level is bumped, because we assume that only patch level changes follow. When changes are merged, the version should be bumped according -to semver and the severity of the change. Finally, a release is always made with the version +to SemVer and the severity of the change. Finally, a release is always made with the version of the current nightly build, but without the ``prerelease`` specifier. Example: From 4105b0a587bb7deeda1f189888e37014f053553c Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Mon, 3 Jan 2022 16:19:04 +0100 Subject: [PATCH 32/77] LSP: Introduce HandlerError(id, code, message) exception for easier handling. --- libsolidity/lsp/LanguageServer.cpp | 101 +++++++++++++++-------------- libsolidity/lsp/LanguageServer.h | 10 +-- libsolidity/lsp/Transport.h | 19 ++++++ 3 files changed, 76 insertions(+), 54 deletions(-) diff --git a/libsolidity/lsp/LanguageServer.cpp b/libsolidity/lsp/LanguageServer.cpp index 254706cc6..f9f023349 100644 --- a/libsolidity/lsp/LanguageServer.cpp +++ b/libsolidity/lsp/LanguageServer.cpp @@ -38,6 +38,7 @@ #include using namespace std; +using namespace std::string_literals; using namespace std::placeholders; using namespace solidity::lsp; @@ -96,10 +97,10 @@ LanguageServer::LanguageServer(Transport& _transport): {"initialize", bind(&LanguageServer::handleInitialize, this, _1, _2)}, {"initialized", [](auto, auto) {}}, {"shutdown", [this](auto, auto) { m_state = State::ShutdownRequested; }}, - {"textDocument/didOpen", bind(&LanguageServer::handleTextDocumentDidOpen, this, _1, _2)}, - {"textDocument/didChange", bind(&LanguageServer::handleTextDocumentDidChange, this, _1, _2)}, - {"textDocument/didClose", bind(&LanguageServer::handleTextDocumentDidClose, this, _1, _2)}, - {"workspace/didChangeConfiguration", bind(&LanguageServer::handleWorkspaceDidChangeConfiguration, this, _1, _2)}, + {"textDocument/didOpen", bind(&LanguageServer::handleTextDocumentDidOpen, this, _2)}, + {"textDocument/didChange", bind(&LanguageServer::handleTextDocumentDidChange, this, _2)}, + {"textDocument/didClose", bind(&LanguageServer::handleTextDocumentDidClose, this, _2)}, + {"workspace/didChangeConfiguration", bind(&LanguageServer::handleWorkspaceDidChangeConfiguration, this, _2)}, }, m_fileRepository("/" /* basePath */), m_compilerStack{m_fileRepository.reader()} @@ -260,6 +261,10 @@ bool LanguageServer::run() else m_client.error({}, ErrorCode::ParseError, "\"method\" has to be a string."); } + catch (RequestError const& error) + { + m_client.error(id, error.code(), error.comment() ? *error.comment() : ""s); + } catch (...) { m_client.error(id, ErrorCode::InternalError, "Unhandled exception: "s + boost::current_exception_diagnostic_information()); @@ -268,24 +273,23 @@ bool LanguageServer::run() return m_state == State::ExitRequested; } -bool LanguageServer::checkServerInitialized(MessageID _id) +void LanguageServer::requireServerInitialized() { if (m_state != State::Initialized) - { - m_client.error(_id, ErrorCode::ServerNotInitialized, "Server is not properly initialized."); - return false; - } - else - return true; + BOOST_THROW_EXCEPTION( + RequestError(ErrorCode::ServerNotInitialized) << + errinfo_comment("Server is not properly initialized.") + ); } void LanguageServer::handleInitialize(MessageID _id, Json::Value const& _args) { if (m_state != State::Started) - { - m_client.error(_id, ErrorCode::RequestFailed, "Initialize called at the wrong time."); - return; - } + BOOST_THROW_EXCEPTION( + RequestError(ErrorCode::RequestFailed) << + errinfo_comment("Initialize called at the wrong time.") + ); + m_state = State::Initialized; // The default of FileReader is to use `.`, but the path from where the LSP was started @@ -295,10 +299,11 @@ void LanguageServer::handleInitialize(MessageID _id, Json::Value const& _args) { rootPath = uri.asString(); if (!boost::starts_with(rootPath, "file://")) - { - m_client.error(_id, ErrorCode::InvalidParams, "rootUri only supports file URI scheme."); - return; - } + BOOST_THROW_EXCEPTION( + RequestError(ErrorCode::InvalidParams) << + errinfo_comment("rootUri only supports file URI scheme.") + ); + rootPath = rootPath.substr(7); } else if (Json::Value rootPath = _args["rootPath"]) @@ -317,23 +322,23 @@ void LanguageServer::handleInitialize(MessageID _id, Json::Value const& _args) m_client.reply(_id, move(replyArgs)); } - -void LanguageServer::handleWorkspaceDidChangeConfiguration(MessageID _id, Json::Value const& _args) +void LanguageServer::handleWorkspaceDidChangeConfiguration(Json::Value const& _args) { - if (!checkServerInitialized(_id)) - return; + requireServerInitialized(); if (_args["settings"].isObject()) changeConfiguration(_args["settings"]); } -void LanguageServer::handleTextDocumentDidOpen(MessageID _id, Json::Value const& _args) +void LanguageServer::handleTextDocumentDidOpen(Json::Value const& _args) { - if (!checkServerInitialized(_id)) - return; + requireServerInitialized(); if (!_args["textDocument"]) - m_client.error(_id, ErrorCode::RequestFailed, "Text document parameter missing."); + BOOST_THROW_EXCEPTION( + RequestError(ErrorCode::RequestFailed) << + errinfo_comment("Text document parameter missing.") + ); string text = _args["textDocument"]["text"].asString(); string uri = _args["textDocument"]["uri"].asString(); @@ -342,41 +347,37 @@ void LanguageServer::handleTextDocumentDidOpen(MessageID _id, Json::Value const& compileAndUpdateDiagnostics(); } -void LanguageServer::handleTextDocumentDidChange(MessageID _id, Json::Value const& _args) +void LanguageServer::handleTextDocumentDidChange(Json::Value const& _args) { - if (!checkServerInitialized(_id)) - return; + requireServerInitialized(); string const uri = _args["textDocument"]["uri"].asString(); for (Json::Value jsonContentChange: _args["contentChanges"]) { if (!jsonContentChange.isObject()) - { - m_client.error(_id, ErrorCode::RequestFailed, "Invalid content reference."); - return; - } + BOOST_THROW_EXCEPTION( + RequestError(ErrorCode::RequestFailed) << + errinfo_comment("Invalid content reference.") + ); string const sourceUnitName = m_fileRepository.clientPathToSourceUnitName(uri); if (!m_fileRepository.sourceUnits().count(sourceUnitName)) - { - m_client.error(_id, ErrorCode::RequestFailed, "Unknown file: " + uri); - return; - } + BOOST_THROW_EXCEPTION( + RequestError(ErrorCode::RequestFailed) << + errinfo_comment("Unknown file: " + uri) + ); string text = jsonContentChange["text"].asString(); if (jsonContentChange["range"].isObject()) // otherwise full content update { optional change = parseRange(sourceUnitName, jsonContentChange["range"]); if (!change || !change->hasText()) - { - m_client.error( - _id, - ErrorCode::RequestFailed, - "Invalid source range: " + jsonCompactPrint(jsonContentChange["range"]) + BOOST_THROW_EXCEPTION( + RequestError(ErrorCode::RequestFailed) << + errinfo_comment("Invalid source range: " + jsonCompactPrint(jsonContentChange["range"])) ); - return; - } + string buffer = m_fileRepository.sourceUnits().at(sourceUnitName); buffer.replace(static_cast(change->start), static_cast(change->end - change->start), move(text)); text = move(buffer); @@ -387,13 +388,15 @@ void LanguageServer::handleTextDocumentDidChange(MessageID _id, Json::Value cons compileAndUpdateDiagnostics(); } -void LanguageServer::handleTextDocumentDidClose(MessageID _id, Json::Value const& _args) +void LanguageServer::handleTextDocumentDidClose(Json::Value const& _args) { - if (!checkServerInitialized(_id)) - return; + requireServerInitialized(); if (!_args["textDocument"]) - m_client.error(_id, ErrorCode::RequestFailed, "Text document parameter missing."); + BOOST_THROW_EXCEPTION( + RequestError(ErrorCode::RequestFailed) << + errinfo_comment("Text document parameter missing.") + ); string uri = _args["textDocument"]["uri"].asString(); m_openFiles.erase(uri); diff --git a/libsolidity/lsp/LanguageServer.h b/libsolidity/lsp/LanguageServer.h index 802dd8198..a3ab37198 100644 --- a/libsolidity/lsp/LanguageServer.h +++ b/libsolidity/lsp/LanguageServer.h @@ -60,12 +60,12 @@ public: private: /// Checks if the server is initialized (to be used by messages that need it to be initialized). /// Reports an error and returns false if not. - bool checkServerInitialized(MessageID _id); + void requireServerInitialized(); void handleInitialize(MessageID _id, Json::Value const& _args); - void handleWorkspaceDidChangeConfiguration(MessageID _id, Json::Value const& _args); - void handleTextDocumentDidOpen(MessageID _id, Json::Value const& _args); - void handleTextDocumentDidChange(MessageID _id, Json::Value const& _args); - void handleTextDocumentDidClose(MessageID _id, Json::Value const& _args); + void handleWorkspaceDidChangeConfiguration(Json::Value const& _args); + void handleTextDocumentDidOpen(Json::Value const& _args); + void handleTextDocumentDidChange(Json::Value const& _args); + void handleTextDocumentDidClose(Json::Value const& _args); /// Invoked when the server user-supplied configuration changes (initiated by the client). void changeConfiguration(Json::Value const&); diff --git a/libsolidity/lsp/Transport.h b/libsolidity/lsp/Transport.h index c6ed8fa8a..384f1e3eb 100644 --- a/libsolidity/lsp/Transport.h +++ b/libsolidity/lsp/Transport.h @@ -17,6 +17,8 @@ // SPDX-License-Identifier: GPL-3.0 #pragma once +#include + #include #include @@ -45,6 +47,23 @@ enum class ErrorCode RequestFailed = -32803 }; +/** + * Error exception used to bail out on errors in the LSP function-call handlers. + */ +class RequestError: public util::Exception +{ +public: + explicit RequestError(ErrorCode _code): + m_code{_code} + { + } + + ErrorCode code() const noexcept { return m_code; } + +private: + ErrorCode m_code; +}; + /** * Transport layer API * From 1bd0f9570fed42e3dd1ce67c0ced0c3a1062d264 Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Wed, 5 Jan 2022 11:30:04 +0100 Subject: [PATCH 33/77] LSP: Introduces lspAssert(condition, ErrorCode, message) --- libsolidity/lsp/LanguageServer.cpp | 80 +++++++++++++++--------------- libsolidity/lsp/Transport.h | 9 ++++ 2 files changed, 49 insertions(+), 40 deletions(-) diff --git a/libsolidity/lsp/LanguageServer.cpp b/libsolidity/lsp/LanguageServer.cpp index f9f023349..fb704d819 100644 --- a/libsolidity/lsp/LanguageServer.cpp +++ b/libsolidity/lsp/LanguageServer.cpp @@ -275,20 +275,20 @@ bool LanguageServer::run() void LanguageServer::requireServerInitialized() { - if (m_state != State::Initialized) - BOOST_THROW_EXCEPTION( - RequestError(ErrorCode::ServerNotInitialized) << - errinfo_comment("Server is not properly initialized.") - ); + lspAssert( + m_state == State::Initialized, + ErrorCode::ServerNotInitialized, + "Server is not properly initialized." + ); } void LanguageServer::handleInitialize(MessageID _id, Json::Value const& _args) { - if (m_state != State::Started) - BOOST_THROW_EXCEPTION( - RequestError(ErrorCode::RequestFailed) << - errinfo_comment("Initialize called at the wrong time.") - ); + lspAssert( + m_state == State::Started, + ErrorCode::RequestFailed, + "Initialize called at the wrong time." + ); m_state = State::Initialized; @@ -298,11 +298,11 @@ void LanguageServer::handleInitialize(MessageID _id, Json::Value const& _args) if (Json::Value uri = _args["rootUri"]) { rootPath = uri.asString(); - if (!boost::starts_with(rootPath, "file://")) - BOOST_THROW_EXCEPTION( - RequestError(ErrorCode::InvalidParams) << - errinfo_comment("rootUri only supports file URI scheme.") - ); + lspAssert( + boost::starts_with(rootPath, "file://"), + ErrorCode::InvalidParams, + "rootUri only supports file URI scheme." + ); rootPath = rootPath.substr(7); } @@ -334,11 +334,11 @@ void LanguageServer::handleTextDocumentDidOpen(Json::Value const& _args) { requireServerInitialized(); - if (!_args["textDocument"]) - BOOST_THROW_EXCEPTION( - RequestError(ErrorCode::RequestFailed) << - errinfo_comment("Text document parameter missing.") - ); + lspAssert( + _args["textDocument"], + ErrorCode::RequestFailed, + "Text document parameter missing." + ); string text = _args["textDocument"]["text"].asString(); string uri = _args["textDocument"]["uri"].asString(); @@ -355,28 +355,28 @@ void LanguageServer::handleTextDocumentDidChange(Json::Value const& _args) for (Json::Value jsonContentChange: _args["contentChanges"]) { - if (!jsonContentChange.isObject()) - BOOST_THROW_EXCEPTION( - RequestError(ErrorCode::RequestFailed) << - errinfo_comment("Invalid content reference.") - ); + lspAssert( + jsonContentChange.isObject(), + ErrorCode::RequestFailed, + "Invalid content reference." + ); string const sourceUnitName = m_fileRepository.clientPathToSourceUnitName(uri); - if (!m_fileRepository.sourceUnits().count(sourceUnitName)) - BOOST_THROW_EXCEPTION( - RequestError(ErrorCode::RequestFailed) << - errinfo_comment("Unknown file: " + uri) - ); + lspAssert( + m_fileRepository.sourceUnits().count(sourceUnitName), + ErrorCode::RequestFailed, + "Unknown file: " + uri + ); string text = jsonContentChange["text"].asString(); if (jsonContentChange["range"].isObject()) // otherwise full content update { optional change = parseRange(sourceUnitName, jsonContentChange["range"]); - if (!change || !change->hasText()) - BOOST_THROW_EXCEPTION( - RequestError(ErrorCode::RequestFailed) << - errinfo_comment("Invalid source range: " + jsonCompactPrint(jsonContentChange["range"])) - ); + lspAssert( + change && change->hasText(), + ErrorCode::RequestFailed, + "Invalid source range: " + jsonCompactPrint(jsonContentChange["range"]) + ); string buffer = m_fileRepository.sourceUnits().at(sourceUnitName); buffer.replace(static_cast(change->start), static_cast(change->end - change->start), move(text)); @@ -392,11 +392,11 @@ void LanguageServer::handleTextDocumentDidClose(Json::Value const& _args) { requireServerInitialized(); - if (!_args["textDocument"]) - BOOST_THROW_EXCEPTION( - RequestError(ErrorCode::RequestFailed) << - errinfo_comment("Text document parameter missing.") - ); + lspAssert( + _args["textDocument"], + ErrorCode::RequestFailed, + "Text document parameter missing." + ); string uri = _args["textDocument"]["uri"].asString(); m_openFiles.erase(uri); diff --git a/libsolidity/lsp/Transport.h b/libsolidity/lsp/Transport.h index 384f1e3eb..2d0b49517 100644 --- a/libsolidity/lsp/Transport.h +++ b/libsolidity/lsp/Transport.h @@ -64,6 +64,15 @@ private: ErrorCode m_code; }; +#define lspAssert(condition, errorCode, errorMessage) \ + if (!(condition)) \ + { \ + BOOST_THROW_EXCEPTION( \ + RequestError(errorCode) << \ + errinfo_comment(errorMessage) \ + ); \ + } + /** * Transport layer API * From b1ef5de49687ec1c65c39320124e208f7d7c037c Mon Sep 17 00:00:00 2001 From: Esquith Allen <18001622+esquith@users.noreply.github.com> Date: Wed, 5 Jan 2022 21:58:41 -0500 Subject: [PATCH 34/77] fix typo --- docs/examples/micropayment.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/examples/micropayment.rst b/docs/examples/micropayment.rst index 3383e6195..c95d7c5e4 100644 --- a/docs/examples/micropayment.rst +++ b/docs/examples/micropayment.rst @@ -37,7 +37,7 @@ Alice does not need to interact with the Ethereum network to sign the transaction, the process is completely offline. In this tutorial, we will sign messages in the browser using `web3.js `_ and -`MetaMask `_, using the method described in `EIP-762 `_, +`MetaMask `_, using the method described in `EIP-712 `_, as it provides a number of other security benefits. .. code-block:: javascript From e969aed7803270f412e43107b83f5d5c97c4bb4a Mon Sep 17 00:00:00 2001 From: Marenz Date: Thu, 30 Dec 2021 18:16:29 +0100 Subject: [PATCH 35/77] Properly resolve virtual modifiers --- Changelog.md | 1 + libsolidity/analysis/ControlFlowBuilder.cpp | 33 ++++++--- libsolidity/analysis/ControlFlowBuilder.h | 8 +- libsolidity/analysis/ControlFlowGraph.cpp | 2 +- libsolidity/analysis/ControlFlowGraph.h | 4 +- .../analysis/ControlFlowRevertPruner.cpp | 74 +++++++++---------- .../modifier_declaration_fine.sol | 6 +- .../modifier_different_functions.sol | 12 +++ .../modifiers/modifier_override.sol | 17 +++++ .../storageReturn/modifier_err.sol | 8 +- .../storageReturn/modifier_fine.sol | 6 +- 11 files changed, 109 insertions(+), 62 deletions(-) create mode 100644 test/libsolidity/syntaxTests/controlFlow/modifiers/modifier_different_functions.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/modifiers/modifier_override.sol diff --git a/Changelog.md b/Changelog.md index b88e1a971..7f985b300 100644 --- a/Changelog.md +++ b/Changelog.md @@ -9,6 +9,7 @@ Compiler Features: Bugfixes: + * Control Flow Graph: Perform proper virtual lookup for modifiers for uninitialized variable and unreachable code analysis. Solc-Js: diff --git a/libsolidity/analysis/ControlFlowBuilder.cpp b/libsolidity/analysis/ControlFlowBuilder.cpp index ff8e2a29a..3de1ecca5 100644 --- a/libsolidity/analysis/ControlFlowBuilder.cpp +++ b/libsolidity/analysis/ControlFlowBuilder.cpp @@ -25,19 +25,21 @@ using namespace solidity::langutil; using namespace solidity::frontend; using namespace std; -ControlFlowBuilder::ControlFlowBuilder(CFG::NodeContainer& _nodeContainer, FunctionFlow const& _functionFlow): +ControlFlowBuilder::ControlFlowBuilder(CFG::NodeContainer& _nodeContainer, FunctionFlow const& _functionFlow, ContractDefinition const* _contract): m_nodeContainer(_nodeContainer), m_currentNode(_functionFlow.entry), m_returnNode(_functionFlow.exit), m_revertNode(_functionFlow.revert), - m_transactionReturnNode(_functionFlow.transactionReturn) + m_transactionReturnNode(_functionFlow.transactionReturn), + m_contract(_contract) { } unique_ptr ControlFlowBuilder::createFunctionFlow( CFG::NodeContainer& _nodeContainer, - FunctionDefinition const& _function + FunctionDefinition const& _function, + ContractDefinition const* _contract ) { auto functionFlow = make_unique(); @@ -45,7 +47,7 @@ unique_ptr ControlFlowBuilder::createFunctionFlow( functionFlow->exit = _nodeContainer.newNode(); functionFlow->revert = _nodeContainer.newNode(); functionFlow->transactionReturn = _nodeContainer.newNode(); - ControlFlowBuilder builder(_nodeContainer, *functionFlow); + ControlFlowBuilder builder(_nodeContainer, *functionFlow, _contract); builder.appendControlFlow(_function); return functionFlow; @@ -297,7 +299,8 @@ bool ControlFlowBuilder::visit(FunctionCall const& _functionCall) _functionCall.expression().accept(*this); ASTNode::listAccept(_functionCall.arguments(), *this); - m_currentNode->functionCalls.emplace_back(&_functionCall); + solAssert(!m_currentNode->functionCall); + m_currentNode->functionCall = &_functionCall; auto nextNode = newLabel(); @@ -321,8 +324,20 @@ bool ControlFlowBuilder::visit(ModifierInvocation const& _modifierInvocation) auto modifierDefinition = dynamic_cast( _modifierInvocation.name().annotation().referencedDeclaration ); - if (!modifierDefinition) return false; - if (!modifierDefinition->isImplemented()) return false; + + if (!modifierDefinition) + return false; + + VirtualLookup const& requiredLookup = *_modifierInvocation.name().annotation().requiredLookup; + + if (requiredLookup == VirtualLookup::Virtual) + modifierDefinition = &modifierDefinition->resolveVirtual(*m_contract); + else + solAssert(requiredLookup == VirtualLookup::Static); + + if (!modifierDefinition->isImplemented()) + return false; + solAssert(!!m_returnNode, ""); m_placeholderEntry = newLabel(); @@ -355,8 +370,8 @@ bool ControlFlowBuilder::visit(FunctionDefinition const& _functionDefinition) } - for (auto const& modifier: _functionDefinition.modifiers()) - appendControlFlow(*modifier); + for (auto const& modifierInvocation: _functionDefinition.modifiers()) + appendControlFlow(*modifierInvocation); appendControlFlow(_functionDefinition.body()); diff --git a/libsolidity/analysis/ControlFlowBuilder.h b/libsolidity/analysis/ControlFlowBuilder.h index 9cab99dd4..a150262f1 100644 --- a/libsolidity/analysis/ControlFlowBuilder.h +++ b/libsolidity/analysis/ControlFlowBuilder.h @@ -37,13 +37,15 @@ class ControlFlowBuilder: private ASTConstVisitor, private yul::ASTWalker public: static std::unique_ptr createFunctionFlow( CFG::NodeContainer& _nodeContainer, - FunctionDefinition const& _function + FunctionDefinition const& _function, + ContractDefinition const* _contract = nullptr ); private: explicit ControlFlowBuilder( CFG::NodeContainer& _nodeContainer, - FunctionFlow const& _functionFlow + FunctionFlow const& _functionFlow, + ContractDefinition const* _contract = nullptr ); // Visits for constructing the control flow. @@ -158,6 +160,8 @@ private: CFGNode* m_revertNode = nullptr; CFGNode* m_transactionReturnNode = nullptr; + ContractDefinition const* m_contract = nullptr; + /// The current jump destination of break Statements. CFGNode* m_breakJump = nullptr; /// The current jump destination of continue Statements. diff --git a/libsolidity/analysis/ControlFlowGraph.cpp b/libsolidity/analysis/ControlFlowGraph.cpp index f4afe0149..ca36b421c 100644 --- a/libsolidity/analysis/ControlFlowGraph.cpp +++ b/libsolidity/analysis/ControlFlowGraph.cpp @@ -44,7 +44,7 @@ bool CFG::visit(ContractDefinition const& _contract) for (FunctionDefinition const* function: contract->definedFunctions()) if (function->isImplemented()) m_functionControlFlow[{&_contract, function}] = - ControlFlowBuilder::createFunctionFlow(m_nodeContainer, *function); + ControlFlowBuilder::createFunctionFlow(m_nodeContainer, *function, &_contract); return true; } diff --git a/libsolidity/analysis/ControlFlowGraph.h b/libsolidity/analysis/ControlFlowGraph.h index 732548664..7383783fd 100644 --- a/libsolidity/analysis/ControlFlowGraph.h +++ b/libsolidity/analysis/ControlFlowGraph.h @@ -98,8 +98,8 @@ struct CFGNode std::vector entries; /// Exit nodes. All CFG nodes to which control flow may continue after this node. std::vector exits; - /// Function calls done by this node - std::vector functionCalls; + /// Function call done by this node + FunctionCall const* functionCall = nullptr; /// Variable occurrences in the node. std::vector variableOccurrences; diff --git a/libsolidity/analysis/ControlFlowRevertPruner.cpp b/libsolidity/analysis/ControlFlowRevertPruner.cpp index 6a8018355..9a44be57a 100644 --- a/libsolidity/analysis/ControlFlowRevertPruner.cpp +++ b/libsolidity/analysis/ControlFlowRevertPruner.cpp @@ -81,27 +81,27 @@ void ControlFlowRevertPruner::findRevertStates() if (_node == functionFlow.exit) foundExit = true; - for (auto const* functionCall: _node->functionCalls) + if (auto const* functionCall = _node->functionCall) { auto const* resolvedFunction = ASTNode::resolveFunctionCall(*functionCall, item.contract); - if (resolvedFunction == nullptr || !resolvedFunction->isImplemented()) - continue; - - CFG::FunctionContractTuple calledFunctionTuple{ - findScopeContract(*resolvedFunction, item.contract), - resolvedFunction - }; - switch (m_functions.at(calledFunctionTuple)) + if (resolvedFunction && resolvedFunction->isImplemented()) { - case RevertState::Unknown: - wakeUp[calledFunctionTuple].insert(item); - foundUnknown = true; - return; - case RevertState::AllPathsRevert: - return; - case RevertState::HasNonRevertingPath: - break; + CFG::FunctionContractTuple calledFunctionTuple{ + findScopeContract(*resolvedFunction, item.contract), + resolvedFunction + }; + switch (m_functions.at(calledFunctionTuple)) + { + case RevertState::Unknown: + wakeUp[calledFunctionTuple].insert(item); + foundUnknown = true; + return; + case RevertState::AllPathsRevert: + return; + case RevertState::HasNonRevertingPath: + break; + } } } @@ -135,31 +135,29 @@ void ControlFlowRevertPruner::modifyFunctionFlows() FunctionFlow const& functionFlow = m_cfg.functionFlow(*item.first.function, item.first.contract); solidity::util::BreadthFirstSearch{{functionFlow.entry}}.run( [&](CFGNode* _node, auto&& _addChild) { - for (auto const* functionCall: _node->functionCalls) + if (auto const* functionCall = _node->functionCall) { auto const* resolvedFunction = ASTNode::resolveFunctionCall(*functionCall, item.first.contract); - if (resolvedFunction == nullptr || !resolvedFunction->isImplemented()) - continue; + if (resolvedFunction && resolvedFunction->isImplemented()) + switch (m_functions.at({findScopeContract(*resolvedFunction, item.first.contract), resolvedFunction})) + { + case RevertState::Unknown: + [[fallthrough]]; + case RevertState::AllPathsRevert: + // If the revert states of the functions do not + // change anymore, we treat all "unknown" states as + // "reverting", since they can only be caused by + // recursion. + for (CFGNode * node: _node->exits) + ranges::remove(node->entries, _node); - switch (m_functions.at({findScopeContract(*resolvedFunction, item.first.contract), resolvedFunction})) - { - case RevertState::Unknown: - [[fallthrough]]; - case RevertState::AllPathsRevert: - // If the revert states of the functions do not - // change anymore, we treat all "unknown" states as - // "reverting", since they can only be caused by - // recursion. - for (CFGNode * node: _node->exits) - ranges::remove(node->entries, _node); - - _node->exits = {functionFlow.revert}; - functionFlow.revert->entries.push_back(_node); - return; - default: - break; - } + _node->exits = {functionFlow.revert}; + functionFlow.revert->entries.push_back(_node); + return; + default: + break; + } } for (CFGNode* exit: _node->exits) diff --git a/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/modifier_declaration_fine.sol b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/modifier_declaration_fine.sol index 6df4939cf..260ae6b94 100644 --- a/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/modifier_declaration_fine.sol +++ b/test/libsolidity/syntaxTests/controlFlow/localStorageVariables/modifier_declaration_fine.sol @@ -1,5 +1,5 @@ contract C { - modifier revertIfNoReturn() { + modifier alwaysRevert() { _; revert(); } @@ -9,10 +9,10 @@ contract C { } struct S { uint a; } S s; - function f(bool flag) revertIfNoReturn() internal view { + function f(bool flag) alwaysRevert() internal view { if (flag) s; } - function g(bool flag) revertIfNoReturn() ifFlag(flag) internal view { + function g(bool flag) alwaysRevert() ifFlag(flag) internal view { s; } diff --git a/test/libsolidity/syntaxTests/controlFlow/modifiers/modifier_different_functions.sol b/test/libsolidity/syntaxTests/controlFlow/modifiers/modifier_different_functions.sol new file mode 100644 index 000000000..63d915369 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/modifiers/modifier_different_functions.sol @@ -0,0 +1,12 @@ +contract A { + function f() mod internal returns (uint[] storage) { + revert(); + } + function g() mod internal returns (uint[] storage) { + } + modifier mod() virtual { + _; + } +} +// ---- +// TypeError 3464: (118-132): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/controlFlow/modifiers/modifier_override.sol b/test/libsolidity/syntaxTests/controlFlow/modifiers/modifier_override.sol new file mode 100644 index 000000000..3c5eb80ee --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/modifiers/modifier_override.sol @@ -0,0 +1,17 @@ +contract A { + function f() mod internal returns (uint[] storage) { + } + modifier mod() virtual { + revert(); + _; + } +} +contract B is A { + modifier mod() override { _; } + function g() public { + f()[0] = 42; + } +} +// ---- +// Warning 5740: (65-69): Unreachable code. +// TypeError 3464: (49-63): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_err.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_err.sol index bf896b86a..5dee487d1 100644 --- a/test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_err.sol +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_err.sol @@ -1,5 +1,5 @@ contract C { - modifier revertIfNoReturn() { + modifier callAndRevert() { _; revert(); } @@ -13,10 +13,10 @@ contract C { return s; } - function g(bool flag) ifFlag(flag) revertIfNoReturn() internal view returns(S storage) { + function g(bool flag) ifFlag(flag) callAndRevert() internal view returns(S storage) { return s; } } // ---- -// TypeError 3464: (249-258): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour. -// TypeError 3464: (367-376): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour. +// TypeError 3464: (246-255): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour. +// TypeError 3464: (361-370): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_fine.sol b/test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_fine.sol index ee37f6d64..7b7b3ba0c 100644 --- a/test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_fine.sol +++ b/test/libsolidity/syntaxTests/controlFlow/storageReturn/modifier_fine.sol @@ -1,5 +1,5 @@ contract C { - modifier revertIfNoReturn() { + modifier callAndRevert() { _; revert(); } @@ -9,10 +9,10 @@ contract C { } struct S { uint a; } S s; - function f(bool flag) revertIfNoReturn() internal view returns(S storage) { + function f(bool flag) callAndRevert() internal view returns(S storage) { if (flag) return s; } - function g(bool flag) revertIfNoReturn() ifFlag(flag) internal view returns(S storage) { + function g(bool flag) callAndRevert() ifFlag(flag) internal view returns(S storage) { return s; } From 2c7aed1d7e584044748eebee573f75576e52f638 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Thu, 6 Jan 2022 14:16:02 +0100 Subject: [PATCH 36/77] Add FunctionHoister as a pre-requisite for equal store eliminator. --- test/libyul/YulOptimizerTestCommon.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/libyul/YulOptimizerTestCommon.cpp b/test/libyul/YulOptimizerTestCommon.cpp index bb8458d78..e7711f586 100644 --- a/test/libyul/YulOptimizerTestCommon.cpp +++ b/test/libyul/YulOptimizerTestCommon.cpp @@ -239,6 +239,7 @@ YulOptimizerTestCommon::YulOptimizerTestCommon( }}, {"equalStoreEliminator", [&]() { disambiguate(); + FunctionHoister::run(*m_context, *m_ast); ForLoopInitRewriter::run(*m_context, *m_ast); EqualStoreEliminator::run(*m_context, *m_ast); }}, From 4c20821e6d3f343fe19245fc01bb0c4fb9b3dbc5 Mon Sep 17 00:00:00 2001 From: Mohamed Safouen Bouabid Date: Fri, 7 Jan 2022 16:01:13 +0100 Subject: [PATCH 37/77] Explaining payable(msg.sender) At this point of the documentation a new Solidity learner will not understand this line without further explanation: if (!payable(msg.sender).send(amount)) { It should explain how msg.sender is of type "address" and not "address payable" so it cannot send or receive Ether. Therefore it must be explicitly converted to payable. --- docs/examples/blind-auction.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/examples/blind-auction.rst b/docs/examples/blind-auction.rst index ad898a9b1..b0a86f248 100644 --- a/docs/examples/blind-auction.rst +++ b/docs/examples/blind-auction.rst @@ -121,6 +121,9 @@ to receive their money - contracts cannot activate themselves. // before `send` returns. pendingReturns[msg.sender] = 0; + // msg.sender is not of type `address payable` and must be + // explicitly converted using `payable(msg.sender)` in order + // use the member function `send()`. if (!payable(msg.sender).send(amount)) { // No need to call throw here, just reset the amount owing pendingReturns[msg.sender] = amount; From 790e7f42a1750b6a8f98079e1671a3cb579e8bf9 Mon Sep 17 00:00:00 2001 From: Brien <58648726+brien-tech@users.noreply.github.com> Date: Mon, 10 Jan 2022 02:29:51 -0500 Subject: [PATCH 38/77] Fixing typo in "smart contracts" --- docs/layout-of-source-files.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/layout-of-source-files.rst b/docs/layout-of-source-files.rst index cd031bb01..b3a27bf1e 100644 --- a/docs/layout-of-source-files.rst +++ b/docs/layout-of-source-files.rst @@ -13,7 +13,7 @@ and :ref:`constant variable` definitions. SPDX License Identifier ======================= -Trust in smart contract can be better established if their source code +Trust in smart contracts can be better established if their source code is available. Since making source code available always touches on legal problems with regards to copyright, the Solidity compiler encourages the use of machine-readable `SPDX license identifiers `_. From 19b1a13c6d2bc80ccc4174691c84f18bb4891f3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 26 Oct 2021 11:12:45 +0200 Subject: [PATCH 39/77] externalTests: Add support for hardhat.config.ts --- test/externalTests/common.sh | 43 +++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/test/externalTests/common.sh b/test/externalTests/common.sh index d394a0b5f..a0bf17bda 100644 --- a/test/externalTests/common.sh +++ b/test/externalTests/common.sh @@ -189,14 +189,17 @@ function force_hardhat_compiler_binary echo "Config file: ${config_file}" echo "Binary type: ${binary_type}" echo "Compiler path: ${solc_path}" - hardhat_solc_build_subtask "$SOLCVERSION_SHORT" "$SOLCVERSION" "$binary_type" "$solc_path" >> "$config_file" + + local language="${config_file##*.}" + hardhat_solc_build_subtask "$SOLCVERSION_SHORT" "$SOLCVERSION" "$binary_type" "$solc_path" "$language" >> "$config_file" } function force_hardhat_compiler_settings { local config_file="$1" local preset="$2" - local evm_version="${3:-"$CURRENT_EVM_VERSION"}" + local config_var_name="$3" + local evm_version="${4:-"$CURRENT_EVM_VERSION"}" printLog "Configuring Hardhat..." echo "-------------------------------------" @@ -208,10 +211,16 @@ function force_hardhat_compiler_settings echo "Compiler version (full): ${SOLCVERSION}" echo "-------------------------------------" - { - echo -n 'module.exports["solidity"] = ' - hardhat_compiler_settings "$SOLCVERSION_SHORT" "$preset" "$evm_version" - } >> "$config_file" + local settings + settings=$(hardhat_compiler_settings "$SOLCVERSION_SHORT" "$preset" "$evm_version") + if [[ $config_file == *\.js ]]; then + [[ $config_var_name == "" ]] || assertFail + echo "module.exports['solidity'] = ${settings}" >> "$config_file" + else + [[ $config_file == *\.ts ]] || assertFail + [[ $config_var_name != "" ]] || assertFail + echo "${config_var_name}.solidity = {compilers: [${settings}]}" >> "$config_file" + fi } function truffle_verify_compiler_version @@ -309,16 +318,27 @@ function hardhat_solc_build_subtask { local full_solc_version="$2" local binary_type="$3" local solc_path="$4" + local language="$5" [[ $binary_type == native || $binary_type == solcjs ]] || assertFail [[ $binary_type == native ]] && local is_solcjs=false [[ $binary_type == solcjs ]] && local is_solcjs=true - echo "const {TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD} = require('hardhat/builtin-tasks/task-names');" - echo "const assert = require('assert');" - echo - echo "subtask(TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD, async (args, hre, runSuper) => {" + if [[ $language == js ]]; then + echo "const {TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD} = require('hardhat/builtin-tasks/task-names');" + echo "const assert = require('assert');" + echo + echo "subtask(TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD, async (args, hre, runSuper) => {" + else + [[ $language == ts ]] || assertFail + echo "import {TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD} from 'hardhat/builtin-tasks/task-names';" + echo "import assert = require('assert');" + echo "import {subtask} from 'hardhat/config';" + echo + echo "subtask(TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD, async (args: any, _hre: any, _runSuper: any) => {" + fi + echo " assert(args.solcVersion == '${solc_version}', 'Unexpected solc version: ' + args.solcVersion)" echo " return {" echo " compilerPath: '$(realpath "$solc_path")'," @@ -384,9 +404,10 @@ function hardhat_run_test local compile_only_presets="$3" local compile_fn="$4" local test_fn="$5" + local config_var_name="$6" hardhat_clean - force_hardhat_compiler_settings "$config_file" "$preset" + force_hardhat_compiler_settings "$config_file" "$preset" "$config_var_name" compile_and_run_test compile_fn test_fn hardhat_verify_compiler_version "$preset" "$compile_only_presets" } From 6980fa32e2c67d18dcf4115f36e225db96a08138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 6 Dec 2021 16:34:36 +0100 Subject: [PATCH 40/77] External test for sushiswap/trident --- .circleci/config.yml | 7 +++ test/externalTests.sh | 1 + test/externalTests/trident.sh | 90 +++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100755 test/externalTests/trident.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 6edfc2d3a..02f91de83 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1371,6 +1371,13 @@ workflows: binary_type: native # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" nodejs_version: '16' + - t_ems_ext: + <<: *workflow_ubuntu2004_static + name: t_native_test_ext_trident + project: trident + binary_type: native + # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" + nodejs_version: '16' # Windows build and tests - b_win: *workflow_trigger_on_tags diff --git a/test/externalTests.sh b/test/externalTests.sh index 86f13401e..846cdf515 100755 --- a/test/externalTests.sh +++ b/test/externalTests.sh @@ -42,3 +42,4 @@ printTask "Running external tests..." "$REPO_ROOT/externalTests/gnosis-v2.sh" "$@" "$REPO_ROOT/externalTests/colony.sh" "$@" "$REPO_ROOT/externalTests/ens.sh" "$@" +"$REPO_ROOT/externalTests/trident.sh" "$@" diff --git a/test/externalTests/trident.sh b/test/externalTests/trident.sh new file mode 100755 index 000000000..379af8cc1 --- /dev/null +++ b/test/externalTests/trident.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash + +# ------------------------------------------------------------------------------ +# This file is part of solidity. +# +# solidity is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# solidity is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with solidity. If not, see +# +# (c) 2021 solidity contributors. +#------------------------------------------------------------------------------ + +set -e + +source scripts/common.sh +source test/externalTests/common.sh + +verify_input "$@" +BINARY_TYPE="$1" +BINARY_PATH="$2" + +function compile_fn { yarn build; } + +function test_fn { + # shellcheck disable=SC2046 + TS_NODE_TRANSPILE_ONLY=1 npx hardhat test --no-compile $( + # TODO: We need to skip Migration.test.ts because it fails and makes other tests fail too. + # Replace this with `yarn test` once https://github.com/sushiswap/trident/issues/283 is fixed. + find test/ -name "*.test.ts" ! -path "test/Migration.test.ts" + ) +} + +function trident_test +{ + # TODO: Switch to https://github.com/sushiswap/trident / master once + # https://github.com/sushiswap/trident/pull/282 gets merged. + local repo="https://github.com/solidity-external-tests/trident.git" + local branch=master_080 + local config_file="hardhat.config.ts" + local config_var=config + + local compile_only_presets=() + local settings_presets=( + "${compile_only_presets[@]}" + #ir-no-optimize # Compilation fails with: "YulException: Variable var_amount_165 is 9 slot(s) too deep inside the stack." + #ir-optimize-evm-only # Compilation fails with: "YulException: Variable var_amount_165 is 9 slot(s) too deep inside the stack." + #ir-optimize-evm+yul # Compilation fails with: "YulException: Cannot swap Variable var_nearestTick with Variable _4: too deep in the stack by 4 slots" + legacy-no-optimize + legacy-optimize-evm-only + legacy-optimize-evm+yul + ) + + local selected_optimizer_presets + selected_optimizer_presets=$(circleci_select_steps_multiarg "${settings_presets[@]}") + print_optimizer_presets_or_exit "$selected_optimizer_presets" + + setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" + download_project "$repo" "$branch" "$DIR" + + # TODO: Currently tests work only with the exact versions from yarn.lock. + # Re-enable this when https://github.com/sushiswap/trident/issues/284 is fixed. + #neutralize_package_lock + + neutralize_package_json_hooks + force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" + force_hardhat_compiler_settings "$config_file" "$(first_word "$selected_optimizer_presets")" "$config_var" + yarn install + + replace_version_pragmas + force_solc_modules "${DIR}/solc" + + # @sushiswap/core package contains contracts that get built with 0.6.12 and fail our compiler + # version check. It's not used by tests so we can remove it. + rm -r node_modules/@sushiswap/core/ + + for preset in $selected_optimizer_presets; do + hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var" + done +} + +external_test Trident trident_test From 2d038cddffc130c44f18d6e3af1e235ac596c329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 9 Dec 2021 13:22:17 +0100 Subject: [PATCH 41/77] trident ext test: Patch upstream instread of relying on our fork --- test/externalTests/trident.sh | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/test/externalTests/trident.sh b/test/externalTests/trident.sh index 379af8cc1..312930293 100755 --- a/test/externalTests/trident.sh +++ b/test/externalTests/trident.sh @@ -41,10 +41,8 @@ function test_fn { function trident_test { - # TODO: Switch to https://github.com/sushiswap/trident / master once - # https://github.com/sushiswap/trident/pull/282 gets merged. - local repo="https://github.com/solidity-external-tests/trident.git" - local branch=master_080 + local repo="https://github.com/sushiswap/trident" + local branch=master local config_file="hardhat.config.ts" local config_var=config @@ -78,6 +76,14 @@ function trident_test replace_version_pragmas force_solc_modules "${DIR}/solc" + # BentoBoxV1Flat.sol requires a few small tweaks to compile on 0.8.x. + # TODO: Remove once https://github.com/sushiswap/trident/pull/282 gets merged. + sed -i 's|uint128(-1)|type(uint128).max|g' contracts/flat/BentoBoxV1Flat.sol + sed -i 's|uint64(-1)|type(uint64).max|g' contracts/flat/BentoBoxV1Flat.sol + sed -i 's|uint32(-1)|type(uint32).max|g' contracts/flat/BentoBoxV1Flat.sol + sed -i 's|IERC20(0)|IERC20(address(0))|g' contracts/flat/BentoBoxV1Flat.sol + sed -i 's|IStrategy(0)|IStrategy(address(0))|g' contracts/flat/BentoBoxV1Flat.sol + # @sushiswap/core package contains contracts that get built with 0.6.12 and fail our compiler # version check. It's not used by tests so we can remove it. rm -r node_modules/@sushiswap/core/ From 1928b7843bc6f76904231f8f2c7858e4d574167f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 17 Dec 2021 16:01:19 +0100 Subject: [PATCH 42/77] externalTests: Preset selection via command-line arguments --- test/externalTests/colony.sh | 10 +++++----- test/externalTests/common.sh | 27 +++++++++++++++++++++++++-- test/externalTests/ens.sh | 10 +++++----- test/externalTests/gnosis-v2.sh | 10 +++++----- test/externalTests/gnosis.sh | 10 +++++----- test/externalTests/zeppelin.sh | 10 +++++----- 6 files changed, 50 insertions(+), 27 deletions(-) diff --git a/test/externalTests/colony.sh b/test/externalTests/colony.sh index 9bebc2722..d3664bb1e 100755 --- a/test/externalTests/colony.sh +++ b/test/externalTests/colony.sh @@ -27,6 +27,7 @@ source test/externalTests/common.sh verify_input "$@" BINARY_TYPE="$1" BINARY_PATH="$2" +SELECTED_PRESETS="$3" function compile_fn { yarn run provision:token:contracts; } function test_fn { yarn run test:contracts; } @@ -49,16 +50,15 @@ function colony_test legacy-optimize-evm+yul ) - local selected_optimizer_presets - selected_optimizer_presets=$(circleci_select_steps_multiarg "${settings_presets[@]}") - print_optimizer_presets_or_exit "$selected_optimizer_presets" + [[ $SELECTED_PRESETS != "" ]] || SELECTED_PRESETS=$(circleci_select_steps_multiarg "${settings_presets[@]}") + print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" download_project "$repo" "$branch" "$DIR" [[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH" neutralize_package_json_hooks - force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$(first_word "$selected_optimizer_presets")" + force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$(first_word "$SELECTED_PRESETS")" yarn install git submodule update --init @@ -70,7 +70,7 @@ function colony_test replace_version_pragmas [[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc" - for preset in $selected_optimizer_presets; do + for preset in $SELECTED_PRESETS; do truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$preset" "${compile_only_presets[*]}" compile_fn test_fn done } diff --git a/test/externalTests/common.sh b/test/externalTests/common.sh index d394a0b5f..ae194062b 100644 --- a/test/externalTests/common.sh +++ b/test/externalTests/common.sh @@ -24,7 +24,16 @@ set -e CURRENT_EVM_VERSION=london -function print_optimizer_presets_or_exit +AVAILABLE_PRESETS=( + legacy-no-optimize + ir-no-optimize + legacy-optimize-evm-only + ir-optimize-evm-only + legacy-optimize-evm+yul + ir-optimize-evm+yul +) + +function print_presets_or_exit { local selected_presets="$1" @@ -37,10 +46,22 @@ function verify_input { local binary_type="$1" local binary_path="$2" + local selected_presets="$3" - (( $# == 2 )) || fail "Usage: $0 native|solcjs " + (( $# >= 2 && $# <= 3 )) || fail "Usage: $0 native|solcjs [preset]" [[ $binary_type == native || $binary_type == solcjs ]] || fail "Invalid binary type: '${binary_type}'. Must be either 'native' or 'solcjs'." [[ -f "$binary_path" ]] || fail "The compiler binary does not exist at '${binary_path}'" + + if [[ $selected_presets != "" ]] + then + for preset in $selected_presets + do + if [[ " ${AVAILABLE_PRESETS[*]} " != *" $preset "* ]] + then + fail "Preset '${preset}' does not exist. Available presets: ${AVAILABLE_PRESETS[*]}." + fi + done + fi } function setup_solc @@ -266,6 +287,8 @@ function settings_from_preset local preset="$1" local evm_version="$2" + [[ " ${AVAILABLE_PRESETS[*]} " == *" $preset "* ]] || assertFail + case "$preset" in # NOTE: Remember to update `parallelism` of `t_ems_ext` job in CI config if you add/remove presets legacy-no-optimize) echo "{evmVersion: '${evm_version}', viaIR: false, optimizer: {enabled: false}}" ;; diff --git a/test/externalTests/ens.sh b/test/externalTests/ens.sh index 2b663cf84..858ce42fc 100755 --- a/test/externalTests/ens.sh +++ b/test/externalTests/ens.sh @@ -27,6 +27,7 @@ source test/externalTests/common.sh verify_input "$@" BINARY_TYPE="$1" BINARY_PATH="$2" +SELECTED_PRESETS="$3" function compile_fn { yarn build; } function test_fn { yarn test; } @@ -49,9 +50,8 @@ function ens_test legacy-optimize-evm+yul ) - local selected_optimizer_presets - selected_optimizer_presets=$(circleci_select_steps_multiarg "${settings_presets[@]}") - print_optimizer_presets_or_exit "$selected_optimizer_presets" + [[ $SELECTED_PRESETS != "" ]] || SELECTED_PRESETS=$(circleci_select_steps_multiarg "${settings_presets[@]}") + print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" download_project "$repo" "$branch" "$DIR" @@ -60,13 +60,13 @@ function ens_test neutralize_package_lock neutralize_package_json_hooks force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" - force_hardhat_compiler_settings "$config_file" "$(first_word "$selected_optimizer_presets")" + force_hardhat_compiler_settings "$config_file" "$(first_word "$SELECTED_PRESETS")" yarn install replace_version_pragmas neutralize_packaged_contracts - for preset in $selected_optimizer_presets; do + for preset in $SELECTED_PRESETS; do hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn done } diff --git a/test/externalTests/gnosis-v2.sh b/test/externalTests/gnosis-v2.sh index f963c74a0..b051d8b4e 100755 --- a/test/externalTests/gnosis-v2.sh +++ b/test/externalTests/gnosis-v2.sh @@ -27,6 +27,7 @@ source test/externalTests/common.sh verify_input "$@" BINARY_TYPE="$1" BINARY_PATH="$2" +SELECTED_PRESETS="$3" function compile_fn { npx truffle compile; } function test_fn { npm test; } @@ -49,9 +50,8 @@ function gnosis_safe_test legacy-optimize-evm+yul ) - local selected_optimizer_presets - selected_optimizer_presets=$(circleci_select_steps_multiarg "${settings_presets[@]}") - print_optimizer_presets_or_exit "$selected_optimizer_presets" + [[ $SELECTED_PRESETS != "" ]] || SELECTED_PRESETS=$(circleci_select_steps_multiarg "${settings_presets[@]}") + print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" download_project "$repo" "$branch" "$DIR" @@ -62,13 +62,13 @@ function gnosis_safe_test neutralize_package_lock neutralize_package_json_hooks - force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$(first_word "$selected_optimizer_presets")" + force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$(first_word "$SELECTED_PRESETS")" npm install --package-lock replace_version_pragmas [[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc" - for preset in $selected_optimizer_presets; do + for preset in $SELECTED_PRESETS; do truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$preset" "${compile_only_presets[*]}" compile_fn test_fn done } diff --git a/test/externalTests/gnosis.sh b/test/externalTests/gnosis.sh index 7d8bc2442..cb07458c9 100755 --- a/test/externalTests/gnosis.sh +++ b/test/externalTests/gnosis.sh @@ -27,6 +27,7 @@ source test/externalTests/common.sh verify_input "$@" BINARY_TYPE="$1" BINARY_PATH="$2" +SELECTED_PRESETS="$3" function compile_fn { npx truffle compile; } function test_fn { npm test; } @@ -48,9 +49,8 @@ function gnosis_safe_test legacy-optimize-evm+yul ) - local selected_optimizer_presets - selected_optimizer_presets=$(circleci_select_steps_multiarg "${settings_presets[@]}") - print_optimizer_presets_or_exit "$selected_optimizer_presets" + [[ $SELECTED_PRESETS != "" ]] || SELECTED_PRESETS=$(circleci_select_steps_multiarg "${settings_presets[@]}") + print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" download_project "$repo" "$branch" "$DIR" @@ -60,13 +60,13 @@ function gnosis_safe_test neutralize_package_lock neutralize_package_json_hooks - force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$(first_word "$selected_optimizer_presets")" + force_truffle_compiler_settings "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$(first_word "$SELECTED_PRESETS")" npm install --package-lock replace_version_pragmas [[ $BINARY_TYPE == solcjs ]] && force_solc_modules "${DIR}/solc" - for preset in $selected_optimizer_presets; do + for preset in $SELECTED_PRESETS; do truffle_run_test "$config_file" "$BINARY_TYPE" "${DIR}/solc" "$preset" "${compile_only_presets[*]}" compile_fn test_fn done } diff --git a/test/externalTests/zeppelin.sh b/test/externalTests/zeppelin.sh index 9865c7e40..3844a2cba 100755 --- a/test/externalTests/zeppelin.sh +++ b/test/externalTests/zeppelin.sh @@ -27,6 +27,7 @@ source test/externalTests/common.sh verify_input "$@" BINARY_TYPE="$1" BINARY_PATH="$2" +SELECTED_PRESETS="$3" function compile_fn { npm run compile; } function test_fn { npm test; } @@ -49,21 +50,20 @@ function zeppelin_test legacy-optimize-evm+yul ) - local selected_optimizer_presets - selected_optimizer_presets=$(circleci_select_steps_multiarg "${settings_presets[@]}") - print_optimizer_presets_or_exit "$selected_optimizer_presets" + [[ $SELECTED_PRESETS != "" ]] || SELECTED_PRESETS=$(circleci_select_steps_multiarg "${settings_presets[@]}") + print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" download_project "$repo" "$branch" "$DIR" neutralize_package_json_hooks force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" - force_hardhat_compiler_settings "$config_file" "$(first_word "$selected_optimizer_presets")" + force_hardhat_compiler_settings "$config_file" "$(first_word "$SELECTED_PRESETS")" npm install replace_version_pragmas - for preset in $selected_optimizer_presets; do + for preset in $SELECTED_PRESETS; do hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn done } From 483148ddff4f3d4836f45cf5c493643bce5e8081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 10 Jan 2022 16:26:14 +0100 Subject: [PATCH 43/77] Include the parallel run number in gitter notifcations from CI --- .circleci/config.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 02f91de83..1b1fbbdb0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -53,8 +53,11 @@ commands: workflow_info=$(curl --silent "https://circleci.com/api/v2/workflow/${CIRCLE_WORKFLOW_ID}") || true workflow_name=$(echo "$workflow_info" | grep -E '"\s*name"\s*:\s*".*"' | cut -d \" -f 4 || echo "$CIRCLE_WORKFLOW_ID") - [[ "<< parameters.event >>" == "failure" ]] && message=" ❌ [${workflow_name}] Job **${CIRCLE_JOB}** failed on **${CIRCLE_BRANCH}**. Please see [build ${CIRCLE_BUILD_NUM}](${CIRCLE_BUILD_URL}) for details." - [[ "<< parameters.event >>" == "success" ]] && message=" ✅ [${workflow_name}] Job **${CIRCLE_JOB}** succeeded on **${CIRCLE_BRANCH}**. Please see [build ${CIRCLE_BUILD_NUM}](${CIRCLE_BUILD_URL}) for details." + [[ $CIRCLE_NODE_TOTAL == 1 ]] && job="**${CIRCLE_JOB}**" + [[ $CIRCLE_NODE_TOTAL != 1 ]] && job="**${CIRCLE_JOB}** (run $((CIRCLE_NODE_INDEX + 1))/${CIRCLE_NODE_TOTAL})" + + [[ "<< parameters.event >>" == "failure" ]] && message=" ❌ [${workflow_name}] Job ${job} failed on **${CIRCLE_BRANCH}**. Please see [build ${CIRCLE_BUILD_NUM}](${CIRCLE_BUILD_URL}) for details." + [[ "<< parameters.event >>" == "success" ]] && message=" ✅ [${workflow_name}] Job ${job} succeeded on **${CIRCLE_BRANCH}**. Please see [build ${CIRCLE_BUILD_NUM}](${CIRCLE_BUILD_URL}) for details." curl "https://api.gitter.im/v1/rooms/${GITTER_NOTIFY_ROOM_ID}/chatMessages" \ --request POST \ From b60b596741614263f80d71a5bfe069360cc97764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 10 Jan 2022 17:25:20 +0100 Subject: [PATCH 44/77] externalTests: Add support for cloning repos at a specific commit --- test/externalTests/colony.sh | 5 +++-- test/externalTests/common.sh | 22 +++++++++++++++++----- test/externalTests/ens.sh | 5 +++-- test/externalTests/gnosis-v2.sh | 5 +++-- test/externalTests/gnosis.sh | 5 +++-- test/externalTests/trident.sh | 5 +++-- test/externalTests/zeppelin.sh | 5 +++-- 7 files changed, 35 insertions(+), 17 deletions(-) diff --git a/test/externalTests/colony.sh b/test/externalTests/colony.sh index 9bebc2722..a63648e85 100755 --- a/test/externalTests/colony.sh +++ b/test/externalTests/colony.sh @@ -34,7 +34,8 @@ function test_fn { yarn run test:contracts; } function colony_test { local repo="https://github.com/solidity-external-tests/colonyNetwork.git" - local branch=develop_080 + local ref_type=branch + local ref="develop_080" local config_file="truffle.js" local compile_only_presets=( @@ -54,7 +55,7 @@ function colony_test print_optimizer_presets_or_exit "$selected_optimizer_presets" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$branch" "$DIR" + download_project "$repo" "$ref_type" "$ref" "$DIR" [[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH" neutralize_package_json_hooks diff --git a/test/externalTests/common.sh b/test/externalTests/common.sh index a0bf17bda..728f85fbb 100644 --- a/test/externalTests/common.sh +++ b/test/externalTests/common.sh @@ -77,12 +77,24 @@ function setup_solc function download_project { local repo="$1" - local solcjs_branch="$2" - local test_dir="$3" + local ref_type="$2" + local solcjs_ref="$3" + local test_dir="$4" - printLog "Cloning $solcjs_branch of $repo..." - git clone --depth 1 "$repo" -b "$solcjs_branch" "$test_dir/ext" - cd ext + [[ $ref_type == commit || $ref_type == branch || $ref_type == tag ]] || assertFail + + printLog "Cloning ${ref_type} ${solcjs_ref} of ${repo}..." + if [[ $ref_type == commit ]]; then + mkdir ext + cd ext + git init + git remote add origin "$repo" + git fetch --depth 1 origin "$solcjs_ref" + git reset --hard FETCH_HEAD + else + git clone --depth 1 "$repo" -b "$solcjs_ref" "$test_dir/ext" + cd ext + fi echo "Current commit hash: $(git rev-parse HEAD)" } diff --git a/test/externalTests/ens.sh b/test/externalTests/ens.sh index 2b663cf84..b19fbabe2 100755 --- a/test/externalTests/ens.sh +++ b/test/externalTests/ens.sh @@ -34,7 +34,8 @@ function test_fn { yarn test; } function ens_test { local repo="https://github.com/ensdomains/ens-contracts.git" - local branch="v0.0.8" # The project is in flux right now and master might be too unstable for us + local ref_type=tag + local ref="v0.0.8" # The project is in flux right now and master might be too unstable for us local config_file="hardhat.config.js" local compile_only_presets=( @@ -54,7 +55,7 @@ function ens_test print_optimizer_presets_or_exit "$selected_optimizer_presets" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$branch" "$DIR" + download_project "$repo" "$ref_type" "$ref" "$DIR" [[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH" neutralize_package_lock diff --git a/test/externalTests/gnosis-v2.sh b/test/externalTests/gnosis-v2.sh index f963c74a0..e21940095 100755 --- a/test/externalTests/gnosis-v2.sh +++ b/test/externalTests/gnosis-v2.sh @@ -34,7 +34,8 @@ function test_fn { npm test; } function gnosis_safe_test { local repo="https://github.com/solidity-external-tests/safe-contracts.git" - local branch=v2_080 + local ref_type=branch + local ref="v2_080" local config_file="truffle-config.js" local compile_only_presets=( @@ -54,7 +55,7 @@ function gnosis_safe_test print_optimizer_presets_or_exit "$selected_optimizer_presets" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$branch" "$DIR" + download_project "$repo" "$ref_type" "$ref" "$DIR" [[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH" sed -i 's|github:gnosis/mock-contract#sol_0_5_0|github:solidity-external-tests/mock-contract#master_080|g' package.json diff --git a/test/externalTests/gnosis.sh b/test/externalTests/gnosis.sh index 7d8bc2442..ade36a9ce 100755 --- a/test/externalTests/gnosis.sh +++ b/test/externalTests/gnosis.sh @@ -34,7 +34,8 @@ function test_fn { npm test; } function gnosis_safe_test { local repo="https://github.com/solidity-external-tests/safe-contracts.git" - local branch=development_080 + local ref_type=branch + local ref="development_080" local config_file="truffle-config.js" local compile_only_presets=() @@ -53,7 +54,7 @@ function gnosis_safe_test print_optimizer_presets_or_exit "$selected_optimizer_presets" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$branch" "$DIR" + download_project "$repo" "$ref_type" "$ref" "$DIR" [[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH" sed -i 's|github:gnosis/mock-contract#sol_0_5_0|github:solidity-external-tests/mock-contract#master_080|g' package.json diff --git a/test/externalTests/trident.sh b/test/externalTests/trident.sh index 312930293..3c15c5ea1 100755 --- a/test/externalTests/trident.sh +++ b/test/externalTests/trident.sh @@ -42,7 +42,8 @@ function test_fn { function trident_test { local repo="https://github.com/sushiswap/trident" - local branch=master + local ref_type=branch + local ref="master" local config_file="hardhat.config.ts" local config_var=config @@ -62,7 +63,7 @@ function trident_test print_optimizer_presets_or_exit "$selected_optimizer_presets" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$branch" "$DIR" + download_project "$repo" "$ref_type" "$ref" "$DIR" # TODO: Currently tests work only with the exact versions from yarn.lock. # Re-enable this when https://github.com/sushiswap/trident/issues/284 is fixed. diff --git a/test/externalTests/zeppelin.sh b/test/externalTests/zeppelin.sh index 9865c7e40..7873ec953 100755 --- a/test/externalTests/zeppelin.sh +++ b/test/externalTests/zeppelin.sh @@ -34,7 +34,8 @@ function test_fn { npm test; } function zeppelin_test { local repo="https://github.com/OpenZeppelin/openzeppelin-contracts.git" - local branch=master + local ref_type=branch + local ref="master" local config_file="hardhat.config.js" local compile_only_presets=( @@ -54,7 +55,7 @@ function zeppelin_test print_optimizer_presets_or_exit "$selected_optimizer_presets" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$branch" "$DIR" + download_project "$repo" "$ref_type" "$ref" "$DIR" neutralize_package_json_hooks force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" From b8b8fcb463e7e42f60e693462c8285975c33bef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 10 Jan 2022 17:26:44 +0100 Subject: [PATCH 45/77] Switch the trident external test to and earlier, working revision --- test/externalTests/trident.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/externalTests/trident.sh b/test/externalTests/trident.sh index 3c15c5ea1..6921d7a8a 100755 --- a/test/externalTests/trident.sh +++ b/test/externalTests/trident.sh @@ -42,8 +42,8 @@ function test_fn { function trident_test { local repo="https://github.com/sushiswap/trident" - local ref_type=branch - local ref="master" + local ref_type=commit + local ref="0cab5ae884cc9a41223d52791be775c3a053cb26" # master as of 2021-12-16 local config_file="hardhat.config.ts" local config_var=config From 823f0da3ee2d3e24975cdb00d67929ac0307a15d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 10 Jan 2022 21:28:32 +0100 Subject: [PATCH 46/77] trident: Update to match changes done to other external tests in the preset selection PR --- test/externalTests/trident.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/externalTests/trident.sh b/test/externalTests/trident.sh index 6921d7a8a..d82b0a707 100755 --- a/test/externalTests/trident.sh +++ b/test/externalTests/trident.sh @@ -58,9 +58,8 @@ function trident_test legacy-optimize-evm+yul ) - local selected_optimizer_presets - selected_optimizer_presets=$(circleci_select_steps_multiarg "${settings_presets[@]}") - print_optimizer_presets_or_exit "$selected_optimizer_presets" + [[ $SELECTED_PRESETS != "" ]] || SELECTED_PRESETS=$(circleci_select_steps_multiarg "${settings_presets[@]}") + print_presets_or_exit "$SELECTED_PRESETS" setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" download_project "$repo" "$ref_type" "$ref" "$DIR" @@ -71,7 +70,7 @@ function trident_test neutralize_package_json_hooks force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" - force_hardhat_compiler_settings "$config_file" "$(first_word "$selected_optimizer_presets")" "$config_var" + force_hardhat_compiler_settings "$config_file" "$(first_word "$SELECTED_PRESETS")" "$config_var" yarn install replace_version_pragmas @@ -89,7 +88,7 @@ function trident_test # version check. It's not used by tests so we can remove it. rm -r node_modules/@sushiswap/core/ - for preset in $selected_optimizer_presets; do + for preset in $SELECTED_PRESETS; do hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var" done } From 7142bfa548f650d3b018092fb826168dfafd177b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 10 Jan 2022 21:11:50 +0100 Subject: [PATCH 47/77] trident: Sort test suites to make the order the same in CI and locally --- test/externalTests/trident.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/externalTests/trident.sh b/test/externalTests/trident.sh index d82b0a707..c244efd09 100755 --- a/test/externalTests/trident.sh +++ b/test/externalTests/trident.sh @@ -35,7 +35,7 @@ function test_fn { TS_NODE_TRANSPILE_ONLY=1 npx hardhat test --no-compile $( # TODO: We need to skip Migration.test.ts because it fails and makes other tests fail too. # Replace this with `yarn test` once https://github.com/sushiswap/trident/issues/283 is fixed. - find test/ -name "*.test.ts" ! -path "test/Migration.test.ts" + find test/ -name "*.test.ts" ! -path "test/Migration.test.ts" | LC_ALL=C sort ) } From cc49eeda3fbbf2886b8ff2f58ed44aed390450e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 10 Jan 2022 21:12:37 +0100 Subject: [PATCH 48/77] trident: Note explaining the hard-coded commit --- test/externalTests/trident.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/test/externalTests/trident.sh b/test/externalTests/trident.sh index c244efd09..26c3d3810 100755 --- a/test/externalTests/trident.sh +++ b/test/externalTests/trident.sh @@ -43,6 +43,7 @@ function trident_test { local repo="https://github.com/sushiswap/trident" local ref_type=commit + # FIXME: Switch back to master branch when https://github.com/sushiswap/trident/issues/303 gets fixed. local ref="0cab5ae884cc9a41223d52791be775c3a053cb26" # master as of 2021-12-16 local config_file="hardhat.config.ts" local config_var=config From 9f171c0f06975a6852c8afac8361bb5a976c8d51 Mon Sep 17 00:00:00 2001 From: Leo Alt Date: Wed, 12 Jan 2022 14:46:30 +0100 Subject: [PATCH 49/77] update smtchecker tests for new z3 --- .circleci/config.yml | 16 ++++++++-------- .circleci/osx_install_dependencies.sh | 2 +- CMakeLists.txt | 2 +- scripts/build_emscripten.sh | 4 ++-- .../blockchain_state/balance_receive_2.sol | 2 +- .../balance_receive_ext_calls_2.sol | 2 +- .../branches_in_modifiers_2.sol | 2 +- .../external_calls/call_with_value_1.sol | 2 +- .../external_call_from_constructor_3.sol | 2 +- .../external_call_with_value_2.sol | 2 +- .../external_hash_known_code_state.sol | 2 +- ...hash_known_code_state_reentrancy_indirect.sol | 4 +++- .../external_calls/external_reentrancy_2.sol | 4 +++- .../functions/functions_external_2.sol | 2 +- .../virtual_function_called_by_constructor.sol | 2 +- .../assignment_contract_member_variable.sol | 2 +- .../operators/compound_add_array_index.sol | 2 +- .../operators/conditional_assignment_6.sol | 2 +- .../special/tx_vars_reentrancy_1.sol | 2 +- .../special/tx_vars_reentrancy_2.sol | 4 +++- .../try_catch/try_public_var_mapping.sol | 2 +- .../types/address_transfer_insufficient.sol | 2 +- .../types/mapping_equal_keys_2.sol | 2 +- .../types/static_array_length_1.sol | 2 +- .../struct_aliasing_parameter_storage_2.sol | 2 +- .../struct_aliasing_parameter_storage_3.sol | 2 +- .../smtCheckerTests/userTypes/fixedpoint.sol | 2 +- 27 files changed, 41 insertions(+), 35 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1b1fbbdb0..56a4af30a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,20 +9,20 @@ version: 2.1 parameters: ubuntu-2004-docker-image: type: string - # solbuildpackpusher/solidity-buildpack-deps:ubuntu2004-9 - default: "solbuildpackpusher/solidity-buildpack-deps@sha256:3d8a912e8e78e98cd217955d06d98608ad60adc67728d4c3a569991235fa1abb" + # solbuildpackpusher/solidity-buildpack-deps:ubuntu2004-10 + default: "solbuildpackpusher/solidity-buildpack-deps@sha256:e61939751ff9777307857361f712b581bfc8a8aaae75fab7b50febc764710587" ubuntu-2004-clang-docker-image: type: string - # solbuildpackpusher/solidity-buildpack-deps:ubuntu2004.clang-9 - default: "solbuildpackpusher/solidity-buildpack-deps@sha256:a1ba002cae17279d1396a898b04e4e9c45602ad881295db3e2f484a7e24f6f43" + # solbuildpackpusher/solidity-buildpack-deps:ubuntu2004.clang-10 + default: "solbuildpackpusher/solidity-buildpack-deps@sha256:0de8c68f084120b2a165406e3a0c2aab58b32f5b7182c2322245245f1d243b8d" ubuntu-1604-clang-ossfuzz-docker-image: type: string - # solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-14 - default: "solbuildpackpusher/solidity-buildpack-deps@sha256:f353823cce2f6cd2f9f1459d86cd76fdfc551a0261d87626615ea6c1d8f90587" + # solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-15 + default: "solbuildpackpusher/solidity-buildpack-deps@sha256:87f1a57586eec194a6217ab624efc69d3d9af2f7ac8ca36497ad57488c2f08ae" emscripten-docker-image: type: string - # solbuildpackpusher/solidity-buildpack-deps:emscripten-8 - default: "solbuildpackpusher/solidity-buildpack-deps@sha256:842d6074e0e7e5355c89122c1cafc1fdb59696596750e7d56e5f35c0d883ad59" + # solbuildpackpusher/solidity-buildpack-deps:emscripten-9 + default: "solbuildpackpusher/solidity-buildpack-deps@sha256:d51534dfdd05ece86f69ed7beafd68c15b88606da00a4b7fe2873ccfbd0dce24" evm-version: type: string default: london diff --git a/.circleci/osx_install_dependencies.sh b/.circleci/osx_install_dependencies.sh index 36d336774..9e8d14963 100755 --- a/.circleci/osx_install_dependencies.sh +++ b/.circleci/osx_install_dependencies.sh @@ -61,7 +61,7 @@ then ./scripts/install_obsolete_jsoncpp_1_7_4.sh # z3 - z3_version="4.8.13" + z3_version="4.8.14" z3_dir="z3-${z3_version}-x64-osx-10.16" z3_package="${z3_dir}.zip" wget "https://github.com/Z3Prover/z3/releases/download/z3-${z3_version}/${z3_package}" diff --git a/CMakeLists.txt b/CMakeLists.txt index f3a03d94e..99d765980 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,7 +65,7 @@ configure_file("${CMAKE_SOURCE_DIR}/cmake/templates/license.h.in" include/licens include(EthOptions) configure_project(TESTS) -set(LATEST_Z3_VERSION "4.8.13") +set(LATEST_Z3_VERSION "4.8.14") set(MINIMUM_Z3_VERSION "4.8.0") find_package(Z3) if (${Z3_FOUND}) diff --git a/scripts/build_emscripten.sh b/scripts/build_emscripten.sh index f6c9151eb..16e9078f3 100755 --- a/scripts/build_emscripten.sh +++ b/scripts/build_emscripten.sh @@ -34,7 +34,7 @@ else BUILD_DIR="$1" fi -# solbuildpackpusher/solidity-buildpack-deps:emscripten-8 +# solbuildpackpusher/solidity-buildpack-deps:emscripten-9 docker run -v "$(pwd):/root/project" -w /root/project \ - solbuildpackpusher/solidity-buildpack-deps@sha256:842d6074e0e7e5355c89122c1cafc1fdb59696596750e7d56e5f35c0d883ad59 \ + solbuildpackpusher/solidity-buildpack-deps@sha256:d51534dfdd05ece86f69ed7beafd68c15b88606da00a4b7fe2873ccfbd0dce24\ ./scripts/ci/build_emscripten.sh "$BUILD_DIR" diff --git a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_2.sol b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_2.sol index c4714e2e3..bbf91ade4 100644 --- a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_2.sol +++ b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_2.sol @@ -16,5 +16,5 @@ contract C { // SMTEngine: all // ---- // Warning 4984: (266-272): CHC: Overflow (resulting value larger than 2**256 - 1) happens here.\nCounterexample:\nx = 115792089237316195423570985008687907853269984665640564039457584007913129639926, once = true\n\nTransaction trace:\nC.constructor(){ msg.value: 28100 }\nState: x = 115792089237316195423570985008687907853269984665640564039457584007913129639926, once = false\nC.f(){ msg.value: 8 } -// Warning 6328: (235-273): CHC: Assertion violation happens here.\nCounterexample:\nx = 0, once = true\n\nTransaction trace:\nC.constructor(){ msg.value: 0 }\nState: x = 0, once = false\nC.f(){ msg.value: 8 } +// Warning 6328: (235-273): CHC: Assertion violation happens here.\nCounterexample:\nx = 0, once = true\n\nTransaction trace:\nC.constructor(){ msg.value: 0 }\nState: x = 0, once = false\nC.f(){ msg.value: 2 } // Info 1180: Contract invariant(s) for :C:\nonce\n diff --git a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_ext_calls_2.sol b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_ext_calls_2.sol index c53f156d6..28c4734bd 100644 --- a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_ext_calls_2.sol +++ b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_ext_calls_2.sol @@ -12,4 +12,4 @@ contract C { // ---- // Warning 9302: (82-93): Return value of low-level calls not used. // Warning 6328: (97-131): CHC: Assertion violation happens here. -// Info 1180: Reentrancy property(ies) for :C:\n(!( >= 2) && (((:var 1).balances[address(this)] + ((- 1) * (:var 0).balances[address(this)])) <= 0))\n = 0 -> no errors\n = 1 -> Assertion failed at assert(address(this).balance == x)\n = 2 -> Assertion failed at assert(address(this).balance >= x)\n +// Info 1180: Reentrancy property(ies) for :C:\n((((:var 1).balances[address(this)] + ((- 1) * (:var 0).balances[address(this)])) <= 0) && !( >= 2))\n = 0 -> no errors\n = 1 -> Assertion failed at assert(address(this).balance == x)\n = 2 -> Assertion failed at assert(address(this).balance >= x)\n diff --git a/test/libsolidity/smtCheckerTests/control_flow/branches_with_return/branches_in_modifiers_2.sol b/test/libsolidity/smtCheckerTests/control_flow/branches_with_return/branches_in_modifiers_2.sol index f08a26bf7..98b551c17 100644 --- a/test/libsolidity/smtCheckerTests/control_flow/branches_with_return/branches_in_modifiers_2.sol +++ b/test/libsolidity/smtCheckerTests/control_flow/branches_with_return/branches_in_modifiers_2.sol @@ -45,5 +45,5 @@ contract C { // SMTIgnoreOS: macos // ---- // Warning 6328: (255-269): CHC: Assertion violation happens here.\nCounterexample:\nx = 0\n\nTransaction trace:\nC.constructor()\nState: x = 0\nC.test()\n C.reset_if_overflow() -- internal call -// Warning 6328: (502-519): CHC: Assertion violation happens here.\nCounterexample:\nx = 2\noldx = 1\n\nTransaction trace:\nC.constructor()\nState: x = 0\nC.set(1)\nState: x = 1\nC.test()\n C.reset_if_overflow() -- internal call +// Warning 6328: (502-519): CHC: Assertion violation happens here. // Warning 6328: (615-629): CHC: Assertion violation happens here.\nCounterexample:\nx = 1\n\nTransaction trace:\nC.constructor()\nState: x = 0\nC.set(10)\nState: x = 10\nC.test()\n C.reset_if_overflow() -- internal call diff --git a/test/libsolidity/smtCheckerTests/external_calls/call_with_value_1.sol b/test/libsolidity/smtCheckerTests/external_calls/call_with_value_1.sol index f9293f693..813185adf 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/call_with_value_1.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/call_with_value_1.sol @@ -12,5 +12,5 @@ contract C { // ---- // Warning 9302: (96-117): Return value of low-level calls not used. // Warning 6328: (121-156): CHC: Assertion violation might happen here. -// Warning 6328: (175-211): CHC: Assertion violation happens here.\nCounterexample:\n\ni = 0x0\n\nTransaction trace:\nC.constructor()\nC.g(0x0)\n i.call{value: 10}("") -- untrusted external call +// Warning 6328: (175-211): CHC: Assertion violation happens here. // Warning 4661: (121-156): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_call_from_constructor_3.sol b/test/libsolidity/smtCheckerTests/external_calls/external_call_from_constructor_3.sol index 9d27d6d3b..eb5cd97dd 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_call_from_constructor_3.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_call_from_constructor_3.sol @@ -20,4 +20,4 @@ contract C { // SMTEngine: all // ---- // Warning 6328: (69-85): CHC: Assertion violation happens here.\nCounterexample:\n\n_x = 100\n = 0\n\nTransaction trace:\nState.constructor()\nState.f(100) -// Warning 6328: (203-217): CHC: Assertion violation happens here.\nCounterexample:\ns = 0, z = 0\n\nTransaction trace:\nC.constructor()\nState: s = 0, z = 0\nC.f() +// Warning 6328: (203-217): CHC: Assertion violation happens here.\nCounterexample:\ns = 0, z = 3\n\nTransaction trace:\nC.constructor()\nState: s = 0, z = 3\nC.f() diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_2.sol b/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_2.sol index f6c833858..4b51d9d9e 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_2.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_2.sol @@ -14,5 +14,5 @@ contract C { // SMTEngine: all // ---- // Warning 6328: (150-186): CHC: Assertion violation might happen here. -// Warning 6328: (205-240): CHC: Assertion violation happens here.\nCounterexample:\n\ni = 0\n\nTransaction trace:\nC.constructor()\nC.g(0)\n i.f{value: 0}() -- untrusted external call +// Warning 6328: (205-240): CHC: Assertion violation happens here. // Warning 4661: (150-186): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state.sol b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state.sol index 2468a1a72..317400e1d 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state.sol @@ -36,4 +36,4 @@ contract C { // SMTIgnoreCex: yes // ---- // Warning 6328: (495-532): CHC: Assertion violation happens here. -// Info 1180: Reentrancy property(ies) for :C:\n(((owner + ((- 1) * owner')) <= 0) && !( = 1) && ((owner + ((- 1) * owner')) >= 0))\n = 0 -> no errors\n = 1 -> Assertion failed at assert(prevOwner == owner)\n = 3 -> Assertion failed at assert(owner == address(0) || y != z)\n +// Info 1180: Reentrancy property(ies) for :C:\n(((owner + ((- 1) * owner')) >= 0) && !( = 1) && ((owner + ((- 1) * owner')) <= 0))\n = 0 -> no errors\n = 1 -> Assertion failed at assert(prevOwner == owner)\n = 3 -> Assertion failed at assert(owner == address(0) || y != z)\n diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_indirect.sol b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_indirect.sol index 4ab3f21e6..1fcda01b0 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_indirect.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_indirect.sol @@ -43,5 +43,7 @@ contract C { // SMTEngine: all // SMTIgnoreCex: yes // ---- +// Warning 1218: (437-463): CHC: Error trying to invoke SMT solver. // Warning 6328: (419-433): CHC: Assertion violation happens here. -// Warning 6328: (437-463): CHC: Assertion violation happens here. +// Warning 6328: (437-463): CHC: Assertion violation might happen here. +// Warning 4661: (437-463): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_reentrancy_2.sol b/test/libsolidity/smtCheckerTests/external_calls/external_reentrancy_2.sol index 19ff2bbad..1e8ce8816 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_reentrancy_2.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_reentrancy_2.sol @@ -13,4 +13,6 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (117-131): CHC: Assertion violation happens here.\nCounterexample:\nlocked = false\ntarget = 0x0\n\nTransaction trace:\nC.constructor()\nState: locked = true\nC.call(0x0)\n D(target).e() -- untrusted external call, synthesized as:\n C.call(0x0) -- reentrant call +// Warning 1218: (117-131): CHC: Error trying to invoke SMT solver. +// Warning 6328: (117-131): CHC: Assertion violation might happen here. +// Warning 4661: (117-131): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/functions/functions_external_2.sol b/test/libsolidity/smtCheckerTests/functions/functions_external_2.sol index c2f55fa98..5efcb2da1 100644 --- a/test/libsolidity/smtCheckerTests/functions/functions_external_2.sol +++ b/test/libsolidity/smtCheckerTests/functions/functions_external_2.sol @@ -25,4 +25,4 @@ contract C // SMTIgnoreOS: macos // ---- // Warning 6328: (234-253): CHC: Assertion violation happens here. -// Info 1180: Reentrancy property(ies) for :C:\n!( = 1)\n((!((map[1] + ((- 1) * map[0])) >= 0) || ((map'[0] + ((- 1) * map'[1])) <= 0)) && (((map'[1] + ((- 1) * map'[0])) <= 0) || !((map[1] + ((- 1) * map[0])) <= 0)) && !( = 2))\n = 0 -> no errors\n = 1 -> Assertion failed at assert(map[0] == map[1])\n = 2 -> Assertion failed at assert(map[0] == map[1])\n = 3 -> Assertion failed at assert(map[0] == 0)\n +// Info 1180: Reentrancy property(ies) for :C:\n!( = 1)\n((!((map[1] + ((- 1) * map[0])) <= 0) || ((map'[1] + ((- 1) * map'[0])) <= 0)) && !( = 2) && (!((map[1] + ((- 1) * map[0])) >= 0) || ((map'[0] + ((- 1) * map'[1])) <= 0)))\n = 0 -> no errors\n = 1 -> Assertion failed at assert(map[0] == map[1])\n = 2 -> Assertion failed at assert(map[0] == map[1])\n = 3 -> Assertion failed at assert(map[0] == 0)\n diff --git a/test/libsolidity/smtCheckerTests/functions/virtual_function_called_by_constructor.sol b/test/libsolidity/smtCheckerTests/functions/virtual_function_called_by_constructor.sol index e30a5e743..0117f9b49 100644 --- a/test/libsolidity/smtCheckerTests/functions/virtual_function_called_by_constructor.sol +++ b/test/libsolidity/smtCheckerTests/functions/virtual_function_called_by_constructor.sol @@ -27,4 +27,4 @@ contract C is A { // ---- // Warning 6328: (199-214): CHC: Assertion violation happens here.\nCounterexample:\nx = 2\n\nTransaction trace:\nA.constructor()\nState: x = 2\nA.i() // Warning 6328: (387-401): CHC: Assertion violation happens here.\nCounterexample:\nx = 10\n\nTransaction trace:\nC.constructor()\nState: x = 10\nC.i() -// Info 1180: Contract invariant(s) for :A:\n(!(x <= 1) && !(x >= 3))\nContract invariant(s) for :C:\n(!(x <= 9) && !(x >= 11))\n +// Info 1180: Contract invariant(s) for :A:\n(!(x <= 1) && !(x >= 3))\nContract invariant(s) for :C:\n(!(x >= 11) && !(x <= 9))\n diff --git a/test/libsolidity/smtCheckerTests/operators/assignment_contract_member_variable.sol b/test/libsolidity/smtCheckerTests/operators/assignment_contract_member_variable.sol index 284f9bcbd..7a1deafe0 100644 --- a/test/libsolidity/smtCheckerTests/operators/assignment_contract_member_variable.sol +++ b/test/libsolidity/smtCheckerTests/operators/assignment_contract_member_variable.sol @@ -29,4 +29,4 @@ contract A { // SMTIgnoreCex: yes // ---- // Warning 6328: (392-408): CHC: Assertion violation happens here. -// Info 1180: Contract invariant(s) for :A:\n(((x = (- 2)) && (y = (- 2))) || ((x = 0) && (y = 0)))\n(((x = 0) && (y = 0)) || ((x = (- 2)) && (y = (- 2))))\n +// Info 1180: Contract invariant(s) for :A:\n(((x = (- 2)) && (y = (- 2))) || ((x = 0) && (y = 0)))\n diff --git a/test/libsolidity/smtCheckerTests/operators/compound_add_array_index.sol b/test/libsolidity/smtCheckerTests/operators/compound_add_array_index.sol index 1c6e205d3..4186f39fe 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_add_array_index.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_add_array_index.sol @@ -20,4 +20,4 @@ contract C // SMTEngine: all // SMTIgnoreOS: macos // ---- -// Warning 6328: (262-284): CHC: Assertion violation happens here.\nCounterexample:\narray = [299, 0]\nx = 99\np = 0\n\nTransaction trace:\nC.constructor()\nState: array = [0, 0]\nC.f(99, 0) +// Warning 6328: (262-284): CHC: Assertion violation happens here.\nCounterexample:\narray = [200, 0]\nx = 0\np = 0\n\nTransaction trace:\nC.constructor()\nState: array = [0, 0]\nC.f(0, 0) diff --git a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_6.sol b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_6.sol index 923147d49..b26fcbd93 100644 --- a/test/libsolidity/smtCheckerTests/operators/conditional_assignment_6.sol +++ b/test/libsolidity/smtCheckerTests/operators/conditional_assignment_6.sol @@ -25,4 +25,4 @@ contract C { // SMTIgnoreOS: macos // ---- // Warning 2072: (255-261): Unused local variable. -// Info 1180: Reentrancy property(ies) for :C:\n((!(x <= 2) || !(x' >= 3)) && ( <= 0) && (!(x' <= 0) || !(x >= 2)))\n = 0 -> no errors\n = 1 -> Assertion failed at assert(x == 2 || x == 1)\n +// Info 1180: Reentrancy property(ies) for :C:\n((!(x' >= 3) || (a' = a)) && ( <= 0) && (!(x' <= 0) || !(x >= 2)) && (!(x <= 2) || !(x' >= 3)))\n = 0 -> no errors\n = 1 -> Assertion failed at assert(x == 2 || x == 1)\n diff --git a/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_1.sol b/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_1.sol index 175b68410..7729cebb9 100644 --- a/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_1.sol +++ b/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_1.sol @@ -13,4 +13,4 @@ contract C { // SMTEngine: all // SMTIgnoreOS: macos // ---- -// Warning 6328: (135-169): CHC: Assertion violation happens here.\nCounterexample:\n\n_i = 0\nx = 2997\n\nTransaction trace:\nC.constructor()\nC.g(0){ msg.value: 2803 }\n _i.f() -- untrusted external call, synthesized as:\n C.g(0){ msg.value: 32278 } -- reentrant call\n _i.f() -- untrusted external call +// Warning 6328: (135-169): CHC: Assertion violation happens here.\nCounterexample:\n\n_i = 0\nx = 2997\n\nTransaction trace:\nC.constructor()\nC.g(0){ msg.value: 2803 }\n _i.f() -- untrusted external call, synthesized as:\n C.g(0){ msg.value: 2446 } -- reentrant call\n _i.f() -- untrusted external call diff --git a/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_2.sol b/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_2.sol index 81de958b3..e704cfd71 100644 --- a/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_2.sol +++ b/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_2.sol @@ -13,4 +13,6 @@ contract C { // SMTEngine: all // SMTIgnoreOS: macos // ---- -// Warning 6328: (157-191): CHC: Assertion violation happens here.\nCounterexample:\n\n_i = 0\nx = 101\n\nTransaction trace:\nC.constructor()\nC.g(0){ msg.value: 83 }\n _i.f{ value: 100 }() -- untrusted external call +// Warning 1218: (157-191): CHC: Error trying to invoke SMT solver. +// Warning 6328: (157-191): CHC: Assertion violation might happen here. +// Warning 4661: (157-191): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/try_catch/try_public_var_mapping.sol b/test/libsolidity/smtCheckerTests/try_catch/try_public_var_mapping.sol index 2caae5e16..0854dedd1 100644 --- a/test/libsolidity/smtCheckerTests/try_catch/try_public_var_mapping.sol +++ b/test/libsolidity/smtCheckerTests/try_catch/try_public_var_mapping.sol @@ -21,5 +21,5 @@ contract C { // SMTEngine: all // SMTIgnoreOS: macos // ---- -// Warning 6328: (280-300): CHC: Assertion violation happens here. +// Warning 6328: (280-300): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f() // Info 1180: Contract invariant(s) for :C:\n!(m[0].length <= 1)\n(!(m[0][1] >= 43) && !(m[0][1] <= 41))\n diff --git a/test/libsolidity/smtCheckerTests/types/address_transfer_insufficient.sol b/test/libsolidity/smtCheckerTests/types/address_transfer_insufficient.sol index 4b55c3241..2fcdda175 100644 --- a/test/libsolidity/smtCheckerTests/types/address_transfer_insufficient.sol +++ b/test/libsolidity/smtCheckerTests/types/address_transfer_insufficient.sol @@ -11,6 +11,6 @@ contract C // ==== // SMTEngine: all // ---- -// Warning 6328: (180-204): CHC: Assertion violation happens here.\nCounterexample:\n\na = 0x2297\nb = 0x2297\n\nTransaction trace:\nC.constructor()\nC.f(0x2297, 0x2297) +// Warning 6328: (180-204): CHC: Assertion violation happens here.\nCounterexample:\n\na = 0x52f6\nb = 0x52f6\n\nTransaction trace:\nC.constructor()\nC.f(0x52f6, 0x52f6) // Warning 1236: (101-116): BMC: Insufficient funds happens here. // Warning 1236: (120-136): BMC: Insufficient funds happens here. diff --git a/test/libsolidity/smtCheckerTests/types/mapping_equal_keys_2.sol b/test/libsolidity/smtCheckerTests/types/mapping_equal_keys_2.sol index 0290d31e1..37e2e4c13 100644 --- a/test/libsolidity/smtCheckerTests/types/mapping_equal_keys_2.sol +++ b/test/libsolidity/smtCheckerTests/types/mapping_equal_keys_2.sol @@ -9,4 +9,4 @@ contract C // ==== // SMTEngine: all // ---- -// Warning 6328: (86-100): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 0\ny = 1\n\nTransaction trace:\nC.constructor()\nC.f(0, 1) +// Warning 6328: (86-100): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 1\ny = 0\n\nTransaction trace:\nC.constructor()\nC.f(1, 0) diff --git a/test/libsolidity/smtCheckerTests/types/static_array_length_1.sol b/test/libsolidity/smtCheckerTests/types/static_array_length_1.sol index e8b6f1a32..72bed0f4e 100644 --- a/test/libsolidity/smtCheckerTests/types/static_array_length_1.sol +++ b/test/libsolidity/smtCheckerTests/types/static_array_length_1.sol @@ -9,4 +9,4 @@ contract C { // SMTEngine: all // ---- // Warning 6328: (102-122): CHC: Assertion violation happens here.\nCounterexample:\n\na = [0x09, 0x09]\n\nTransaction trace:\nC.constructor()\nC.f([0x09, 0x09]) -// Warning 6328: (141-161): CHC: Assertion violation happens here.\nCounterexample:\n\na = [0x09, 0x09]\n\nTransaction trace:\nC.constructor()\nC.f([0x09, 0x09]) +// Warning 6328: (141-161): CHC: Assertion violation happens here.\nCounterexample:\n\na = [0x0a, 0x0a]\n\nTransaction trace:\nC.constructor()\nC.f([0x0a, 0x0a]) diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_parameter_storage_2.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_parameter_storage_2.sol index 9d4623ae0..698262382 100644 --- a/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_parameter_storage_2.sol +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_parameter_storage_2.sol @@ -20,4 +20,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (289-322): CHC: Assertion violation happens here.\nCounterexample:\ns = {innerM, sum: 10}\n\nTransaction trace:\nC.constructor(0){ msg.sender: 0x6dc4 }\nState: s = {innerM, sum: 10}\nC.g(){ msg.sender: 0x0985 } +// Warning 6328: (289-322): CHC: Assertion violation happens here.\nCounterexample:\ns = {innerM, sum: 11}\n\nTransaction trace:\nC.constructor(0){ msg.sender: 0x6dc4 }\nState: s = {innerM, sum: 11}\nC.g(){ msg.sender: 0x0985 } diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_parameter_storage_3.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_parameter_storage_3.sol index 8779cd095..fcf30555e 100644 --- a/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_parameter_storage_3.sol +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_parameter_storage_3.sol @@ -26,4 +26,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (307-327): CHC: Assertion violation happens here.\nCounterexample:\nt = {x: 10, s: {innerM, sum: 21239}}\n\nTransaction trace:\nC.constructor(0){ msg.sender: 0x6dc4 }\nState: t = {x: 10, s: {innerM, sum: 21239}}\nC.g() +// Warning 6328: (307-327): CHC: Assertion violation happens here.\nCounterexample:\nt = {x: 11, s: {innerM, sum: 21239}}\n\nTransaction trace:\nC.constructor(0){ msg.sender: 0x6dc4 }\nState: t = {x: 11, s: {innerM, sum: 21239}}\nC.g() diff --git a/test/libsolidity/smtCheckerTests/userTypes/fixedpoint.sol b/test/libsolidity/smtCheckerTests/userTypes/fixedpoint.sol index a8aa0bd9a..0a479c4ac 100644 --- a/test/libsolidity/smtCheckerTests/userTypes/fixedpoint.sol +++ b/test/libsolidity/smtCheckerTests/userTypes/fixedpoint.sol @@ -69,6 +69,6 @@ contract TestFixedMath { // SMTEngine: all // ---- // Warning 6328: (1886-1970): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nTestFixedMath.constructor()\nTestFixedMath.f()\n TestFixedMath.add(0, 0) -- internal call\n FixedMath.add(0, 0) -- internal call\n TestFixedMath.add(25, 45) -- internal call\n FixedMath.add(25, 45) -- internal call\n TestFixedMath.add(25, 45) -- internal call\n FixedMath.add(25, 45) -- internal call -// Warning 6328: (2165-2266): CHC: Assertion violation happens here. +// Warning 6328: (2165-2266): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nTestFixedMath.constructor()\nTestFixedMath.g()\n TestFixedMath.mul(340282366920938463463374607431768211456, 20) -- internal call\n FixedMath.mul(340282366920938463463374607431768211456, 20) -- internal call\n TestFixedMath.mul(340282366920938463463374607431768211456, 20) -- internal call\n FixedMath.mul(340282366920938463463374607431768211456, 20) -- internal call // Warning 6328: (2675-2791): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nTestFixedMath.constructor()\nTestFixedMath.h()\n TestFixedMath.floor(11579208923731619542357098500868790785326998665640564039457584007913129639930) -- internal call\n FixedMath.floor(11579208923731619542357098500868790785326998665640564039457584007913129639930) -- internal call\n TestFixedMath.floor(115792089237316195423570985008687907853269984665640564039457584007913129639935) -- internal call\n FixedMath.floor(115792089237316195423570985008687907853269984665640564039457584007913129639935) -- internal call\n TestFixedMath.floor(11579208923731619542357098500868790785326998665640564039457584007913129639930) -- internal call\n FixedMath.floor(11579208923731619542357098500868790785326998665640564039457584007913129639930) -- internal call // Warning 6328: (3161-3212): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nTestFixedMath.constructor()\nTestFixedMath.i()\n TestFixedMath.toUFixed256x18(0) -- internal call\n FixedMath.toUFixed256x18(0) -- internal call\n TestFixedMath.toUFixed256x18(5) -- internal call\n FixedMath.toUFixed256x18(5) -- internal call\n TestFixedMath.toUFixed256x18(115792089237316195423570985008687907853269984665640564039457) -- internal call\n FixedMath.toUFixed256x18(115792089237316195423570985008687907853269984665640564039457) -- internal call\n TestFixedMath.toUFixed256x18(5) -- internal call\n FixedMath.toUFixed256x18(5) -- internal call From b49f486cf6d6dfb19dfaee0dea1cad58930534f7 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 12 Jan 2022 17:38:47 +0100 Subject: [PATCH 50/77] Update osx z3 archive hash. --- .circleci/osx_install_dependencies.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/osx_install_dependencies.sh b/.circleci/osx_install_dependencies.sh index 9e8d14963..cd0637eac 100755 --- a/.circleci/osx_install_dependencies.sh +++ b/.circleci/osx_install_dependencies.sh @@ -65,7 +65,7 @@ then z3_dir="z3-${z3_version}-x64-osx-10.16" z3_package="${z3_dir}.zip" wget "https://github.com/Z3Prover/z3/releases/download/z3-${z3_version}/${z3_package}" - validate_checksum "$z3_package" 191b26be2b617b2dffffce139d77abcd7e584859efbc10a58d01a1d7830697a4 + validate_checksum "$z3_package" 1341671670e0c4e72da80815128a68975ee90816d50ceaf6bd820f06babe2cfd unzip "$z3_package" rm "$z3_package" cp "${z3_dir}/bin/libz3.a" /usr/local/lib From 1655626e0a0704aee0351b1a9bf700941b8be244 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 12 Jan 2022 17:58:05 +0100 Subject: [PATCH 51/77] Remove counterexample from test. --- .../libsolidity/smtCheckerTests/userTypes/fixedpoint.sol | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/libsolidity/smtCheckerTests/userTypes/fixedpoint.sol b/test/libsolidity/smtCheckerTests/userTypes/fixedpoint.sol index 0a479c4ac..4bff3a498 100644 --- a/test/libsolidity/smtCheckerTests/userTypes/fixedpoint.sol +++ b/test/libsolidity/smtCheckerTests/userTypes/fixedpoint.sol @@ -67,8 +67,9 @@ contract TestFixedMath { } // ==== // SMTEngine: all +// SMTIgnoreCex: yes // ---- -// Warning 6328: (1886-1970): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nTestFixedMath.constructor()\nTestFixedMath.f()\n TestFixedMath.add(0, 0) -- internal call\n FixedMath.add(0, 0) -- internal call\n TestFixedMath.add(25, 45) -- internal call\n FixedMath.add(25, 45) -- internal call\n TestFixedMath.add(25, 45) -- internal call\n FixedMath.add(25, 45) -- internal call -// Warning 6328: (2165-2266): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nTestFixedMath.constructor()\nTestFixedMath.g()\n TestFixedMath.mul(340282366920938463463374607431768211456, 20) -- internal call\n FixedMath.mul(340282366920938463463374607431768211456, 20) -- internal call\n TestFixedMath.mul(340282366920938463463374607431768211456, 20) -- internal call\n FixedMath.mul(340282366920938463463374607431768211456, 20) -- internal call -// Warning 6328: (2675-2791): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nTestFixedMath.constructor()\nTestFixedMath.h()\n TestFixedMath.floor(11579208923731619542357098500868790785326998665640564039457584007913129639930) -- internal call\n FixedMath.floor(11579208923731619542357098500868790785326998665640564039457584007913129639930) -- internal call\n TestFixedMath.floor(115792089237316195423570985008687907853269984665640564039457584007913129639935) -- internal call\n FixedMath.floor(115792089237316195423570985008687907853269984665640564039457584007913129639935) -- internal call\n TestFixedMath.floor(11579208923731619542357098500868790785326998665640564039457584007913129639930) -- internal call\n FixedMath.floor(11579208923731619542357098500868790785326998665640564039457584007913129639930) -- internal call -// Warning 6328: (3161-3212): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nTestFixedMath.constructor()\nTestFixedMath.i()\n TestFixedMath.toUFixed256x18(0) -- internal call\n FixedMath.toUFixed256x18(0) -- internal call\n TestFixedMath.toUFixed256x18(5) -- internal call\n FixedMath.toUFixed256x18(5) -- internal call\n TestFixedMath.toUFixed256x18(115792089237316195423570985008687907853269984665640564039457) -- internal call\n FixedMath.toUFixed256x18(115792089237316195423570985008687907853269984665640564039457) -- internal call\n TestFixedMath.toUFixed256x18(5) -- internal call\n FixedMath.toUFixed256x18(5) -- internal call +// Warning 6328: (1886-1970): CHC: Assertion violation happens here. +// Warning 6328: (2165-2266): CHC: Assertion violation happens here. +// Warning 6328: (2675-2791): CHC: Assertion violation happens here. +// Warning 6328: (3161-3212): CHC: Assertion violation happens here. From 098a3cb537db94869157905f5f0af7f4e2558460 Mon Sep 17 00:00:00 2001 From: Leo Alt Date: Wed, 12 Jan 2022 18:42:40 +0100 Subject: [PATCH 52/77] adjust tests for nondeterminism --- .../smtCheckerTests/blockchain_state/balance_receive_2.sol | 5 +++-- .../blockchain_state/balance_receive_ext_calls_2.sol | 2 +- .../smtCheckerTests/external_calls/call_mutex_unsafe.sol | 3 ++- .../external_calls/external_call_with_value_2.sol | 1 + .../external_hash_known_code_state_reentrancy_3.sol | 3 +-- .../external_hash_known_code_state_reentrancy_indirect.sol | 1 + test/libsolidity/smtCheckerTests/file_level/import.sol | 5 +++-- .../operators/assignment_contract_member_variable.sol | 2 +- .../smtCheckerTests/types/address_transfer_insufficient.sol | 3 ++- .../smtCheckerTests/types/mapping_equal_keys_2.sol | 3 ++- .../smtCheckerTests/types/static_array_length_1.sol | 5 +++-- .../types/struct/struct_aliasing_parameter_storage_4.sol | 3 ++- 12 files changed, 22 insertions(+), 14 deletions(-) diff --git a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_2.sol b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_2.sol index bbf91ade4..b611bc95f 100644 --- a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_2.sol +++ b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_2.sol @@ -14,7 +14,8 @@ contract C { } // ==== // SMTEngine: all +// SMTIgnoreCex: yes // ---- -// Warning 4984: (266-272): CHC: Overflow (resulting value larger than 2**256 - 1) happens here.\nCounterexample:\nx = 115792089237316195423570985008687907853269984665640564039457584007913129639926, once = true\n\nTransaction trace:\nC.constructor(){ msg.value: 28100 }\nState: x = 115792089237316195423570985008687907853269984665640564039457584007913129639926, once = false\nC.f(){ msg.value: 8 } -// Warning 6328: (235-273): CHC: Assertion violation happens here.\nCounterexample:\nx = 0, once = true\n\nTransaction trace:\nC.constructor(){ msg.value: 0 }\nState: x = 0, once = false\nC.f(){ msg.value: 2 } +// Warning 4984: (266-272): CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +// Warning 6328: (235-273): CHC: Assertion violation happens here. // Info 1180: Contract invariant(s) for :C:\nonce\n diff --git a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_ext_calls_2.sol b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_ext_calls_2.sol index 28c4734bd..a1eb278bc 100644 --- a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_ext_calls_2.sol +++ b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_ext_calls_2.sol @@ -9,7 +9,7 @@ contract C { // ==== // SMTEngine: all // SMTIgnoreCex: yes +// SMTIgnoreInv: yes // ---- // Warning 9302: (82-93): Return value of low-level calls not used. // Warning 6328: (97-131): CHC: Assertion violation happens here. -// Info 1180: Reentrancy property(ies) for :C:\n((((:var 1).balances[address(this)] + ((- 1) * (:var 0).balances[address(this)])) <= 0) && !( >= 2))\n = 0 -> no errors\n = 1 -> Assertion failed at assert(address(this).balance == x)\n = 2 -> Assertion failed at assert(address(this).balance >= x)\n diff --git a/test/libsolidity/smtCheckerTests/external_calls/call_mutex_unsafe.sol b/test/libsolidity/smtCheckerTests/external_calls/call_mutex_unsafe.sol index ad17e3d05..64494971a 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/call_mutex_unsafe.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/call_mutex_unsafe.sol @@ -21,6 +21,7 @@ contract C { } // ==== // SMTEngine: all +// SMTIgnoreCex: yes // ---- // Warning 9302: (212-228): Return value of low-level calls not used. -// Warning 6328: (232-246): CHC: Assertion violation happens here.\nCounterexample:\nx = 1, lock = false\n_a = 0x0\ny = 0\n\nTransaction trace:\nC.constructor()\nState: x = 0, lock = false\nC.f(0x0)\n _a.call("aaaaa") -- untrusted external call, synthesized as:\n C.set(1) -- reentrant call +// Warning 6328: (232-246): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_2.sol b/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_2.sol index 4b51d9d9e..2b94abc0e 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_2.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_2.sol @@ -12,6 +12,7 @@ contract C { } // ==== // SMTEngine: all +// SMTIgnoreCex: yes // ---- // Warning 6328: (150-186): CHC: Assertion violation might happen here. // Warning 6328: (205-240): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_3.sol b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_3.sol index 508047c39..8372285ee 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_3.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_3.sol @@ -40,5 +40,4 @@ contract C { } // ==== // SMTEngine: all -// ---- -// Info 1180: Contract invariant(s) for :C:\n((insidef || (z <= 0)) && (y <= 0))\nReentrancy property(ies) for :C:\n((!insidef || !( >= 2)) && (insidef' || !insidef) && (!(y <= 0) || (y' <= 0)))\n((!insidef || !( >= 3)) && (insidef' || !insidef))\n = 0 -> no errors\n = 2 -> Assertion failed at assert(z == y)\n = 3 -> Assertion failed at assert(prevOwner == owner)\n +// SMTIgnoreInv: yes diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_indirect.sol b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_indirect.sol index 1fcda01b0..ea9764e17 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_indirect.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_hash_known_code_state_reentrancy_indirect.sol @@ -42,6 +42,7 @@ contract C { // ==== // SMTEngine: all // SMTIgnoreCex: yes +// SMTIgnoreOS: macos // ---- // Warning 1218: (437-463): CHC: Error trying to invoke SMT solver. // Warning 6328: (419-433): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/file_level/import.sol b/test/libsolidity/smtCheckerTests/file_level/import.sol index 85ae71293..7bc2a5445 100644 --- a/test/libsolidity/smtCheckerTests/file_level/import.sol +++ b/test/libsolidity/smtCheckerTests/file_level/import.sol @@ -21,6 +21,7 @@ contract C { } // ==== // SMTEngine: all +// SMTIgnoreCex: yes // ---- -// Warning 6328: (B:238-252): CHC: Assertion violation happens here.\nCounterexample:\ndata = {x: 21238}\nx = 8\ny = 21238\n\nTransaction trace:\nC.constructor()\nState: data = {x: 0}\nC.g()\n C.f(7) -- internal call\n A:set({x: 0}, 7) -- internal call\n A:set({x: 8}, 8) -- internal call -// Warning 6328: (B:308-322): CHC: Assertion violation happens here.\nCounterexample:\ndata = {x: 6}\nx = 0\ny = 6\n\nTransaction trace:\nC.constructor()\nState: data = {x: 0}\nC.g()\n C.f(7) -- internal call\n A:set({x: 0}, 7) -- internal call\n A:set({x: 0}, 8) -- internal call +// Warning 6328: (B:238-252): CHC: Assertion violation happens here. +// Warning 6328: (B:308-322): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/operators/assignment_contract_member_variable.sol b/test/libsolidity/smtCheckerTests/operators/assignment_contract_member_variable.sol index 7a1deafe0..efa29edc1 100644 --- a/test/libsolidity/smtCheckerTests/operators/assignment_contract_member_variable.sol +++ b/test/libsolidity/smtCheckerTests/operators/assignment_contract_member_variable.sol @@ -27,6 +27,6 @@ contract A { // ==== // SMTEngine: all // SMTIgnoreCex: yes +// SMTIgnoreInv: yes // ---- // Warning 6328: (392-408): CHC: Assertion violation happens here. -// Info 1180: Contract invariant(s) for :A:\n(((x = (- 2)) && (y = (- 2))) || ((x = 0) && (y = 0)))\n diff --git a/test/libsolidity/smtCheckerTests/types/address_transfer_insufficient.sol b/test/libsolidity/smtCheckerTests/types/address_transfer_insufficient.sol index 2fcdda175..59568cb5b 100644 --- a/test/libsolidity/smtCheckerTests/types/address_transfer_insufficient.sol +++ b/test/libsolidity/smtCheckerTests/types/address_transfer_insufficient.sol @@ -10,7 +10,8 @@ contract C } // ==== // SMTEngine: all +// SMTIgnoreCex: yes // ---- -// Warning 6328: (180-204): CHC: Assertion violation happens here.\nCounterexample:\n\na = 0x52f6\nb = 0x52f6\n\nTransaction trace:\nC.constructor()\nC.f(0x52f6, 0x52f6) +// Warning 6328: (180-204): CHC: Assertion violation happens here. // Warning 1236: (101-116): BMC: Insufficient funds happens here. // Warning 1236: (120-136): BMC: Insufficient funds happens here. diff --git a/test/libsolidity/smtCheckerTests/types/mapping_equal_keys_2.sol b/test/libsolidity/smtCheckerTests/types/mapping_equal_keys_2.sol index 37e2e4c13..3b8a8846e 100644 --- a/test/libsolidity/smtCheckerTests/types/mapping_equal_keys_2.sol +++ b/test/libsolidity/smtCheckerTests/types/mapping_equal_keys_2.sol @@ -8,5 +8,6 @@ contract C } // ==== // SMTEngine: all +// SMTIgnoreCex: yes // ---- -// Warning 6328: (86-100): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 1\ny = 0\n\nTransaction trace:\nC.constructor()\nC.f(1, 0) +// Warning 6328: (86-100): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/static_array_length_1.sol b/test/libsolidity/smtCheckerTests/types/static_array_length_1.sol index 72bed0f4e..61d18c417 100644 --- a/test/libsolidity/smtCheckerTests/types/static_array_length_1.sol +++ b/test/libsolidity/smtCheckerTests/types/static_array_length_1.sol @@ -7,6 +7,7 @@ contract C { } // ==== // SMTEngine: all +// SMTIgnoreCex: yes // ---- -// Warning 6328: (102-122): CHC: Assertion violation happens here.\nCounterexample:\n\na = [0x09, 0x09]\n\nTransaction trace:\nC.constructor()\nC.f([0x09, 0x09]) -// Warning 6328: (141-161): CHC: Assertion violation happens here.\nCounterexample:\n\na = [0x0a, 0x0a]\n\nTransaction trace:\nC.constructor()\nC.f([0x0a, 0x0a]) +// Warning 6328: (102-122): CHC: Assertion violation happens here. +// Warning 6328: (141-161): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_parameter_storage_4.sol b/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_parameter_storage_4.sol index 957c72c12..618b1172d 100644 --- a/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_parameter_storage_4.sol +++ b/test/libsolidity/smtCheckerTests/types/struct/struct_aliasing_parameter_storage_4.sol @@ -25,5 +25,6 @@ contract C { } // ==== // SMTEngine: all +// SMTIgnoreCex: yes // ---- -// Warning 6328: (305-325): CHC: Assertion violation happens here.\nCounterexample:\nt = {x: 10, s: {innerM, sum: 21239}}\n\nTransaction trace:\nC.constructor(0){ msg.sender: 0x6dc4 }\nState: t = {x: 10, s: {innerM, sum: 21239}}\nC.g() +// Warning 6328: (305-325): CHC: Assertion violation happens here. From 38545e81c1d04a6619260570cf0d644f26bf2683 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 12 Jan 2022 13:09:49 +0100 Subject: [PATCH 53/77] Update docker images to Z3 4.8.14. --- scripts/deps-ppa/static_z3.sh | 4 ++-- scripts/docker/buildpack-deps/Dockerfile.emscripten | 4 ++-- .../docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz | 4 ++-- scripts/docker/buildpack-deps/Dockerfile.ubuntu2004 | 2 +- scripts/docker/buildpack-deps/Dockerfile.ubuntu2004.clang | 2 +- scripts/release_ppa.sh | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/deps-ppa/static_z3.sh b/scripts/deps-ppa/static_z3.sh index 733f9bf3d..353a8a8d9 100755 --- a/scripts/deps-ppa/static_z3.sh +++ b/scripts/deps-ppa/static_z3.sh @@ -25,9 +25,9 @@ set -ev keyid=70D110489D66E2F6 email=builds@ethereum.org packagename=z3-static -version=4.8.13 +version=4.8.14 -DISTRIBUTIONS="focal groovy hirsute impish" +DISTRIBUTIONS="focal hirsute impish jammy" for distribution in $DISTRIBUTIONS do diff --git a/scripts/docker/buildpack-deps/Dockerfile.emscripten b/scripts/docker/buildpack-deps/Dockerfile.emscripten index 5f86b1e19..0d1d1a28e 100644 --- a/scripts/docker/buildpack-deps/Dockerfile.emscripten +++ b/scripts/docker/buildpack-deps/Dockerfile.emscripten @@ -33,12 +33,12 @@ # Using $(em-config CACHE)/sysroot/usr seems to work, though, and still has cmake find the # dependencies automatically. FROM emscripten/emsdk:2.0.33 AS base -LABEL version="8" +LABEL version="9" ADD emscripten.jam /usr/src RUN set -ex; \ cd /usr/src; \ - git clone https://github.com/Z3Prover/z3.git -b z3-4.8.13 --depth 1 ; \ + git clone https://github.com/Z3Prover/z3.git -b z3-4.8.14 --depth 1 ; \ cd z3; \ mkdir build; \ cd build; \ diff --git a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz index 1d00eabce..fb79ea946 100644 --- a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz +++ b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz @@ -22,7 +22,7 @@ # (c) 2016-2021 solidity contributors. #------------------------------------------------------------------------------ FROM gcr.io/oss-fuzz-base/base-clang:latest as base -LABEL version="14" +LABEL version="15" ARG DEBIAN_FRONTEND=noninteractive @@ -61,7 +61,7 @@ RUN set -ex; \ # Z3 RUN set -ex; \ - git clone --depth 1 -b z3-4.8.13 https://github.com/Z3Prover/z3.git \ + git clone --depth 1 -b z3-4.8.14 https://github.com/Z3Prover/z3.git \ /usr/src/z3; \ cd /usr/src/z3; \ mkdir build; \ diff --git a/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004 b/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004 index 8ed35d67e..3ecf9143a 100644 --- a/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004 +++ b/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004 @@ -22,7 +22,7 @@ # (c) 2016-2019 solidity contributors. #------------------------------------------------------------------------------ FROM buildpack-deps:focal AS base -LABEL version="9" +LABEL version="10" ARG DEBIAN_FRONTEND=noninteractive diff --git a/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004.clang b/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004.clang index 0ac9d4abf..d262fa5fa 100644 --- a/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004.clang +++ b/scripts/docker/buildpack-deps/Dockerfile.ubuntu2004.clang @@ -22,7 +22,7 @@ # (c) 2016-2019 solidity contributors. #------------------------------------------------------------------------------ FROM buildpack-deps:focal AS base -LABEL version="9" +LABEL version="10" ARG DEBIAN_FRONTEND=noninteractive diff --git a/scripts/release_ppa.sh b/scripts/release_ppa.sh index 60e931083..725649f80 100755 --- a/scripts/release_ppa.sh +++ b/scripts/release_ppa.sh @@ -57,7 +57,7 @@ packagename=solc static_build_distribution=hirsute -DISTRIBUTIONS="focal hirsute impish" +DISTRIBUTIONS="focal hirsute impish jammy" if is_release then From 78f0be56c3ed7a6c60e39871cdca877644a67afc Mon Sep 17 00:00:00 2001 From: William Entriken Date: Thu, 13 Jan 2022 01:19:03 -0500 Subject: [PATCH 54/77] Document address members code and codehash --- docs/types/value-types.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 49e35d9ea..215a18cee 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -329,6 +329,10 @@ on ``call``. regardless of whether state is read from or written to, as this can have many pitfalls. Also, access to gas might change in the future. +* ``code`` and ``codehash`` + +You can query the deployed code for any smart contract. Use ``code`` to get the EVM bytecode as a string, which might be empty. Use ``codehash`` get the Keccak-256 hash of that code. + .. note:: All contracts can be converted to ``address`` type, so it is possible to query the balance of the current contract using ``address(this).balance``. From 2c4c8264e4428ff45cfd5f8f9b5458f1044ba8aa Mon Sep 17 00:00:00 2001 From: Marenz Date: Wed, 12 Jan 2022 18:58:17 +0100 Subject: [PATCH 55/77] Fix wrong error with immutables when base contract c'tor uses return --- Changelog.md | 1 + libsolidity/analysis/ImmutableValidator.cpp | 25 ++++++++++++------- libsolidity/analysis/ImmutableValidator.h | 5 ++-- .../base_ctor_return_no_immutables.sol | 10 ++++++++ 4 files changed, 30 insertions(+), 11 deletions(-) create mode 100644 test/libsolidity/syntaxTests/immutable/base_ctor_return_no_immutables.sol diff --git a/Changelog.md b/Changelog.md index b83e083d0..bd492e4bf 100644 --- a/Changelog.md +++ b/Changelog.md @@ -11,6 +11,7 @@ Compiler Features: Bugfixes: * Control Flow Graph: Perform proper virtual lookup for modifiers for uninitialized variable and unreachable code analysis. + * Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the parent contract contains immutable variables. Solc-Js: diff --git a/libsolidity/analysis/ImmutableValidator.cpp b/libsolidity/analysis/ImmutableValidator.cpp index e28236fb6..485aa3fa2 100644 --- a/libsolidity/analysis/ImmutableValidator.cpp +++ b/libsolidity/analysis/ImmutableValidator.cpp @@ -29,7 +29,7 @@ void ImmutableValidator::analyze() { m_inCreationContext = true; - auto linearizedContracts = m_currentContract.annotation().linearizedBaseContracts | ranges::views::reverse; + auto linearizedContracts = m_mostDerivedContract.annotation().linearizedBaseContracts | ranges::views::reverse; for (ContractDefinition const* contract: linearizedContracts) for (VariableDeclaration const* stateVar: contract->stateVariables()) @@ -62,7 +62,7 @@ void ImmutableValidator::analyze() visitCallableIfNew(*modDef); } - checkAllVariablesInitialized(m_currentContract.location()); + checkAllVariablesInitialized(m_mostDerivedContract.location()); } bool ImmutableValidator::visit(Assignment const& _assignment) @@ -137,7 +137,7 @@ void ImmutableValidator::endVisit(IdentifierPath const& _identifierPath) if (auto const callableDef = dynamic_cast(_identifierPath.annotation().referencedDeclaration)) visitCallableIfNew( *_identifierPath.annotation().requiredLookup == VirtualLookup::Virtual ? - callableDef->resolveVirtual(m_currentContract) : + callableDef->resolveVirtual(m_mostDerivedContract) : *callableDef ); @@ -147,7 +147,7 @@ void ImmutableValidator::endVisit(IdentifierPath const& _identifierPath) void ImmutableValidator::endVisit(Identifier const& _identifier) { if (auto const callableDef = dynamic_cast(_identifier.annotation().referencedDeclaration)) - visitCallableIfNew(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual ? callableDef->resolveVirtual(m_currentContract) : *callableDef); + visitCallableIfNew(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual ? callableDef->resolveVirtual(m_mostDerivedContract) : *callableDef); if (auto const varDecl = dynamic_cast(_identifier.annotation().referencedDeclaration)) analyseVariableReference(*varDecl, _identifier); } @@ -160,15 +160,18 @@ void ImmutableValidator::endVisit(Return const& _return) bool ImmutableValidator::analyseCallable(CallableDeclaration const& _callableDeclaration) { - FunctionDefinition const* prevConstructor = m_currentConstructor; - m_currentConstructor = nullptr; + ScopedSaveAndRestore constructorGuard{m_currentConstructor, {}}; + ScopedSaveAndRestore constructorContractGuard{m_currentConstructorContract, {}}; if (FunctionDefinition const* funcDef = dynamic_cast(&_callableDeclaration)) { ASTNode::listAccept(funcDef->modifiers(), *this); if (funcDef->isConstructor()) + { + m_currentConstructorContract = funcDef->annotation().contract; m_currentConstructor = funcDef; + } if (funcDef->isImplemented()) funcDef->body().accept(*this); @@ -177,8 +180,6 @@ bool ImmutableValidator::analyseCallable(CallableDeclaration const& _callableDec if (modDef->isImplemented()) modDef->body().accept(*this); - m_currentConstructor = prevConstructor; - return false; } @@ -253,7 +254,8 @@ void ImmutableValidator::analyseVariableReference(VariableDeclaration const& _va void ImmutableValidator::checkAllVariablesInitialized(solidity::langutil::SourceLocation const& _location) { - for (ContractDefinition const* contract: m_currentContract.annotation().linearizedBaseContracts) + for (ContractDefinition const* contract: m_mostDerivedContract.annotation().linearizedBaseContracts | ranges::views::reverse) + { for (VariableDeclaration const* varDecl: contract->stateVariables()) if (varDecl->immutable()) if (!util::contains(m_initializedStateVariables, varDecl)) @@ -263,6 +265,11 @@ void ImmutableValidator::checkAllVariablesInitialized(solidity::langutil::Source solidity::langutil::SecondarySourceLocation().append("Not initialized: ", varDecl->location()), "Construction control flow ends without initializing all immutable state variables." ); + + // Don't check further than the current c'tors contract + if (contract == m_currentConstructorContract) + break; + } } void ImmutableValidator::visitCallableIfNew(Declaration const& _declaration) diff --git a/libsolidity/analysis/ImmutableValidator.h b/libsolidity/analysis/ImmutableValidator.h index e6d837efe..452e91d7c 100644 --- a/libsolidity/analysis/ImmutableValidator.h +++ b/libsolidity/analysis/ImmutableValidator.h @@ -42,7 +42,7 @@ class ImmutableValidator: private ASTConstVisitor public: ImmutableValidator(langutil::ErrorReporter& _errorReporter, ContractDefinition const& _contractDefinition): - m_currentContract(_contractDefinition), + m_mostDerivedContract(_contractDefinition), m_errorReporter(_errorReporter) { } @@ -66,7 +66,7 @@ private: void visitCallableIfNew(Declaration const& _declaration); - ContractDefinition const& m_currentContract; + ContractDefinition const& m_mostDerivedContract; CallableDeclarationSet m_visitedCallables; @@ -74,6 +74,7 @@ private: langutil::ErrorReporter& m_errorReporter; FunctionDefinition const* m_currentConstructor = nullptr; + ContractDefinition const* m_currentConstructorContract = nullptr; bool m_inLoop = false; bool m_inBranch = false; bool m_inCreationContext = true; diff --git a/test/libsolidity/syntaxTests/immutable/base_ctor_return_no_immutables.sol b/test/libsolidity/syntaxTests/immutable/base_ctor_return_no_immutables.sol new file mode 100644 index 000000000..e6e668bc0 --- /dev/null +++ b/test/libsolidity/syntaxTests/immutable/base_ctor_return_no_immutables.sol @@ -0,0 +1,10 @@ +contract Parent { + constructor() { + return; + } +} + +contract Child is Parent { + uint public immutable baked = 123; +} + From f6ca4132b357fc43acb50d2122ab5f6ae7141457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 13 Jan 2022 18:05:45 +0100 Subject: [PATCH 56/77] ens: Remove global solc replacement (only necessary with Truffle) --- test/externalTests/ens.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/test/externalTests/ens.sh b/test/externalTests/ens.sh index 2a539f8fc..d3fcb0b13 100755 --- a/test/externalTests/ens.sh +++ b/test/externalTests/ens.sh @@ -56,7 +56,6 @@ function ens_test setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" download_project "$repo" "$ref_type" "$ref" "$DIR" - [[ $BINARY_TYPE == native ]] && replace_global_solc "$BINARY_PATH" neutralize_package_lock neutralize_package_json_hooks From f7a075bd48340eab881f900caf709d4c5e45e837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 13 Jan 2022 17:46:40 +0100 Subject: [PATCH 57/77] externalTests: Add force_hardhat_unlimited_contract_size --- test/externalTests/common.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/externalTests/common.sh b/test/externalTests/common.sh index 91068d07d..37bd8d74d 100644 --- a/test/externalTests/common.sh +++ b/test/externalTests/common.sh @@ -227,6 +227,26 @@ function force_hardhat_compiler_binary hardhat_solc_build_subtask "$SOLCVERSION_SHORT" "$SOLCVERSION" "$binary_type" "$solc_path" "$language" >> "$config_file" } +function force_hardhat_unlimited_contract_size +{ + local config_file="$1" + local config_var_name="$2" + + printLog "Configuring Hardhat..." + echo "-------------------------------------" + echo "Allow unlimited contract size: true" + echo "-------------------------------------" + + if [[ $config_file == *\.js ]]; then + [[ $config_var_name == "" ]] || assertFail + echo "module.exports.networks.hardhat.allowUnlimitedContractSize = true" >> "$config_file" + else + [[ $config_file == *\.ts ]] || assertFail + [[ $config_var_name != "" ]] || assertFail + echo "${config_var_name}.networks!.hardhat!.allowUnlimitedContractSize = true" >> "$config_file" + fi +} + function force_hardhat_compiler_settings { local config_file="$1" From 054f1cb304cba5c20f4a4a2ef708bdead82a68b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 13 Jan 2022 17:47:00 +0100 Subject: [PATCH 58/77] External test for Euler --- .circleci/config.yml | 7 ++++ test/externalTests.sh | 1 + test/externalTests/euler.sh | 74 +++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100755 test/externalTests/euler.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 56a4af30a..cafe68b78 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1381,6 +1381,13 @@ workflows: binary_type: native # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" nodejs_version: '16' + - t_ems_ext: + <<: *workflow_ubuntu2004_static + name: t_native_test_ext_euler + project: euler + binary_type: native + # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" + nodejs_version: '16' # Windows build and tests - b_win: *workflow_trigger_on_tags diff --git a/test/externalTests.sh b/test/externalTests.sh index 846cdf515..67a5e24ad 100755 --- a/test/externalTests.sh +++ b/test/externalTests.sh @@ -43,3 +43,4 @@ printTask "Running external tests..." "$REPO_ROOT/externalTests/colony.sh" "$@" "$REPO_ROOT/externalTests/ens.sh" "$@" "$REPO_ROOT/externalTests/trident.sh" "$@" +"$REPO_ROOT/externalTests/euler.sh" "$@" diff --git a/test/externalTests/euler.sh b/test/externalTests/euler.sh new file mode 100755 index 000000000..485d7ae56 --- /dev/null +++ b/test/externalTests/euler.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash + +# ------------------------------------------------------------------------------ +# This file is part of solidity. +# +# solidity is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# solidity is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with solidity. If not, see +# +# (c) 2022 solidity contributors. +#------------------------------------------------------------------------------ + +set -e + +source scripts/common.sh +source test/externalTests/common.sh + +verify_input "$@" +BINARY_TYPE="$1" +BINARY_PATH="$2" +SELECTED_PRESETS="$3" + +function compile_fn { npm run compile; } +function test_fn { npx --no hardhat --no-compile test; } + +function euler_test +{ + local repo="https://github.com/euler-xyz/euler-contracts" + local ref_type=branch + local ref="master" + local config_file="hardhat.config.js" + + local compile_only_presets=() + local settings_presets=( + "${compile_only_presets[@]}" + #ir-no-optimize # Compilation fails with "YulException: Variable var_utilisation_307 is 6 slot(s) too deep inside the stack." + #ir-optimize-evm-only # Compilation fails with "YulException: Variable var_utilisation_307 is 6 slot(s) too deep inside the stack." + #ir-optimize-evm+yul # Compilation fails with "YulException: Variable var_status_mpos is 3 too deep in the stack" + legacy-optimize-evm-only + legacy-optimize-evm+yul + legacy-no-optimize + ) + + [[ $SELECTED_PRESETS != "" ]] || SELECTED_PRESETS=$(circleci_select_steps_multiarg "${settings_presets[@]}") + print_presets_or_exit "$SELECTED_PRESETS" + + setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" + download_project "$repo" "$ref_type" "$ref" "$DIR" + + neutralize_package_lock + neutralize_package_json_hooks + force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" + force_hardhat_compiler_settings "$config_file" "$(first_word "$SELECTED_PRESETS")" + force_hardhat_unlimited_contract_size "$config_file" + npm install + + replace_version_pragmas + neutralize_packaged_contracts + + for preset in $SELECTED_PRESETS; do + hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn + done +} + +external_test Euler euler_test From 4de1367ba771a9aebb5a165cea72f2048600b919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 13 Jan 2022 18:44:17 +0100 Subject: [PATCH 59/77] External test for Yield Liquidator V2 --- .circleci/config.yml | 7 +++ test/externalTests.sh | 1 + test/externalTests/yield-liquidator.sh | 74 ++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100755 test/externalTests/yield-liquidator.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index cafe68b78..b23a0db3d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1388,6 +1388,13 @@ workflows: binary_type: native # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" nodejs_version: '16' + - t_ems_ext: + <<: *workflow_ubuntu2004_static + name: t_native_test_ext_yield_liquidator + project: yield-liquidator + binary_type: native + # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" + nodejs_version: '16' # Windows build and tests - b_win: *workflow_trigger_on_tags diff --git a/test/externalTests.sh b/test/externalTests.sh index 67a5e24ad..3b2c0e5bb 100755 --- a/test/externalTests.sh +++ b/test/externalTests.sh @@ -44,3 +44,4 @@ printTask "Running external tests..." "$REPO_ROOT/externalTests/ens.sh" "$@" "$REPO_ROOT/externalTests/trident.sh" "$@" "$REPO_ROOT/externalTests/euler.sh" "$@" +"$REPO_ROOT/externalTests/yield-liquidator.sh" "$@" diff --git a/test/externalTests/yield-liquidator.sh b/test/externalTests/yield-liquidator.sh new file mode 100755 index 000000000..6712941e7 --- /dev/null +++ b/test/externalTests/yield-liquidator.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash + +# ------------------------------------------------------------------------------ +# This file is part of solidity. +# +# solidity is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# solidity is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with solidity. If not, see +# +# (c) 2022 solidity contributors. +#------------------------------------------------------------------------------ + +set -e + +source scripts/common.sh +source test/externalTests/common.sh + +verify_input "$@" +BINARY_TYPE="$1" +BINARY_PATH="$2" +SELECTED_PRESETS="$3" + +function compile_fn { npm run build; } +function test_fn { npm run test; } + +function yield_liquidator_test +{ + local repo="https://github.com/yieldprotocol/yield-liquidator-v2" + local ref_type=branch + local ref="master" + local config_file="hardhat.config.ts" + local config_var="module.exports" + + local compile_only_presets=() + local settings_presets=( + "${compile_only_presets[@]}" + #ir-no-optimize # Compilation fails with "YulException: Variable var_roles_168_mpos is 2 slot(s) too deep inside the stack." + #ir-optimize-evm-only # Compilation fails with "YulException: Variable var__33 is 6 slot(s) too deep inside the stack." + ir-optimize-evm+yul + legacy-optimize-evm-only + legacy-optimize-evm+yul + legacy-no-optimize + ) + + [[ $SELECTED_PRESETS != "" ]] || SELECTED_PRESETS=$(circleci_select_steps_multiarg "${settings_presets[@]}") + print_presets_or_exit "$SELECTED_PRESETS" + + setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" + download_project "$repo" "$ref_type" "$ref" "$DIR" + + neutralize_package_lock + neutralize_package_json_hooks + force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" + force_hardhat_compiler_settings "$config_file" "$(first_word "$SELECTED_PRESETS")" "$config_var" + force_hardhat_unlimited_contract_size "$config_file" "$config_var" + npm install + + replace_version_pragmas + + for preset in $SELECTED_PRESETS; do + hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var" + done +} + +external_test Yield-Liquidator-V2 yield_liquidator_test From 91f51b76c622df691be7251179ac1d97b5f9f74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 14 Jan 2022 22:30:55 +0100 Subject: [PATCH 60/77] CI: Use 'large' resource class for macOS and use -j without spaces --- .circleci/config.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index cafe68b78..e046caeb5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -358,7 +358,15 @@ defaults: xcode: "13.2.0" environment: TERM: xterm - MAKEFLAGS: -j 5 + MAKEFLAGS: -j5 + + - base_osx_large: &base_osx_large + macos: + xcode: "13.2.0" + resource_class: large + environment: + TERM: xterm + MAKEFLAGS: -j10 - base_ems_large: &base_ems_large docker: @@ -794,11 +802,11 @@ jobs: - gitter_notify_failure_unless_pr b_osx: - <<: *base_osx + <<: *base_osx_large environment: TERM: xterm CMAKE_BUILD_TYPE: Release - MAKEFLAGS: -j 5 + MAKEFLAGS: -j10 steps: - checkout - restore_cache: From 1af0ce0f260b515f4def20ada0f6606b211cb852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 13 Jan 2022 23:07:35 +0100 Subject: [PATCH 61/77] External test for Bleeps --- .circleci/config.yml | 8 ++++ test/externalTests.sh | 1 + test/externalTests/bleeps.sh | 84 ++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100755 test/externalTests/bleeps.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index ca2a8fed1..ad19100a3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1403,6 +1403,14 @@ workflows: binary_type: native # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" nodejs_version: '16' + - t_ems_ext: + <<: *workflow_ubuntu2004_static + name: t_native_test_ext_bleeps + project: bleeps + binary_type: native + # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" + nodejs_version: '16' + resource_class: medium # Windows build and tests - b_win: *workflow_trigger_on_tags diff --git a/test/externalTests.sh b/test/externalTests.sh index 3b2c0e5bb..4968f5213 100755 --- a/test/externalTests.sh +++ b/test/externalTests.sh @@ -45,3 +45,4 @@ printTask "Running external tests..." "$REPO_ROOT/externalTests/trident.sh" "$@" "$REPO_ROOT/externalTests/euler.sh" "$@" "$REPO_ROOT/externalTests/yield-liquidator.sh" "$@" +"$REPO_ROOT/externalTests/bleeps.sh" "$@" diff --git a/test/externalTests/bleeps.sh b/test/externalTests/bleeps.sh new file mode 100755 index 000000000..df0e5e39e --- /dev/null +++ b/test/externalTests/bleeps.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash + +# ------------------------------------------------------------------------------ +# This file is part of solidity. +# +# solidity is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# solidity is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with solidity. If not, see +# +# (c) 2022 solidity contributors. +#------------------------------------------------------------------------------ + +set -e + +source scripts/common.sh +source test/externalTests/common.sh + +verify_input "$@" +BINARY_TYPE="$1" +BINARY_PATH="$2" + +function compile_fn { npm run compile; } +function test_fn { npm run test; } + +function bleeps_test +{ + local repo="https://github.com/wighawag/bleeps" + local ref_type=tag + local ref=bleeps_migrations # TODO: There's a 0.4.19 contract in 'main' that would need patching for the latest compiler. + local config_file="hardhat.config.ts" + local config_var=config + + local compile_only_presets=() + local settings_presets=( + "${compile_only_presets[@]}" + #ir-no-optimize # Compilation fails with: "YulException: Variable param_0 is 2 slot(s) too deep inside the stack." + #ir-optimize-evm-only # Compilation fails with: "YulException: Variable param_0 is 2 slot(s) too deep inside the stack." + ir-optimize-evm+yul + #legacy-no-optimize # Compilation fails with: "CompilerError: Stack too deep, try removing local variables." + #legacy-optimize-evm-only # Compilation fails with: "CompilerError: Stack too deep, try removing local variables." + legacy-optimize-evm+yul + ) + + [[ $SELECTED_PRESETS != "" ]] || SELECTED_PRESETS=$(circleci_select_steps_multiarg "${settings_presets[@]}") + print_presets_or_exit "$SELECTED_PRESETS" + + setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" + download_project "$repo" "$ref_type" "$ref" "$DIR" + + pushd "common-lib/" + neutralize_package_json_hooks + npm install + npm run build + popd + + pushd "contracts/" + sed -i 's|"bleeps-common": "workspace:\*",|"bleeps-common": "file:../common-lib/",|g' package.json + + neutralize_package_lock + neutralize_package_json_hooks + force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" + force_hardhat_compiler_settings "$config_file" "$(first_word "$SELECTED_PRESETS")" "$config_var" + npm install npm-run-all + npm install + + replace_version_pragmas + + for preset in $SELECTED_PRESETS; do + hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var" + done + + popd +} + +external_test Bleeps bleeps_test From 0004ad876451e28de1b3aa031ab56d08d2cdb3b1 Mon Sep 17 00:00:00 2001 From: Marenz Date: Wed, 12 Jan 2022 14:12:03 +0100 Subject: [PATCH 62/77] Fix ICE when a constant variable declaration forward references a struct --- Changelog.md | 1 + .../analysis/DeclarationTypeChecker.cpp | 18 ++++++++---------- libsolidity/analysis/TypeChecker.cpp | 9 --------- libsolidity/ast/Types.h | 6 +----- .../constantEvaluator/type_reference.sol | 1 + .../type_reference_in_contract.sol | 1 + .../syntaxTests/constants/mapping_constant.sol | 2 +- .../syntaxTests/constants/struct_constant.sol | 2 +- .../const_struct_with_mapping.sol | 2 +- .../105_constant_input_parameter.sol | 1 + .../171_assignment_to_const_array_vars.sol | 2 +- .../173_constant_struct.sol | 2 +- .../constant_forward_reference_struct.sol | 4 ++++ .../nameAndTypeResolution/constant_mapping.sol | 2 +- .../constant_nested_mapping.sol | 2 +- .../parsing/location_specifiers_for_params.sol | 1 + 16 files changed, 25 insertions(+), 31 deletions(-) create mode 100644 test/libsolidity/syntaxTests/nameAndTypeResolution/constant_forward_reference_struct.sol diff --git a/Changelog.md b/Changelog.md index bd492e4bf..92018a771 100644 --- a/Changelog.md +++ b/Changelog.md @@ -12,6 +12,7 @@ Compiler Features: Bugfixes: * Control Flow Graph: Perform proper virtual lookup for modifiers for uninitialized variable and unreachable code analysis. * Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the parent contract contains immutable variables. + * TypeChecker: Fix ICE when a constant variable declaration forward references a struct. Solc-Js: diff --git a/libsolidity/analysis/DeclarationTypeChecker.cpp b/libsolidity/analysis/DeclarationTypeChecker.cpp index 076155366..7a4aa9942 100644 --- a/libsolidity/analysis/DeclarationTypeChecker.cpp +++ b/libsolidity/analysis/DeclarationTypeChecker.cpp @@ -437,16 +437,14 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable) type = TypeProvider::withLocation(ref, typeLoc, isPointer); } - if ( - _variable.isConstant() && - !dynamic_cast(type) && - type->containsNestedMapping() - ) - m_errorReporter.fatalDeclarationError( - 3530_error, - _variable.location(), - "The type contains a (nested) mapping and therefore cannot be a constant." - ); + if (_variable.isConstant() && !type->isValueType()) + { + bool allowed = false; + if (auto arrayType = dynamic_cast(type)) + allowed = arrayType->isByteArray(); + if (!allowed) + m_errorReporter.fatalTypeError(9259_error, _variable.location(), "Only constants of value type and byte array type are implemented."); + } _variable.annotation().type = type; } diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 94f4b80da..f3ba2884b 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -530,15 +530,6 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) } if (_variable.isConstant()) { - if (!varType->isValueType()) - { - bool allowed = false; - if (auto arrayType = dynamic_cast(varType)) - allowed = arrayType->isByteArray(); - if (!allowed) - m_errorReporter.fatalTypeError(9259_error, _variable.location(), "Constants of non-value type not yet implemented."); - } - if (!_variable.value()) m_errorReporter.typeError(4266_error, _variable.location(), "Uninitialized \"constant\" variable."); else if (!*_variable.value()->annotation().isPure) diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 2f7e6005b..f15da58ab 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -1110,11 +1110,7 @@ public: u256 storageSize() const override { return underlyingType().storageSize(); } unsigned storageBytes() const override { return underlyingType().storageBytes(); } - bool isValueType() const override - { - solAssert(underlyingType().isValueType(), ""); - return true; - } + bool isValueType() const override { return true; } bool nameable() const override { solAssert(underlyingType().nameable(), ""); diff --git a/test/libsolidity/syntaxTests/constantEvaluator/type_reference.sol b/test/libsolidity/syntaxTests/constantEvaluator/type_reference.sol index 585c005f6..f10d01533 100644 --- a/test/libsolidity/syntaxTests/constantEvaluator/type_reference.sol +++ b/test/libsolidity/syntaxTests/constantEvaluator/type_reference.sol @@ -1,3 +1,4 @@ int[L] constant L = 6; // ---- // TypeError 5462: (4-5): Invalid array length, expected integer literal or constant expression. +// TypeError 9259: (0-21): Only constants of value type and byte arrays are implemented. diff --git a/test/libsolidity/syntaxTests/constantEvaluator/type_reference_in_contract.sol b/test/libsolidity/syntaxTests/constantEvaluator/type_reference_in_contract.sol index 9073f6ac1..c95eab19d 100644 --- a/test/libsolidity/syntaxTests/constantEvaluator/type_reference_in_contract.sol +++ b/test/libsolidity/syntaxTests/constantEvaluator/type_reference_in_contract.sol @@ -3,3 +3,4 @@ contract C { } // ---- // TypeError 5462: (21-22): Invalid array length, expected integer literal or constant expression. +// TypeError 9259: (17-38): Only constants of value type and byte arrays are implemented. diff --git a/test/libsolidity/syntaxTests/constants/mapping_constant.sol b/test/libsolidity/syntaxTests/constants/mapping_constant.sol index 4d80fb43e..3ca53d35c 100644 --- a/test/libsolidity/syntaxTests/constants/mapping_constant.sol +++ b/test/libsolidity/syntaxTests/constants/mapping_constant.sol @@ -1,3 +1,3 @@ mapping(uint => uint) constant b = b; // ---- -// DeclarationError 3530: (0-36): The type contains a (nested) mapping and therefore cannot be a constant. +// TypeError 9259: (0-36): Only constants of value type and byte arrays are implemented. diff --git a/test/libsolidity/syntaxTests/constants/struct_constant.sol b/test/libsolidity/syntaxTests/constants/struct_constant.sol index 8d750beb6..fd9d90ff5 100644 --- a/test/libsolidity/syntaxTests/constants/struct_constant.sol +++ b/test/libsolidity/syntaxTests/constants/struct_constant.sol @@ -1,4 +1,4 @@ struct S { uint x; } S constant s; // ---- -// TypeError 9259: (21-33): Constants of non-value type not yet implemented. +// TypeError 9259: (21-33): Only constants of value type and byte arrays are implemented. diff --git a/test/libsolidity/syntaxTests/iceRegressionTests/const_struct_with_mapping.sol b/test/libsolidity/syntaxTests/iceRegressionTests/const_struct_with_mapping.sol index f8e0896c3..79d0f93c6 100644 --- a/test/libsolidity/syntaxTests/iceRegressionTests/const_struct_with_mapping.sol +++ b/test/libsolidity/syntaxTests/iceRegressionTests/const_struct_with_mapping.sol @@ -5,4 +5,4 @@ contract C { S public constant e = 0x1212121212121212121212121212121212121212; } // ---- -// DeclarationError 3530: (71-135): The type contains a (nested) mapping and therefore cannot be a constant. +// TypeError 9259: (71-135): Only constants of value type and byte arrays are implemented. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol index aaf6f620a..9289e5dd8 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol @@ -3,3 +3,4 @@ contract test { } // ---- // DeclarationError 1788: (31-55): The "constant" keyword can only be used for state variables or variables at file level. +// TypeError 9259: (31-55): Only constants of value type and byte arrays are implemented. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/171_assignment_to_const_array_vars.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/171_assignment_to_const_array_vars.sol index 81b9eab8a..db3539b7c 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/171_assignment_to_const_array_vars.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/171_assignment_to_const_array_vars.sol @@ -2,4 +2,4 @@ contract C { uint[3] constant x = [uint(1), 2, 3]; } // ---- -// TypeError 9259: (17-53): Constants of non-value type not yet implemented. +// TypeError 9259: (17-53): Only constants of value type and byte arrays are implemented. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/173_constant_struct.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/173_constant_struct.sol index d32dd2768..24dab2fb2 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/173_constant_struct.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/173_constant_struct.sol @@ -3,4 +3,4 @@ contract C { S constant x = S(5, new uint[](4)); } // ---- -// TypeError 9259: (52-86): Constants of non-value type not yet implemented. +// TypeError 9259: (52-86): Only constants of value type and byte arrays are implemented. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_forward_reference_struct.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_forward_reference_struct.sol new file mode 100644 index 000000000..0c6281c95 --- /dev/null +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_forward_reference_struct.sol @@ -0,0 +1,4 @@ +S constant x; +struct S { int y; } +// ---- +// TypeError 9259: (0-12): Only constants of value type and byte arrays are implemented. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_mapping.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_mapping.sol index 7539a99cb..b2670db79 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_mapping.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_mapping.sol @@ -2,4 +2,4 @@ contract C { mapping(uint => uint) constant x; } // ---- -// DeclarationError 3530: (17-49): The type contains a (nested) mapping and therefore cannot be a constant. +// TypeError 9259: (17-49): Only constants of value type and byte arrays are implemented. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_nested_mapping.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_nested_mapping.sol index 81e6e6b15..dd5ae352c 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_nested_mapping.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_nested_mapping.sol @@ -5,4 +5,4 @@ contract C { S public constant c; } // ---- -// DeclarationError 3530: (71-90): The type contains a (nested) mapping and therefore cannot be a constant. +// TypeError 9259: (71-90): Only constants of value type and byte arrays are implemented. diff --git a/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol b/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol index 7d3dd5640..866c7f427 100644 --- a/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol +++ b/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol @@ -3,3 +3,4 @@ contract Foo { } // ---- // DeclarationError 1788: (30-55): The "constant" keyword can only be used for state variables or variables at file level. +// TypeError 9259: (30-55): Only constants of value type and byte arrays are implemented. From 57d84c8bfb6cad75f13ddfe4a5aee4ed97300f51 Mon Sep 17 00:00:00 2001 From: Marenz Date: Wed, 12 Jan 2022 16:30:04 +0100 Subject: [PATCH 63/77] Fix genetic algorithms CI failure --- .../syntaxTests/constantEvaluator/type_reference.sol | 2 +- .../constantEvaluator/type_reference_in_contract.sol | 2 +- test/libsolidity/syntaxTests/constants/mapping_constant.sol | 2 +- test/libsolidity/syntaxTests/constants/struct_constant.sol | 2 +- .../iceRegressionTests/const_struct_with_mapping.sol | 2 +- .../nameAndTypeResolution/105_constant_input_parameter.sol | 2 +- .../171_assignment_to_const_array_vars.sol | 2 +- .../syntaxTests/nameAndTypeResolution/173_constant_struct.sol | 2 +- .../constant_forward_reference_struct.sol | 2 +- .../syntaxTests/nameAndTypeResolution/constant_mapping.sol | 2 +- .../nameAndTypeResolution/constant_nested_mapping.sol | 2 +- .../syntaxTests/parsing/location_specifiers_for_params.sol | 2 +- test/yulPhaser/GeneticAlgorithms.cpp | 3 +++ 13 files changed, 15 insertions(+), 12 deletions(-) diff --git a/test/libsolidity/syntaxTests/constantEvaluator/type_reference.sol b/test/libsolidity/syntaxTests/constantEvaluator/type_reference.sol index f10d01533..086d89151 100644 --- a/test/libsolidity/syntaxTests/constantEvaluator/type_reference.sol +++ b/test/libsolidity/syntaxTests/constantEvaluator/type_reference.sol @@ -1,4 +1,4 @@ int[L] constant L = 6; // ---- // TypeError 5462: (4-5): Invalid array length, expected integer literal or constant expression. -// TypeError 9259: (0-21): Only constants of value type and byte arrays are implemented. +// TypeError 9259: (0-21): Only constants of value type and byte array type are implemented. diff --git a/test/libsolidity/syntaxTests/constantEvaluator/type_reference_in_contract.sol b/test/libsolidity/syntaxTests/constantEvaluator/type_reference_in_contract.sol index c95eab19d..dfb81378b 100644 --- a/test/libsolidity/syntaxTests/constantEvaluator/type_reference_in_contract.sol +++ b/test/libsolidity/syntaxTests/constantEvaluator/type_reference_in_contract.sol @@ -3,4 +3,4 @@ contract C { } // ---- // TypeError 5462: (21-22): Invalid array length, expected integer literal or constant expression. -// TypeError 9259: (17-38): Only constants of value type and byte arrays are implemented. +// TypeError 9259: (17-38): Only constants of value type and byte array type are implemented. diff --git a/test/libsolidity/syntaxTests/constants/mapping_constant.sol b/test/libsolidity/syntaxTests/constants/mapping_constant.sol index 3ca53d35c..e6b5b124a 100644 --- a/test/libsolidity/syntaxTests/constants/mapping_constant.sol +++ b/test/libsolidity/syntaxTests/constants/mapping_constant.sol @@ -1,3 +1,3 @@ mapping(uint => uint) constant b = b; // ---- -// TypeError 9259: (0-36): Only constants of value type and byte arrays are implemented. +// TypeError 9259: (0-36): Only constants of value type and byte array type are implemented. diff --git a/test/libsolidity/syntaxTests/constants/struct_constant.sol b/test/libsolidity/syntaxTests/constants/struct_constant.sol index fd9d90ff5..9195dac0c 100644 --- a/test/libsolidity/syntaxTests/constants/struct_constant.sol +++ b/test/libsolidity/syntaxTests/constants/struct_constant.sol @@ -1,4 +1,4 @@ struct S { uint x; } S constant s; // ---- -// TypeError 9259: (21-33): Only constants of value type and byte arrays are implemented. +// TypeError 9259: (21-33): Only constants of value type and byte array type are implemented. diff --git a/test/libsolidity/syntaxTests/iceRegressionTests/const_struct_with_mapping.sol b/test/libsolidity/syntaxTests/iceRegressionTests/const_struct_with_mapping.sol index 79d0f93c6..2983b0e71 100644 --- a/test/libsolidity/syntaxTests/iceRegressionTests/const_struct_with_mapping.sol +++ b/test/libsolidity/syntaxTests/iceRegressionTests/const_struct_with_mapping.sol @@ -5,4 +5,4 @@ contract C { S public constant e = 0x1212121212121212121212121212121212121212; } // ---- -// TypeError 9259: (71-135): Only constants of value type and byte arrays are implemented. +// TypeError 9259: (71-135): Only constants of value type and byte array type are implemented. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol index 9289e5dd8..e2ef8518d 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/105_constant_input_parameter.sol @@ -3,4 +3,4 @@ contract test { } // ---- // DeclarationError 1788: (31-55): The "constant" keyword can only be used for state variables or variables at file level. -// TypeError 9259: (31-55): Only constants of value type and byte arrays are implemented. +// TypeError 9259: (31-55): Only constants of value type and byte array type are implemented. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/171_assignment_to_const_array_vars.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/171_assignment_to_const_array_vars.sol index db3539b7c..590cec5a3 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/171_assignment_to_const_array_vars.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/171_assignment_to_const_array_vars.sol @@ -2,4 +2,4 @@ contract C { uint[3] constant x = [uint(1), 2, 3]; } // ---- -// TypeError 9259: (17-53): Only constants of value type and byte arrays are implemented. +// TypeError 9259: (17-53): Only constants of value type and byte array type are implemented. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/173_constant_struct.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/173_constant_struct.sol index 24dab2fb2..6b5e7a13c 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/173_constant_struct.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/173_constant_struct.sol @@ -3,4 +3,4 @@ contract C { S constant x = S(5, new uint[](4)); } // ---- -// TypeError 9259: (52-86): Only constants of value type and byte arrays are implemented. +// TypeError 9259: (52-86): Only constants of value type and byte array type are implemented. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_forward_reference_struct.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_forward_reference_struct.sol index 0c6281c95..d845e735c 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_forward_reference_struct.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_forward_reference_struct.sol @@ -1,4 +1,4 @@ S constant x; struct S { int y; } // ---- -// TypeError 9259: (0-12): Only constants of value type and byte arrays are implemented. +// TypeError 9259: (0-12): Only constants of value type and byte array type are implemented. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_mapping.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_mapping.sol index b2670db79..803cdad53 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_mapping.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_mapping.sol @@ -2,4 +2,4 @@ contract C { mapping(uint => uint) constant x; } // ---- -// TypeError 9259: (17-49): Only constants of value type and byte arrays are implemented. +// TypeError 9259: (17-49): Only constants of value type and byte array type are implemented. diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_nested_mapping.sol b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_nested_mapping.sol index dd5ae352c..2fed9d631 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_nested_mapping.sol +++ b/test/libsolidity/syntaxTests/nameAndTypeResolution/constant_nested_mapping.sol @@ -5,4 +5,4 @@ contract C { S public constant c; } // ---- -// TypeError 9259: (71-90): Only constants of value type and byte arrays are implemented. +// TypeError 9259: (71-90): Only constants of value type and byte array type are implemented. diff --git a/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol b/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol index 866c7f427..c5761a944 100644 --- a/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol +++ b/test/libsolidity/syntaxTests/parsing/location_specifiers_for_params.sol @@ -3,4 +3,4 @@ contract Foo { } // ---- // DeclarationError 1788: (30-55): The "constant" keyword can only be used for state variables or variables at file level. -// TypeError 9259: (30-55): Only constants of value type and byte arrays are implemented. +// TypeError 9259: (30-55): Only constants of value type and byte array type are implemented. diff --git a/test/yulPhaser/GeneticAlgorithms.cpp b/test/yulPhaser/GeneticAlgorithms.cpp index 16d5cc654..29c9cfa2e 100644 --- a/test/yulPhaser/GeneticAlgorithms.cpp +++ b/test/yulPhaser/GeneticAlgorithms.cpp @@ -217,6 +217,9 @@ BOOST_FIXTURE_TEST_CASE(runNextRound_should_select_individuals_with_probability_ { constexpr double relativeTolerance = 0.1; constexpr size_t populationSize = 1000; + + SimulationRNG::reset(1); + assert(populationSize % 4 == 0 && "Choose a number divisible by 4 for this test"); auto population = From 776c984cb03130a8ecbb5c45df2fabfa505e3162 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Thu, 13 Jan 2022 14:55:20 +0100 Subject: [PATCH 64/77] Adjust documentation for linux packages not maintained by us. --- docs/installing-solidity.rst | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst index d3f9015a2..438c1afa9 100644 --- a/docs/installing-solidity.rst +++ b/docs/installing-solidity.rst @@ -118,8 +118,17 @@ The nightly version can be installed using these commands: sudo apt-get update sudo apt-get install solc -We are also releasing a `snap package `_, which is -installable in all the `supported Linux distros `_. To +Furthermore, some Linux distributions provide their own packages. These packages are not directly +maintained by us, but usually kept up-to-date by the respective package maintainers. + +For example, Arch Linux has packages for the latest development version: + +.. code-block:: bash + + pacman -S solidity + +There is also a `snap package `_, however, it is **currently unmaintained**. +It is installable in all the `supported Linux distros `_. To install the latest stable version of solc: .. code-block:: bash @@ -139,18 +148,6 @@ with the most recent changes, please use the following: but it comes with limitations, like accessing only the files in your ``/home`` and ``/media`` directories. For more information, go to `Demystifying Snap Confinement `_. -Arch Linux also has packages, albeit limited to the latest development version: - -.. code-block:: bash - - pacman -S solidity - -Gentoo Linux has an `Ethereum overlay `_ that contains a Solidity package. -After the overlay is setup, ``solc`` can be installed in x86_64 architectures by: - -.. code-block:: bash - - emerge dev-lang/solidity macOS Packages ============== From 7c0a121e456b966826afe575929bad225aa0cb15 Mon Sep 17 00:00:00 2001 From: Marenz Date: Mon, 17 Jan 2022 17:09:14 +0100 Subject: [PATCH 65/77] Natspec: Fix ICE when overriding a struct getter with a Natspec-documented return value and the name in the struct is different. --- Changelog.md | 1 + libsolidity/analysis/DocStringAnalyser.cpp | 35 +++++++------- libsolidity/analysis/DocStringAnalyser.h | 3 +- test/libsolidity/SolidityNatspecJSON.cpp | 54 +++++++++++++++++++++- 4 files changed, 73 insertions(+), 20 deletions(-) diff --git a/Changelog.md b/Changelog.md index 92018a771..4723b1039 100644 --- a/Changelog.md +++ b/Changelog.md @@ -12,6 +12,7 @@ Compiler Features: Bugfixes: * Control Flow Graph: Perform proper virtual lookup for modifiers for uninitialized variable and unreachable code analysis. * Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the parent contract contains immutable variables. + * Natspec: Fix ICE when overriding a struct getter with a Natspec-documented return value and the name in the struct is different. * TypeChecker: Fix ICE when a constant variable declaration forward references a struct. diff --git a/libsolidity/analysis/DocStringAnalyser.cpp b/libsolidity/analysis/DocStringAnalyser.cpp index 018c10f58..5cff34f2a 100644 --- a/libsolidity/analysis/DocStringAnalyser.cpp +++ b/libsolidity/analysis/DocStringAnalyser.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -37,7 +38,7 @@ using namespace solidity::frontend; namespace { -void copyMissingTags(set const& _baseFunctions, StructurallyDocumentedAnnotation& _target, CallableDeclaration const* _declaration = nullptr) +void copyMissingTags(set const& _baseFunctions, StructurallyDocumentedAnnotation& _target, FunctionType const* _functionType = nullptr) { // Only copy if there is exactly one direct base function. if (_baseFunctions.size() != 1) @@ -45,12 +46,6 @@ void copyMissingTags(set const& _baseFunctions, Stru CallableDeclaration const& baseFunction = **_baseFunctions.begin(); - auto hasReturnParameter = [](CallableDeclaration const& declaration, size_t _n) - { - return declaration.returnParameterList() && - declaration.returnParameters().size() > _n; - }; - auto& sourceDoc = dynamic_cast(baseFunction.annotation()); for (auto it = sourceDoc.docTags.begin(); it != sourceDoc.docTags.end();) @@ -70,21 +65,22 @@ void copyMissingTags(set const& _baseFunctions, Stru DocTag content = it->second; // Update the parameter name for @return tags - if (_declaration && tag == "return") + if (_functionType && tag == "return") { size_t docParaNameEndPos = content.content.find_first_of(" \t"); string const docParameterName = content.content.substr(0, docParaNameEndPos); if ( - hasReturnParameter(*_declaration, n) && - docParameterName != _declaration->returnParameters().at(n)->name() + _functionType->returnParameterNames().size() > n && + docParameterName != _functionType->returnParameterNames().at(n) ) { bool baseHasNoName = - hasReturnParameter(baseFunction, n) && + baseFunction.returnParameterList() && + baseFunction.returnParameters().size() > n && baseFunction.returnParameters().at(n)->name().empty(); - string paramName = _declaration->returnParameters().at(n)->name(); + string paramName = _functionType->returnParameterNames().at(n); content.content = (paramName.empty() ? "" : std::move(paramName) + " ") + ( string::npos == docParaNameEndPos || baseHasNoName ? @@ -127,7 +123,7 @@ bool DocStringAnalyser::analyseDocStrings(SourceUnit const& _sourceUnit) bool DocStringAnalyser::visit(FunctionDefinition const& _function) { if (!_function.isConstructor()) - handleCallable(_function, _function, _function.annotation()); + handleCallable(_function, _function, _function.annotation(), TypeProvider::function(_function)); return true; } @@ -136,10 +132,12 @@ bool DocStringAnalyser::visit(VariableDeclaration const& _variable) if (!_variable.isStateVariable() && !_variable.isFileLevelVariable()) return false; + auto const* getterType = TypeProvider::function(_variable); + if (CallableDeclaration const* baseFunction = resolveInheritDoc(_variable.annotation().baseFunctions, _variable, _variable.annotation())) - copyMissingTags({baseFunction}, _variable.annotation()); + copyMissingTags({baseFunction}, _variable.annotation(), getterType); else if (_variable.annotation().docTags.empty()) - copyMissingTags(_variable.annotation().baseFunctions, _variable.annotation()); + copyMissingTags(_variable.annotation().baseFunctions, _variable.annotation(), getterType); return false; } @@ -168,17 +166,18 @@ bool DocStringAnalyser::visit(ErrorDefinition const& _error) void DocStringAnalyser::handleCallable( CallableDeclaration const& _callable, StructurallyDocumented const& _node, - StructurallyDocumentedAnnotation& _annotation + StructurallyDocumentedAnnotation& _annotation, + FunctionType const* _functionType ) { if (CallableDeclaration const* baseFunction = resolveInheritDoc(_callable.annotation().baseFunctions, _node, _annotation)) - copyMissingTags({baseFunction}, _annotation, &_callable); + copyMissingTags({baseFunction}, _annotation, _functionType); else if ( _annotation.docTags.empty() && _callable.annotation().baseFunctions.size() == 1 && parameterNamesEqual(_callable, **_callable.annotation().baseFunctions.begin()) ) - copyMissingTags(_callable.annotation().baseFunctions, _annotation, &_callable); + copyMissingTags(_callable.annotation().baseFunctions, _annotation, _functionType); } CallableDeclaration const* DocStringAnalyser::resolveInheritDoc( diff --git a/libsolidity/analysis/DocStringAnalyser.h b/libsolidity/analysis/DocStringAnalyser.h index 1fa076359..d9cd6f09d 100644 --- a/libsolidity/analysis/DocStringAnalyser.h +++ b/libsolidity/analysis/DocStringAnalyser.h @@ -54,7 +54,8 @@ private: void handleCallable( CallableDeclaration const& _callable, StructurallyDocumented const& _node, - StructurallyDocumentedAnnotation& _annotation + StructurallyDocumentedAnnotation& _annotation, + FunctionType const* _functionType = nullptr ); langutil::ErrorReporter& m_errorReporter; diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index 6ee55d586..af04d0795 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -2482,7 +2482,7 @@ BOOST_AUTO_TEST_CASE(custom_inheritance) checkNatspec(sourceCode, "B", natspecB, false); } -BOOST_AUTO_TEST_CASE(dev_different_amount_return_parameters) +BOOST_AUTO_TEST_CASE(dev_struct_getter_override) { char const *sourceCode = R"( interface IThing { @@ -2534,6 +2534,58 @@ BOOST_AUTO_TEST_CASE(dev_different_amount_return_parameters) checkNatspec(sourceCode, "Thing", natspec2, false); } +BOOST_AUTO_TEST_CASE(dev_struct_getter_override_different_return_parameter_names) +{ + char const *sourceCode = R"( + interface IThing { + /// @return x a number + /// @return y another number + function value() external view returns (uint128 x, uint128 y); + } + + contract Thing is IThing { + struct Value { + uint128 a; + uint128 b; + } + + Value public override value; + } + )"; + + char const *natspec = R"ABCDEF({ + "methods": + { + "value()": + { + "returns": + { + "x": "a number", + "y": "another number" + } + } + } + })ABCDEF"; + + char const *natspec2 = R"ABCDEF({ + "methods": {}, + "stateVariables": + { + "value": + { + "returns": + { + "a": "a number", + "b": "another number" + } + } + } + })ABCDEF"; + + checkNatspec(sourceCode, "IThing", natspec, false); + checkNatspec(sourceCode, "Thing", natspec2, false); +} + } BOOST_AUTO_TEST_SUITE_END() From 2d0f6278bbe9a740e715ee9acbc83eec0bca68e9 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 17 Jan 2022 18:39:18 +0100 Subject: [PATCH 66/77] Allow builtins as yul identifier paths in antlr grammar. --- Changelog.md | 1 + docs/grammar/SolidityParser.g4 | 2 +- .../inlineAssembly/assignment_to_function_pointer.sol | 9 +++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 test/libsolidity/syntaxTests/inlineAssembly/assignment_to_function_pointer.sol diff --git a/Changelog.md b/Changelog.md index bd492e4bf..39e844387 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,6 +10,7 @@ Compiler Features: Bugfixes: + * Antlr Grammar: Allow builtin names in ``yulPath`` to support ``.address`` in function pointers. * Control Flow Graph: Perform proper virtual lookup for modifiers for uninitialized variable and unreachable code analysis. * Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the parent contract contains immutable variables. diff --git a/docs/grammar/SolidityParser.g4 b/docs/grammar/SolidityParser.g4 index f7630c59e..110773fed 100644 --- a/docs/grammar/SolidityParser.g4 +++ b/docs/grammar/SolidityParser.g4 @@ -564,7 +564,7 @@ yulFunctionDefinition: * While only identifiers without dots can be declared within inline assembly, * paths containing dots can refer to declarations outside the inline assembly block. */ -yulPath: YulIdentifier (YulPeriod YulIdentifier)*; +yulPath: YulIdentifier (YulPeriod (YulIdentifier | YulEVMBuiltin))*; /** * A call to a function with return values can only occur as right-hand side of an assignment or * a variable declaration. diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assignment_to_function_pointer.sol b/test/libsolidity/syntaxTests/inlineAssembly/assignment_to_function_pointer.sol new file mode 100644 index 000000000..d29a74890 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/assignment_to_function_pointer.sol @@ -0,0 +1,9 @@ +contract C { + function f() public pure { + function() external g; + assembly { + g.address := 0x42 + g.selector := 0x23 + } + } +} From 31cf7f7adbd40732f3522a2f4eedd5ce0874f215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 22 Dec 2021 13:55:29 +0100 Subject: [PATCH 67/77] CI: Create templates for parameterized jobs to make it easier to reuse them in multiple workflows --- .circleci/config.yml | 176 +++++++++++++++++++++++-------------------- 1 file changed, 96 insertions(+), 80 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ad19100a3..ed9c2ca05 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -475,6 +475,91 @@ defaults: requires: - b_win_release + # -------------------------------------------------------------------------- + # Parameterized Job Templates + + # Separate compile-only runs of those external tests where a full run takes much longer. + - job_ems_compile_ext_colony: &job_ems_compile_ext_colony + <<: *workflow_emscripten + name: t_ems_compile_ext_colony + project: colony + binary_type: solcjs + compile_only: 1 + nodejs_version: '14' + - job_native_compile_ext_gnosis: &job_native_compile_ext_gnosis + <<: *workflow_ubuntu2004_static + name: t_native_compile_ext_gnosis + project: gnosis + binary_type: native + compile_only: 1 + nodejs_version: '14' + + - job_native_test_ext_gnosis: &job_native_test_ext_gnosis + <<: *workflow_emscripten + name: t_native_test_ext_gnosis + project: gnosis + binary_type: native + # NOTE: Tests do not start on node.js 14 ("ganache-cli exited early with code 1"). + nodejs_version: '12' + - job_native_test_ext_gnosis_v2: &job_native_test_ext_gnosis_v2 + <<: *workflow_ubuntu2004_static + name: t_native_test_ext_gnosis_v2 + project: gnosis-v2 + binary_type: native + # NOTE: Tests do not start on node.js 14 ("ganache-cli exited early with code 1"). + nodejs_version: '12' + - job_native_test_ext_zeppelin: &job_native_test_ext_zeppelin + <<: *workflow_ubuntu2004_static + name: t_native_test_ext_zeppelin + project: zeppelin + binary_type: native + # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" + nodejs_version: '16' + resource_class: large + - job_native_test_ext_ens: &job_native_test_ext_ens + <<: *workflow_ubuntu2004_static + name: t_native_test_ext_ens + project: ens + binary_type: native + # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" + nodejs_version: '16' + - job_native_test_ext_trident: &job_native_test_ext_trident + <<: *workflow_ubuntu2004_static + name: t_native_test_ext_trident + project: trident + binary_type: native + # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" + nodejs_version: '16' + - job_native_test_ext_euler: &job_native_test_ext_euler + <<: *workflow_ubuntu2004_static + name: t_native_test_ext_euler + project: euler + binary_type: native + # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" + nodejs_version: '16' + - job_native_test_ext_yield_liquidator: &job_native_test_ext_yield_liquidator + <<: *workflow_ubuntu2004_static + name: t_native_test_ext_yield_liquidator + project: yield-liquidator + binary_type: native + # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" + nodejs_version: '16' + - job_native_test_ext_bleeps: &job_native_test_ext_bleeps + <<: *workflow_ubuntu2004_static + name: t_native_test_ext_bleeps + project: bleeps + binary_type: native + # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" + nodejs_version: '16' + resource_class: medium + - job_ems_test_ext_colony: &job_ems_test_ext_colony + <<: *workflow_emscripten + name: t_ems_test_ext_colony + project: colony + binary_type: solcjs + nodejs_version: '14' + resource_class: medium + # ----------------------------------------------------------------------------------------------- jobs: @@ -1335,82 +1420,19 @@ workflows: - t_ems_solcjs: *workflow_emscripten - t_ems_ext_hardhat: *workflow_emscripten - # Separate compile-only runs of those external tests where a full run takes much longer. - - t_ems_ext: - <<: *workflow_emscripten - name: t_ems_compile_ext_colony - project: colony - binary_type: solcjs - compile_only: 1 - nodejs_version: '14' - - t_ems_ext: - <<: *workflow_ubuntu2004_static - name: t_native_compile_ext_gnosis - project: gnosis - binary_type: native - compile_only: 1 - nodejs_version: '14' + - t_ems_ext: *job_ems_compile_ext_colony + - t_ems_ext: *job_native_compile_ext_gnosis # FIXME: Gnosis tests are pretty flaky right now. They often fail on CircleCI due to random ProviderError # and there are also other less frequent problems. See https://github.com/gnosis/safe-contracts/issues/216. - #- t_ems_ext: - # <<: *workflow_emscripten - # name: t_native_test_ext_gnosis - # project: gnosis - # binary_type: native - # # NOTE: Tests do not start on node.js 14 ("ganache-cli exited early with code 1"). - # nodejs_version: '12' - - t_ems_ext: - <<: *workflow_ubuntu2004_static - name: t_native_test_ext_gnosis_v2 - project: gnosis-v2 - binary_type: native - # NOTE: Tests do not start on node.js 14 ("ganache-cli exited early with code 1"). - nodejs_version: '12' - - t_ems_ext: - <<: *workflow_ubuntu2004_static - name: t_native_test_ext_zeppelin - project: zeppelin - binary_type: native - # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" - nodejs_version: '16' - resource_class: large - - t_ems_ext: - <<: *workflow_ubuntu2004_static - name: t_native_test_ext_ens - project: ens - binary_type: native - # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" - nodejs_version: '16' - - t_ems_ext: - <<: *workflow_ubuntu2004_static - name: t_native_test_ext_trident - project: trident - binary_type: native - # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" - nodejs_version: '16' - - t_ems_ext: - <<: *workflow_ubuntu2004_static - name: t_native_test_ext_euler - project: euler - binary_type: native - # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" - nodejs_version: '16' - - t_ems_ext: - <<: *workflow_ubuntu2004_static - name: t_native_test_ext_yield_liquidator - project: yield-liquidator - binary_type: native - # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" - nodejs_version: '16' - - t_ems_ext: - <<: *workflow_ubuntu2004_static - name: t_native_test_ext_bleeps - project: bleeps - binary_type: native - # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" - nodejs_version: '16' - resource_class: medium + #-t_ems_ext: *job_native_test_ext_gnosis + - t_ems_ext: *job_native_test_ext_gnosis_v2 + - t_ems_ext: *job_native_test_ext_zeppelin + - t_ems_ext: *job_native_test_ext_ens + - t_ems_ext: *job_native_test_ext_trident + - t_ems_ext: *job_native_test_ext_euler + - t_ems_ext: *job_native_test_ext_yield_liquidator + - t_ems_ext: *job_native_test_ext_bleeps # Windows build and tests - b_win: *workflow_trigger_on_tags @@ -1471,10 +1493,4 @@ workflows: # Emscripten build and tests that take more than 15 minutes to execute - b_ems: *workflow_trigger_on_tags - - t_ems_ext: - <<: *workflow_emscripten - name: t_ems_test_ext_colony - project: colony - binary_type: solcjs - nodejs_version: '14' - resource_class: medium + - t_ems_ext: *job_ems_test_ext_colony From b1e7964ad533c400e9e5c623e8e9f81c85c03648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 22 Dec 2021 17:43:37 +0100 Subject: [PATCH 68/77] CI: Add missing workflow_trigger_on_tags filter to bytecode jobs --- .circleci/config.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index ed9c2ca05..b53bdb72b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1442,18 +1442,23 @@ workflows: # Bytecode comparison: - b_bytecode_ubu: + <<: *workflow_trigger_on_tags requires: - b_ubu - b_bytecode_win: + <<: *workflow_trigger_on_tags requires: - b_win - b_bytecode_osx: + <<: *workflow_trigger_on_tags requires: - b_osx - b_bytecode_ems: + <<: *workflow_trigger_on_tags requires: - b_ems - t_bytecode_compare: + <<: *workflow_trigger_on_tags requires: - b_bytecode_ubu - b_bytecode_win From c91f995ec9aa389fb3c0b0b98bbb836deb8cc353 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 17 Jan 2022 20:12:11 +0100 Subject: [PATCH 69/77] Update test/libsolidity/syntaxTests/inlineAssembly/assignment_to_function_pointer.sol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kamil Śliwak --- .../assignment_to_function_pointer.sol | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/libsolidity/syntaxTests/inlineAssembly/assignment_to_function_pointer.sol b/test/libsolidity/syntaxTests/inlineAssembly/assignment_to_function_pointer.sol index d29a74890..38e88eeeb 100644 --- a/test/libsolidity/syntaxTests/inlineAssembly/assignment_to_function_pointer.sol +++ b/test/libsolidity/syntaxTests/inlineAssembly/assignment_to_function_pointer.sol @@ -1,9 +1,9 @@ contract C { - function f() public pure { - function() external g; - assembly { - g.address := 0x42 - g.selector := 0x23 + function f() public pure { + function() external g; + assembly { + g.address := 0x42 + g.selector := 0x23 + } } - } } From 89d6bff72afe8cf1a3eb6e1590e6419e1fea9f42 Mon Sep 17 00:00:00 2001 From: Marenz Date: Tue, 18 Jan 2022 15:21:48 +0100 Subject: [PATCH 70/77] Fix .push() not considering external functions --- Changelog.md | 1 + libsolidity/codegen/YulUtilFunctions.cpp | 2 +- .../viaYul/copy_struct_invalid_ir_bug.sol | 28 +++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 test/libsolidity/semanticTests/viaYul/copy_struct_invalid_ir_bug.sol diff --git a/Changelog.md b/Changelog.md index bb20bd813..597a6a70a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -13,6 +13,7 @@ Bugfixes: * Antlr Grammar: Allow builtin names in ``yulPath`` to support ``.address`` in function pointers. * Control Flow Graph: Perform proper virtual lookup for modifiers for uninitialized variable and unreachable code analysis. * Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the parent contract contains immutable variables. + * IR Generator: Fix IR syntax error when copying storage arrays of structs containing functions. * Natspec: Fix ICE when overriding a struct getter with a Natspec-documented return value and the name in the struct is different. * TypeChecker: Fix ICE when a constant variable declaration forward references a struct. diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 106ad260f..2327250b2 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -3608,7 +3608,7 @@ string YulUtilFunctions::copyStructToStorageFunction(StructType const& _from, St auto const& [srcSlotOffset, srcOffset] = _from.storageOffsetsOfMember(structMembers[i].name); t("memberOffset", formatNumber(srcSlotOffset)); if (memberType.isValueType()) - t("read", readFromStorageValueType(memberType, srcOffset, false)); + t("read", readFromStorageValueType(memberType, srcOffset, true)); else solAssert(srcOffset == 0, ""); diff --git a/test/libsolidity/semanticTests/viaYul/copy_struct_invalid_ir_bug.sol b/test/libsolidity/semanticTests/viaYul/copy_struct_invalid_ir_bug.sol new file mode 100644 index 000000000..70e3a34d4 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/copy_struct_invalid_ir_bug.sol @@ -0,0 +1,28 @@ +contract C { + struct Struct { + function () external el; + } + Struct[] array; + int externalCalled = 0; + + function ext() external { + externalCalled++; + } + + function f() public { + array.push(Struct(this.ext)); + array.push(array[0]); + + array[0].el(); + array[1].el(); + + assert(externalCalled == 2); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> +// gas irOptimized: 113142 +// gas legacy: 112937 +// gas legacyOptimized: 112608 From a0d6c118604dd20896601b3c85344c8882da1d4a Mon Sep 17 00:00:00 2001 From: nishant-sachdeva Date: Thu, 16 Dec 2021 17:05:39 +0530 Subject: [PATCH 71/77] Equality operator allowed for external function types --- Changelog.md | 1 + libsolidity/ast/Types.cpp | 12 ++- libsolidity/codegen/ExpressionCompiler.cpp | 26 +++++- libsolidity/codegen/YulUtilFunctions.cpp | 29 +++++++ libsolidity/codegen/YulUtilFunctions.h | 3 + .../codegen/ir/IRGeneratorForStatements.cpp | 26 ++++-- ...or_external_function_cleans_dirty_bits.sol | 17 ++++ ...rison_operators_for_external_functions.sol | 81 +++++++++++++++++++ ...xternal_functions_with_extra_gas_slots.sol | 12 +++ ...nternal_and_external_function_pointers.sol | 23 ++++++ ...al_functions_with_different_parameters.sol | 26 ++++++ 11 files changed, 244 insertions(+), 12 deletions(-) create mode 100644 test/libsolidity/semanticTests/functionTypes/comparison_operator_for_external_function_cleans_dirty_bits.sol create mode 100644 test/libsolidity/semanticTests/functionTypes/comparison_operators_for_external_functions.sol create mode 100644 test/libsolidity/syntaxTests/functionTypes/comparison_operator_for_external_functions_with_extra_gas_slots.sol create mode 100644 test/libsolidity/syntaxTests/functionTypes/comparison_operators_between_internal_and_external_function_pointers.sol create mode 100644 test/libsolidity/syntaxTests/functionTypes/comparison_operators_external_functions_with_different_parameters.sol diff --git a/Changelog.md b/Changelog.md index bb20bd813..d8e9d8f40 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ Language Features: * General: Support ``ContractName.functionName`` for ``abi.encodeCall``, in addition to external function pointers. + * General: Add equality-comparison operators for external function types. Compiler Features: diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index da2811a21..fb31a9303 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -3018,8 +3018,18 @@ TypeResult FunctionType::binaryOperatorResult(Token _operator, Type const* _othe if (_other->category() != category() || !(_operator == Token::Equal || _operator == Token::NotEqual)) return nullptr; FunctionType const& other = dynamic_cast(*_other); - if (kind() == Kind::Internal && other.kind() == Kind::Internal && sizeOnStack() == 1 && other.sizeOnStack() == 1) + if (kind() == Kind::Internal && sizeOnStack() == 1 && other.kind() == Kind::Internal && other.sizeOnStack() == 1) return commonType(this, _other); + else if ( + kind() == Kind::External && + sizeOnStack() == 2 && + !bound() && + other.kind() == Kind::External && + other.sizeOnStack() == 2 && + !other.bound() + ) + return commonType(this, _other); + return nullptr; } diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 34a9a1ee8..b14a032c4 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -2278,12 +2278,29 @@ void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryO void ExpressionCompiler::appendCompareOperatorCode(Token _operator, Type const& _type) { - solAssert(_type.sizeOnStack() == 1, "Comparison of multi-slot types."); if (_operator == Token::Equal || _operator == Token::NotEqual) { - if (FunctionType const* funType = dynamic_cast(&_type)) + FunctionType const* functionType = dynamic_cast(&_type); + if (functionType && functionType->kind() == FunctionType::Kind::External) { - if (funType->kind() == FunctionType::Kind::Internal) + solUnimplementedAssert(functionType->sizeOnStack() == 2, ""); + m_context << Instruction::SWAP3; + + m_context << ((u256(1) << 160) - 1) << Instruction::AND; + m_context << Instruction::SWAP1; + m_context << ((u256(1) << 160) - 1) << Instruction::AND; + m_context << Instruction::EQ; + m_context << Instruction::SWAP2; + m_context << ((u256(1) << 32) - 1) << Instruction::AND; + m_context << Instruction::SWAP1; + m_context << ((u256(1) << 32) - 1) << Instruction::AND; + m_context << Instruction::EQ; + m_context << Instruction::AND; + } + else + { + solAssert(_type.sizeOnStack() == 1, "Comparison of multi-slot types."); + if (functionType && functionType->kind() == FunctionType::Kind::Internal) { // We have to remove the upper bits (construction time value) because they might // be "unknown" in one of the operands and not in the other. @@ -2291,13 +2308,14 @@ void ExpressionCompiler::appendCompareOperatorCode(Token _operator, Type const& m_context << Instruction::SWAP1; m_context << ((u256(1) << 32) - 1) << Instruction::AND; } + m_context << Instruction::EQ; } - m_context << Instruction::EQ; if (_operator == Token::NotEqual) m_context << Instruction::ISZERO; } else { + solAssert(_type.sizeOnStack() == 1, "Comparison of multi-slot types."); bool isSigned = false; if (auto type = dynamic_cast(&_type)) isSigned = type->isSigned(); diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 106ad260f..cbe8b8204 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -29,6 +29,7 @@ #include #include #include +#include using namespace std; using namespace solidity; @@ -4548,3 +4549,31 @@ string YulUtilFunctions::externalCodeFunction() .render(); }); } + +std::string YulUtilFunctions::externalFunctionPointersEqualFunction() +{ + std::string const functionName = "externalFunctionPointersEqualFunction"; + return m_functionCollector.createFunction(functionName, [&]() { + return util::Whiskers(R"( + function ( + leftAddress, + leftSelector, + rightAddress, + rightSelector + ) -> result { + result := and( + eq( + (leftAddress), (rightAddress) + ), + eq( + (leftSelector), (rightSelector) + ) + ) + } + )") + ("functionName", functionName) + ("addressCleanUpFunction", cleanupFunction(*TypeProvider::address())) + ("selectorCleanUpFunction", cleanupFunction(*TypeProvider::uint(32))) + .render(); + }); +} diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index a03ee75c2..52d672b1f 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -522,6 +522,9 @@ public: /// Signature: (address) -> mpos std::string externalCodeFunction(); + /// @return the name of a function that that checks if two external functions pointers are equal or not + std::string externalFunctionPointersEqualFunction(); + private: /// @returns the name of a function that copies a struct from calldata or memory to storage /// signature: (slot, value) -> diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index d35685037..24d695d39 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -799,13 +799,8 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) if (TokenTraits::isCompareOp(op)) { - if (auto type = dynamic_cast(commonType)) - { - solAssert(op == Token::Equal || op == Token::NotEqual, "Invalid function pointer comparison!"); - solAssert(type->kind() != FunctionType::Kind::External, "External function comparison not allowed!"); - } - solAssert(commonType->isValueType(), ""); + bool isSigned = false; if (auto type = dynamic_cast(commonType)) isSigned = type->isSigned(); @@ -813,8 +808,25 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) string args = expressionAsType(_binOp.leftExpression(), *commonType, true); args += ", " + expressionAsType(_binOp.rightExpression(), *commonType, true); + auto functionType = dynamic_cast(commonType); + solAssert(functionType ? (op == Token::Equal || op == Token::NotEqual) : true, "Invalid function pointer comparison!"); + string expr; - if (op == Token::Equal) + + if (functionType && functionType->kind() == FunctionType::Kind::External) + { + solUnimplementedAssert(functionType->sizeOnStack() == 2, ""); + expr = m_utils.externalFunctionPointersEqualFunction() + + "(" + + IRVariable{_binOp.leftExpression()}.part("address").name() + "," + + IRVariable{_binOp.leftExpression()}.part("functionSelector").name() + "," + + IRVariable{_binOp.rightExpression()}.part("address").name() + "," + + IRVariable{_binOp.rightExpression()}.part("functionSelector").name() + + ")"; + if (op == Token::NotEqual) + expr = "iszero(" + expr + ")"; + } + else if (op == Token::Equal) expr = "eq(" + move(args) + ")"; else if (op == Token::NotEqual) expr = "iszero(eq(" + move(args) + "))"; diff --git a/test/libsolidity/semanticTests/functionTypes/comparison_operator_for_external_function_cleans_dirty_bits.sol b/test/libsolidity/semanticTests/functionTypes/comparison_operator_for_external_function_cleans_dirty_bits.sol new file mode 100644 index 000000000..3347d9b77 --- /dev/null +++ b/test/libsolidity/semanticTests/functionTypes/comparison_operator_for_external_function_cleans_dirty_bits.sol @@ -0,0 +1,17 @@ +contract C { + function g() external {} + function comparison_operators_for_external_function_pointers_with_dirty_bits() external returns (bool) { + function() external g_ptr_dirty = this.g; + assembly { + g_ptr_dirty.address := or(g_ptr_dirty.address, shl(160, sub(0,1))) + g_ptr_dirty.selector := or(g_ptr_dirty.selector, shl(32, sub(0,1))) + } + function() external g_ptr = this.g; + return g_ptr == g_ptr_dirty; + } +} +// ==== +// compileViaYul: also +// EVMVersion: >=constantinople +// ---- +// comparison_operators_for_external_function_pointers_with_dirty_bits() -> true diff --git a/test/libsolidity/semanticTests/functionTypes/comparison_operators_for_external_functions.sol b/test/libsolidity/semanticTests/functionTypes/comparison_operators_for_external_functions.sol new file mode 100644 index 000000000..da75ea071 --- /dev/null +++ b/test/libsolidity/semanticTests/functionTypes/comparison_operators_for_external_functions.sol @@ -0,0 +1,81 @@ +contract C { + function f() external {} + function g() external {} + function h() pure external {} + function i() view external {} + + function comparison_operators_for_external_functions() public returns (bool) { + assert( + this.f != this.g && + this.f != this.h && + this.f != this.i && + + this.g != this.h && + this.g != this.i && + + this.h != this.i && + + this.f == this.f && + this.g == this.g && + this.h == this.h && + this.i == this.i + ); + return true; + } + + function comparison_operators_for_local_external_function_pointers() public returns (bool) { + function () external f_local = this.f; + function () external g_local = this.g; + function () external pure h_local = this.h; + function () external view i_local = this.i; + + assert( + f_local == this.f && + g_local == this.g && + h_local == this.h && + i_local == this.i && + + f_local != this.g && + f_local != this.h && + f_local != this.i && + + g_local != this.f && + g_local != this.h && + g_local != this.i && + + h_local != this.f && + h_local != this.g && + h_local != this.i && + + i_local != this.f && + i_local != this.g && + i_local != this.h + ); + + assert( + f_local == f_local && + f_local != g_local && + f_local != h_local && + f_local != i_local + ); + + assert( + g_local == g_local && + g_local != h_local && + g_local != i_local + ); + + assert( + h_local == h_local && + i_local == i_local && + h_local != i_local + ); + + return true; + } +} +// ==== +// compileViaYul: also +// ---- +// comparison_operators_for_external_functions() -> true +// comparison_operators_for_local_external_function_pointers() -> true diff --git a/test/libsolidity/syntaxTests/functionTypes/comparison_operator_for_external_functions_with_extra_gas_slots.sol b/test/libsolidity/syntaxTests/functionTypes/comparison_operator_for_external_functions_with_extra_gas_slots.sol new file mode 100644 index 000000000..7b0713caf --- /dev/null +++ b/test/libsolidity/syntaxTests/functionTypes/comparison_operator_for_external_functions_with_extra_gas_slots.sol @@ -0,0 +1,12 @@ +contract C { + function external_test_function() external {} + function comparison_operator_for_external_function_with_extra_slots() external returns (bool) { + return ( + (this.external_test_function{gas: 4} == this.external_test_function) && + (this.external_test_function{gas: 4} == this.external_test_function{gas: 4}) + ); + } +} +// ---- +// TypeError 2271: (193-259): Operator == not compatible with types function () external and function () external +// TypeError 2271: (277-351): Operator == not compatible with types function () external and function () external diff --git a/test/libsolidity/syntaxTests/functionTypes/comparison_operators_between_internal_and_external_function_pointers.sol b/test/libsolidity/syntaxTests/functionTypes/comparison_operators_between_internal_and_external_function_pointers.sol new file mode 100644 index 000000000..19f44658f --- /dev/null +++ b/test/libsolidity/syntaxTests/functionTypes/comparison_operators_between_internal_and_external_function_pointers.sol @@ -0,0 +1,23 @@ +contract C { + function external_test_function() external {} + function internal_test_function() internal {} + + function comparison_operator_between_internal_and_external_function_pointers() external returns (bool) { + function () external external_function_pointer_local = this.external_test_function; + function () internal internal_function_pointer_local = internal_test_function; + + assert( + this.external_test_function == external_function_pointer_local && + internal_function_pointer_local == internal_test_function + ); + assert( + internal_function_pointer_local != external_function_pointer_local && + internal_test_function != this.external_test_function + ); + + return true; + } +} +// ---- +// TypeError 2271: (606-672): Operator != not compatible with types function () and function () external +// TypeError 2271: (688-741): Operator != not compatible with types function () and function () external diff --git a/test/libsolidity/syntaxTests/functionTypes/comparison_operators_external_functions_with_different_parameters.sol b/test/libsolidity/syntaxTests/functionTypes/comparison_operators_external_functions_with_different_parameters.sol new file mode 100644 index 000000000..39381f454 --- /dev/null +++ b/test/libsolidity/syntaxTests/functionTypes/comparison_operators_external_functions_with_different_parameters.sol @@ -0,0 +1,26 @@ +contract C { + function external_test_function1(uint num) external {} + function external_test_function2(bool val) external {} + + function comparison_operator_between_internal_and_external_function_pointers() external returns (bool) { + function () external external_function_pointer_local1 = this.external_test_function1; + function () external external_function_pointer_local2 = this.external_test_function2; + + assert( + this.external_test_function1 == external_function_pointer_local1 && + this.external_test_function2 == external_function_pointer_local2 + ); + assert( + external_function_pointer_local2 != external_function_pointer_local1 && + this.external_test_function2 != this.external_test_function1 + ); + + return true; + } +} +// ---- +// TypeError 9574: (249-333): Type function (uint256) external is not implicitly convertible to expected type function () external. +// TypeError 9574: (343-427): Type function (bool) external is not implicitly convertible to expected type function () external. +// TypeError 2271: (458-522): Operator == not compatible with types function (uint256) external and function () external +// TypeError 2271: (538-602): Operator == not compatible with types function (bool) external and function () external +// TypeError 2271: (726-786): Operator != not compatible with types function (bool) external and function (uint256) external From 6d05912d70086c6e86012bb7dc67677c95a027cc Mon Sep 17 00:00:00 2001 From: Marenz Date: Wed, 19 Jan 2022 14:30:47 +0100 Subject: [PATCH 72/77] Require strict parsing for natspec JSON tests --- test/libsolidity/SolidityNatspecJSON.cpp | 110 ++++++++++++++--------- 1 file changed, 66 insertions(+), 44 deletions(-) diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index af04d0795..ebd109be9 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -56,7 +56,8 @@ public: else generatedDocumentation = m_compilerStack.natspecDev(_contractName); Json::Value expectedDocumentation; - util::jsonParseStrict(_expectedDocumentationString, expectedDocumentation); + std::string parseError; + BOOST_REQUIRE_MESSAGE(util::jsonParseStrict(_expectedDocumentationString, expectedDocumentation, &parseError), parseError); expectedDocumentation["version"] = Json::Value(Natspec::c_natspecVersion); expectedDocumentation["kind"] = Json::Value(_userDocumentation ? "user" : "dev"); @@ -185,18 +186,27 @@ BOOST_AUTO_TEST_CASE(dev_and_user_basic_test) } )"; - char const* devNatspec = "{" - "\"methods\":{" - " \"mul(uint256)\":{ \n" - " \"details\": \"Multiplies a number by 7\"\n" - " }\n" - " }\n" - "}}"; + char const* devNatspec = R"R( + { + "methods" : + { + "mul(uint256)": + { + "details": "Multiplies a number by 7" + } + } + })R"; - char const* userNatspec = "{" - "\"methods\":{" - " \"mul(uint256)\":{ \"notice\": \"Multiplies `a` by 7\"}" - "}}"; + char const* userNatspec = R"R( + { + "methods" : + { + "mul(uint256)": + { + "notice": "Multiplies `a` by 7" + } + } + })R"; checkNatspec(sourceCode, "test", devNatspec, false); checkNatspec(sourceCode, "test", userNatspec, true); @@ -636,7 +646,7 @@ BOOST_AUTO_TEST_CASE(dev_return_no_params) { "methods": { "mul(uint256,uint256)": { - "returns": { "d": "The result of the multiplication" + "returns": { "d": "The result of the multiplication" } } } })ABCDEF"; @@ -866,19 +876,23 @@ BOOST_AUTO_TEST_CASE(dev_multiline_return) } )"; - char const* natspec = "{" - "\"methods\":{" - " \"mul(uint256,uint256)\":{ \n" - " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" - " \"params\": {\n" - " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" - " \"second\": \"Documentation for the second parameter\"\n" - " },\n" - " \"returns\": {\n" - " \"d\": \"The result of the multiplication and cookies with nutella\",\n" - " }\n" - " }\n" - "}}"; + char const* natspec = R"R({ + "methods": + { + "mul(uint256,uint256)": { + "details": "Multiplies a number by 7 and adds second parameter", + "params": + { + "a": "Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines", + "second": "Documentation for the second parameter" + }, + "returns": + { + "d": "The result of the multiplication and cookies with nutella" + } + } + } + })R"; checkNatspec(sourceCode, "test", natspec, false); } @@ -901,19 +915,25 @@ BOOST_AUTO_TEST_CASE(dev_multiline_comment) } )"; - char const* natspec = "{" - "\"methods\":{" - " \"mul(uint256,uint256)\":{ \n" - " \"details\": \"Multiplies a number by 7 and adds second parameter\",\n" - " \"params\": {\n" - " \"a\": \"Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines\",\n" - " \"second\": \"Documentation for the second parameter\"\n" - " },\n" - " \"returns\": {\n" - " \"d\": \"The result of the multiplication and cookies with nutella\",\n" - " }\n" - " }\n" - "}}"; + char const* natspec = R"R( + { + "methods": + { + "mul(uint256,uint256)": + { + "details": "Multiplies a number by 7 and adds second parameter", + "params": + { + "a": "Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines", + "second": "Documentation for the second parameter" + }, + "returns": + { + "d": "The result of the multiplication and cookies with nutella" + } + } + } + })R"; checkNatspec(sourceCode, "test", natspec, false); } @@ -2295,7 +2315,7 @@ BOOST_AUTO_TEST_CASE(dev_return_name_no_description) { "returns": { - "a": "a", + "a": "a" } } } @@ -2308,7 +2328,7 @@ BOOST_AUTO_TEST_CASE(dev_return_name_no_description) { "returns": { - "b": "a", + "b": "a" } } } @@ -2465,7 +2485,8 @@ BOOST_AUTO_TEST_CASE(custom_inheritance) } )"; - char const* natspecA = R"ABCDEF({ + char const* natspecA = R"ABCDEF( + { "methods": { "g(uint256)": @@ -2473,8 +2494,9 @@ BOOST_AUTO_TEST_CASE(custom_inheritance) "custom:since": "2014" } } - )ABCDEF"; - char const* natspecB = R"ABCDEF({ + })ABCDEF"; + char const* natspecB = R"ABCDEF( + { "methods": {} })ABCDEF"; From be7c7dd4a9102336d595312c0d43a1bbd2790ce8 Mon Sep 17 00:00:00 2001 From: Marenz Date: Wed, 19 Jan 2022 15:35:05 +0100 Subject: [PATCH 73/77] Make formatting more consistent in natspec tests --- test/libsolidity/SolidityNatspecJSON.cpp | 234 +++++++++++++---------- 1 file changed, 130 insertions(+), 104 deletions(-) diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index ebd109be9..29796922e 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -119,7 +119,8 @@ BOOST_AUTO_TEST_CASE(user_newline_break) char const* natspec = R"ABCDEF( { - "methods": { + "methods": + { "f()": { "notice": "world" @@ -147,8 +148,10 @@ BOOST_AUTO_TEST_CASE(user_multiline_empty_lines) char const* natspec = R"ABCDEF( { - "methods": { - "f()": { + "methods": + { + "f()": + { "notice": "hello world" } } @@ -188,7 +191,7 @@ BOOST_AUTO_TEST_CASE(dev_and_user_basic_test) char const* devNatspec = R"R( { - "methods" : + "methods": { "mul(uint256)": { @@ -199,7 +202,7 @@ BOOST_AUTO_TEST_CASE(dev_and_user_basic_test) char const* userNatspec = R"R( { - "methods" : + "methods": { "mul(uint256)": { @@ -307,16 +310,16 @@ BOOST_AUTO_TEST_CASE(public_state_variable) char const* devDoc = R"R( { - "methods" : {}, - "stateVariables" : + "methods": {}, + "stateVariables": { - "state" : + "state": { - "details" : "example of dev", - "return" : "returns state", - "returns" : + "details": "example of dev", + "return": "returns state", + "returns": { - "_0" : "returns state" + "_0": "returns state" } } } @@ -326,9 +329,9 @@ BOOST_AUTO_TEST_CASE(public_state_variable) char const* userDoc = R"R( { - "methods" : + "methods": { - "state()" : + "state()": { "notice": "example of notice" } @@ -356,15 +359,15 @@ BOOST_AUTO_TEST_CASE(public_state_variable_struct) char const* devDoc = R"R( { - "methods" : {}, - "stateVariables" : + "methods": {}, + "stateVariables": { - "coinStack" : + "coinStack": { - "returns" : + "returns": { - "observeGraphicURL" : "Front pic", - "reverseGraphicURL" : "Back pic" + "observeGraphicURL": "Front pic", + "reverseGraphicURL": "Back pic" } } } @@ -374,9 +377,9 @@ BOOST_AUTO_TEST_CASE(public_state_variable_struct) char const* userDoc = R"R( { - "methods" : + "methods": { - "coinStack(uint256)" : + "coinStack(uint256)": { "notice": "Get the n-th coin I own" } @@ -416,12 +419,12 @@ BOOST_AUTO_TEST_CASE(private_state_variable) char const* devDoc = R"( { - "methods" : {}, - "stateVariables" : + "methods": {}, + "stateVariables": { - "state" : + "state": { - "details" : "example of dev" + "details": "example of dev" } } } @@ -644,8 +647,10 @@ BOOST_AUTO_TEST_CASE(dev_return_no_params) char const* natspec = R"ABCDEF( { - "methods": { - "mul(uint256,uint256)": { + "methods": + { + "mul(uint256,uint256)": + { "returns": { "d": "The result of the multiplication" } } } @@ -879,7 +884,8 @@ BOOST_AUTO_TEST_CASE(dev_multiline_return) char const* natspec = R"R({ "methods": { - "mul(uint256,uint256)": { + "mul(uint256,uint256)": + { "details": "Multiplies a number by 7 and adds second parameter", "params": { @@ -1024,13 +1030,14 @@ BOOST_AUTO_TEST_CASE(natspec_notice_without_tag) char const* natspec = R"ABCDEF( { - "methods" : { - "mul(uint256)" : { - "notice" : "I do something awesome" - } - } - } - )ABCDEF"; + "methods": + { + "mul(uint256)": + { + "notice": "I do something awesome" + } + } + })ABCDEF"; checkNatspec(sourceCode, "test", natspec, true); } @@ -1047,11 +1054,13 @@ BOOST_AUTO_TEST_CASE(natspec_multiline_notice_without_tag) char const* natspec = R"ABCDEF( { - "methods" : { - "mul(uint256)" : { - "notice" : "I do something awesome which requires two lines to explain" - } - } + "methods": + { + "mul(uint256)": + { + "notice": "I do something awesome which requires two lines to explain" + } + } } )ABCDEF"; @@ -1067,7 +1076,7 @@ BOOST_AUTO_TEST_CASE(empty_comment) )"; char const* natspec = R"ABCDEF( { - "methods" : {} + "methods": {} } )ABCDEF"; @@ -1155,8 +1164,10 @@ BOOST_AUTO_TEST_CASE(user_constructor) )"; char const* natspec = R"ABCDEF({ - "methods": { - "constructor" : { + "methods": + { + "constructor": + { "notice": "this is a really nice constructor" } } @@ -1177,12 +1188,15 @@ BOOST_AUTO_TEST_CASE(user_constructor_and_function) )"; char const* natspec = R"ABCDEF({ - "methods" : { - "mul(uint256,uint256)" : { - "notice" : "another multiplier" + "methods": + { + "mul(uint256,uint256)": + { + "notice": "another multiplier" }, - "constructor" : { - "notice" : "this is a really nice constructor" + "constructor": + { + "notice": "this is a really nice constructor" } } })ABCDEF"; @@ -1201,11 +1215,14 @@ BOOST_AUTO_TEST_CASE(dev_constructor) )"; char const *natspec = R"ABCDEF({ - "methods" : { - "constructor" : { - "params" : { - "a" : "the parameter a is really nice and very useful", - "second" : "the second parameter is not very useful, it just provides additional confusion" + "methods": + { + "constructor": + { + "params": + { + "a": "the parameter a is really nice and very useful", + "second": "the second parameter is not very useful, it just provides additional confusion" } } } @@ -1248,21 +1265,27 @@ BOOST_AUTO_TEST_CASE(dev_constructor_and_function) )"; char const *natspec = R"ABCDEF({ - "methods" : { - "mul(uint256,uint256)" : { - "details" : "Multiplies a number by 7 and adds second parameter", - "params" : { - "a" : "Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines", - "second" : "Documentation for the second parameter" + "methods": + { + "mul(uint256,uint256)": + { + "details": "Multiplies a number by 7 and adds second parameter", + "params": + { + "a": "Documentation for the first parameter starts here. Since it's a really complicated parameter we need 2 lines", + "second": "Documentation for the second parameter" }, - "returns" : { + "returns": + { "d": "The result of the multiplication and cookies with nutella" } }, - "constructor" : { - "params" : { - "a" : "the parameter a is really nice and very useful", - "second" : "the second parameter is not very useful, it just provides additional confusion" + "constructor": + { + "params": + { + "a": "the parameter a is really nice and very useful", + "second": "the second parameter is not very useful, it just provides additional confusion" } } } @@ -1312,7 +1335,8 @@ BOOST_AUTO_TEST_CASE(slash3_slash3) )"; char const* natspec = R"ABCDEF({ - "methods": { + "methods": + { "f()": { "notice": "lorem ipsum" } } })ABCDEF"; @@ -1331,7 +1355,8 @@ BOOST_AUTO_TEST_CASE(slash3_slash4) )"; char const* natspec = R"ABCDEF({ - "methods": { + "methods": + { "f()": { "notice": "lorem" } } })ABCDEF"; @@ -1360,12 +1385,12 @@ BOOST_AUTO_TEST_CASE(dev_default_inherit_variable) })ABCDEF"; char const *natspec1 = R"ABCDEF({ - "methods" : {}, - "stateVariables" : + "methods": {}, + "stateVariables": { - "x" : + "x": { - "details" : "test" + "details": "test" } } })ABCDEF"; @@ -1426,12 +1451,12 @@ BOOST_AUTO_TEST_CASE(dev_explicit_inherit_variable) })ABCDEF"; char const *natspec1 = R"ABCDEF({ - "methods" : {}, - "stateVariables" : + "methods": {}, + "stateVariables": { - "x" : + "x": { - "details" : "test" + "details": "test" } } })ABCDEF"; @@ -1487,7 +1512,7 @@ BOOST_AUTO_TEST_CASE(dev_default_inherit) function transfer(address to, uint amount) virtual override external returns (bool) { return false; - } + } } contract Token is Middle { @@ -1533,8 +1558,8 @@ BOOST_AUTO_TEST_CASE(user_default_inherit) contract Middle is ERC20 { function transfer(address to, uint amount) virtual override external returns (bool) { - return false; - } + return false; + } } contract Token is Middle { @@ -2353,11 +2378,11 @@ BOOST_AUTO_TEST_CASE(error) char const* devdoc = R"X({ "errors":{ "E(uint256,uint256)": [{ - "details" : "an error.", - "params" : + "details": "an error.", + "params": { - "a" : "first parameter", - "b" : "second parameter" + "a": "first parameter", + "b": "second parameter" } }] }, @@ -2369,7 +2394,7 @@ BOOST_AUTO_TEST_CASE(error) char const* userdoc = R"X({ "errors":{ "E(uint256,uint256)": [{ - "notice" : "Something failed." + "notice": "Something failed." }] }, "methods": {} @@ -2404,22 +2429,23 @@ BOOST_AUTO_TEST_CASE(error_multiple) char const* devdoc = R"X({ "methods": {}, - "errors": { + "errors": + { "E(uint256,uint256)": [ { - "details" : "an error.", - "params" : + "details": "an error.", + "params": { - "x" : "first parameter", - "y" : "second parameter" + "x": "first parameter", + "y": "second parameter" } }, { - "details" : "X an error.", - "params" : + "details": "X an error.", + "params": { - "a" : "X first parameter", - "b" : "X second parameter" + "a": "X first parameter", + "b": "X second parameter" } } ] @@ -2431,8 +2457,8 @@ BOOST_AUTO_TEST_CASE(error_multiple) char const* userdoc = R"X({ "errors":{ "E(uint256,uint256)": [ - { "notice" : "Something failed." }, - { "notice" : "X Something failed." } + { "notice": "Something failed." }, + { "notice": "X Something failed." } ] }, "methods": {} @@ -2528,11 +2554,11 @@ BOOST_AUTO_TEST_CASE(dev_struct_getter_override) { "value()": { - "returns": - { - "x": "a number", - "y": "another number" - } + "returns": + { + "x": "a number", + "y": "another number" + } } } })ABCDEF"; @@ -2580,11 +2606,11 @@ BOOST_AUTO_TEST_CASE(dev_struct_getter_override_different_return_parameter_names { "value()": { - "returns": - { - "x": "a number", - "y": "another number" - } + "returns": + { + "x": "a number", + "y": "another number" + } } } })ABCDEF"; From 93f7d5f8f0be28d84158a6ccde7fd7d2050598d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 19 Jan 2022 17:02:20 +0100 Subject: [PATCH 74/77] External tests for Pool Together v4 --- .circleci/config.yml | 8 +++ test/externalTests.sh | 1 + test/externalTests/pool-together.sh | 78 +++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100755 test/externalTests/pool-together.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index b53bdb72b..0813fe576 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -552,6 +552,13 @@ defaults: # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" nodejs_version: '16' resource_class: medium + - job_native_test_ext_pool_together: &job_native_test_ext_pool_together + <<: *workflow_ubuntu2004_static + name: t_native_test_ext_pool_together + project: pool-together + binary_type: native + # NOTE: Tests crash on nodejs 17: "Error: error:0308010C:digital envelope routines::unsupported" + nodejs_version: '16' - job_ems_test_ext_colony: &job_ems_test_ext_colony <<: *workflow_emscripten name: t_ems_test_ext_colony @@ -1433,6 +1440,7 @@ workflows: - t_ems_ext: *job_native_test_ext_euler - t_ems_ext: *job_native_test_ext_yield_liquidator - t_ems_ext: *job_native_test_ext_bleeps + - t_ems_ext: *job_native_test_ext_pool_together # Windows build and tests - b_win: *workflow_trigger_on_tags diff --git a/test/externalTests.sh b/test/externalTests.sh index 4968f5213..560ca2744 100755 --- a/test/externalTests.sh +++ b/test/externalTests.sh @@ -46,3 +46,4 @@ printTask "Running external tests..." "$REPO_ROOT/externalTests/euler.sh" "$@" "$REPO_ROOT/externalTests/yield-liquidator.sh" "$@" "$REPO_ROOT/externalTests/bleeps.sh" "$@" +"$REPO_ROOT/externalTests/pool-together.sh" "$@" diff --git a/test/externalTests/pool-together.sh b/test/externalTests/pool-together.sh new file mode 100755 index 000000000..1cabd6a50 --- /dev/null +++ b/test/externalTests/pool-together.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash + +# ------------------------------------------------------------------------------ +# This file is part of solidity. +# +# solidity is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# solidity is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with solidity. If not, see +# +# (c) 2022 solidity contributors. +#------------------------------------------------------------------------------ + +set -e + +source scripts/common.sh +source test/externalTests/common.sh + +verify_input "$@" +BINARY_TYPE="$1" +BINARY_PATH="$2" +SELECTED_PRESETS="$3" + +function compile_fn { yarn compile; } +function test_fn { yarn test; } + +function pool_together_test +{ + local repo="https://github.com/pooltogether/v4-core" + local ref_type=branch + local ref=master + local config_file="hardhat.config.ts" + local config_var="config" + + local compile_only_presets=() + local settings_presets=( + "${compile_only_presets[@]}" + #ir-no-optimize # Compilation fails with "YulException: Variable var_amount_205 is 9 slot(s) too deep inside the stack." + #ir-optimize-evm-only # Compilation fails with "YulException: Variable var_amount_205 is 9 slot(s) too deep inside the stack." + #ir-optimize-evm+yul # FIXME: ICE due to https://github.com/ethereum/solidity/issues/12558 + legacy-no-optimize + legacy-optimize-evm-only + legacy-optimize-evm+yul + ) + + [[ $SELECTED_PRESETS != "" ]] || SELECTED_PRESETS=$(circleci_select_steps_multiarg "${settings_presets[@]}") + print_presets_or_exit "$SELECTED_PRESETS" + + setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" + download_project "$repo" "$ref_type" "$ref" "$DIR" + + neutralize_package_lock + neutralize_package_json_hooks + force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" + force_hardhat_compiler_settings "$config_file" "$(first_word "$SELECTED_PRESETS")" "$config_var" + yarn install + + # These come with already compiled artifacts. We want them recompiled with latest compiler. + rm -r node_modules/@pooltogether/yield-source-interface/artifacts/ + rm -r node_modules/@pooltogether/uniform-random-number/artifacts/ + rm -r node_modules/@pooltogether/owner-manager-contracts/artifacts/ + + replace_version_pragmas + + for preset in $SELECTED_PRESETS; do + hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var" + done +} + +external_test Pool-Together-V4 pool_together_test From 27d0480e9615bd2347eef6c6aaf17d3b3874b216 Mon Sep 17 00:00:00 2001 From: nishant-sachdeva Date: Wed, 19 Jan 2022 21:00:40 +0530 Subject: [PATCH 75/77] Adding Stack Height Checker and modifying the number of POP instructions to appropriately provide the pointer address --- Changelog.md | 1 + libsolidity/codegen/ExpressionCompiler.cpp | 6 +++-- ...eck_on_adding_gas_variable_to_function.sol | 25 +++++++++++++++++++ ...ns_with_variable_number_of_stack_slots.sol | 8 ++++++ 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 test/libsolidity/semanticTests/functionTypes/stack_height_check_on_adding_gas_variable_to_function.sol create mode 100644 test/libsolidity/syntaxTests/functionTypes/external_functions_with_variable_number_of_stack_slots.sol diff --git a/Changelog.md b/Changelog.md index d751eb4bf..0f7c3f29e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -17,6 +17,7 @@ Bugfixes: * IR Generator: Fix IR syntax error when copying storage arrays of structs containing functions. * Natspec: Fix ICE when overriding a struct getter with a Natspec-documented return value and the name in the struct is different. * TypeChecker: Fix ICE when a constant variable declaration forward references a struct. + * Code Generator: Fix ICE when accessing the members of external functions occupying more than two stack slots. Solc-Js: diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index b14a032c4..a76d1f3d9 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1760,6 +1760,9 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) case Type::Category::Function: if (member == "selector") { + auto const& functionType = dynamic_cast(*_memberAccess.expression().annotation().type); + if (functionType.kind() == FunctionType::Kind::External) + CompilerUtils(m_context).popStackSlots(functionType.sizeOnStack() - 2); m_context << Instruction::SWAP1 << Instruction::POP; /// need to store it as bytes4 utils().leftShiftNumberOnStack(224); @@ -1768,8 +1771,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) { auto const& functionType = dynamic_cast(*_memberAccess.expression().annotation().type); solAssert(functionType.kind() == FunctionType::Kind::External, ""); - // stack:
- m_context << Instruction::POP; + CompilerUtils(m_context).popStackSlots(functionType.sizeOnStack() - 1); } else solAssert( diff --git a/test/libsolidity/semanticTests/functionTypes/stack_height_check_on_adding_gas_variable_to_function.sol b/test/libsolidity/semanticTests/functionTypes/stack_height_check_on_adding_gas_variable_to_function.sol new file mode 100644 index 000000000..5726860b9 --- /dev/null +++ b/test/libsolidity/semanticTests/functionTypes/stack_height_check_on_adding_gas_variable_to_function.sol @@ -0,0 +1,25 @@ +contract C { + function g() external {} + function h() external payable {} + function test_function() external returns (bool){ + assert ( + this.g.address == this.g.address && + this.g{gas: 42}.address == this.g.address && + this.g{gas: 42}.selector == this.g.selector + ); + assert ( + this.h.address == this.h.address && + this.h{gas: 42}.address == this.h.address && + this.h{gas: 42}.selector == this.h.selector + ); + assert ( + this.h{gas: 42, value: 5}.address == this.h.address && + this.h{gas: 42, value: 5}.selector == this.h.selector + ); + return true; + } +} +// ==== +// compileViaYul: also +// ---- +// test_function() -> true diff --git a/test/libsolidity/syntaxTests/functionTypes/external_functions_with_variable_number_of_stack_slots.sol b/test/libsolidity/syntaxTests/functionTypes/external_functions_with_variable_number_of_stack_slots.sol new file mode 100644 index 000000000..8593bdbf4 --- /dev/null +++ b/test/libsolidity/syntaxTests/functionTypes/external_functions_with_variable_number_of_stack_slots.sol @@ -0,0 +1,8 @@ +contract C { + function f (address) external returns (bool) { + this.f{gas: 42}.address; + } +} +// ---- +// Warning 6321: (56-60): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable. +// Warning 2018: (17-102): Function state mutability can be restricted to view From a550048cf058ac7a20e2c4ac07c962de74474e30 Mon Sep 17 00:00:00 2001 From: Marenz Date: Thu, 20 Jan 2022 14:53:18 +0100 Subject: [PATCH 76/77] Fix too strict assert for calldata string -> bytes conversions --- Changelog.md | 3 ++- libsolidity/codegen/CompilerUtils.cpp | 5 ++++- libsolidity/codegen/YulUtilFunctions.cpp | 5 ++++- .../explicit_string_bytes_calldata_cast.sol | 11 +++++++++++ 4 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 test/libsolidity/semanticTests/viaYul/conversion/explicit_string_bytes_calldata_cast.sol diff --git a/Changelog.md b/Changelog.md index 0f7c3f29e..93b940839 100644 --- a/Changelog.md +++ b/Changelog.md @@ -12,12 +12,13 @@ Compiler Features: Bugfixes: * Antlr Grammar: Allow builtin names in ``yulPath`` to support ``.address`` in function pointers. + * Code Generator: Fix ICE when accessing the members of external functions occupying more than two stack slots. + * Code Generator: Fix ICE when doing an explicit conversion from ``string calldata`` to ``bytes``. * Control Flow Graph: Perform proper virtual lookup for modifiers for uninitialized variable and unreachable code analysis. * Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the parent contract contains immutable variables. * IR Generator: Fix IR syntax error when copying storage arrays of structs containing functions. * Natspec: Fix ICE when overriding a struct getter with a Natspec-documented return value and the name in the struct is different. * TypeChecker: Fix ICE when a constant variable declaration forward references a struct. - * Code Generator: Fix ICE when accessing the members of external functions occupying more than two stack slots. Solc-Js: diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 5e49868a3..a9a9118df 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1140,7 +1140,10 @@ void CompilerUtils::convertType( solAssert(_targetType.category() == Type::Category::Array, ""); auto const& targetArrayType = dynamic_cast(_targetType); - solAssert(typeOnStack.arrayType().isImplicitlyConvertibleTo(targetArrayType), ""); + solAssert( + typeOnStack.arrayType().isImplicitlyConvertibleTo(targetArrayType) || + (typeOnStack.arrayType().isByteArray() && targetArrayType.isByteArray()) + ); solAssert( typeOnStack.arrayType().dataStoredIn(DataLocation::CallData) && typeOnStack.arrayType().isDynamicallySized() && diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index f8d4630ca..cb4bd3553 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -3222,7 +3222,10 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) solAssert(_to.category() == Type::Category::Array, ""); auto const& targetType = dynamic_cast(_to); - solAssert(fromType.arrayType().isImplicitlyConvertibleTo(targetType), ""); + solAssert( + fromType.arrayType().isImplicitlyConvertibleTo(targetType) || + (fromType.arrayType().isByteArray() && targetType.isByteArray()) + ); solAssert( fromType.arrayType().dataStoredIn(DataLocation::CallData) && fromType.arrayType().isDynamicallySized() && diff --git a/test/libsolidity/semanticTests/viaYul/conversion/explicit_string_bytes_calldata_cast.sol b/test/libsolidity/semanticTests/viaYul/conversion/explicit_string_bytes_calldata_cast.sol new file mode 100644 index 000000000..4a5b01d39 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/conversion/explicit_string_bytes_calldata_cast.sol @@ -0,0 +1,11 @@ +// Triggered ICE before +contract C { + function f(string calldata data) external pure returns(string memory) { + bytes calldata test = bytes(data[:3]); + return string(test); + } +} +// ==== +// compileViaYul: also +// ---- +// f(string): 0x20, 3, "123" -> 0x20, 3, "123" From 6f4709d3838a560e29fd5b2c7fb81bd17bfe1b73 Mon Sep 17 00:00:00 2001 From: Marenz Date: Thu, 20 Jan 2022 15:03:37 +0100 Subject: [PATCH 77/77] Remove empty assert messages --- libsolidity/codegen/CompilerUtils.cpp | 95 ++++--- libsolidity/codegen/YulUtilFunctions.cpp | 5 +- .../codegen/ir/IRGeneratorForStatements.cpp | 232 +++++++++--------- 3 files changed, 165 insertions(+), 167 deletions(-) diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index a9a9118df..1876b6ac0 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -54,7 +54,7 @@ static_assert(CompilerUtils::generalPurposeMemoryStart >= CompilerUtils::zeroPoi void CompilerUtils::initialiseFreeMemoryPointer() { size_t reservedMemory = m_context.reservedMemory(); - solAssert(bigint(generalPurposeMemoryStart) + bigint(reservedMemory) < bigint(1) << 63, ""); + solAssert(bigint(generalPurposeMemoryStart) + bigint(reservedMemory) < bigint(1) << 63); m_context << (u256(generalPurposeMemoryStart) + reservedMemory); storeFreeMemoryPointer(); } @@ -92,7 +92,7 @@ void CompilerUtils::toSizeAfterFreeMemoryPointer() void CompilerUtils::revertWithStringData(Type const& _argumentType) { - solAssert(_argumentType.isImplicitlyConvertibleTo(*TypeProvider::fromElementaryTypeName("string memory")), ""); + solAssert(_argumentType.isImplicitlyConvertibleTo(*TypeProvider::fromElementaryTypeName("string memory"))); fetchFreeMemoryPointer(); m_context << util::selectorFromSignature("Error(string)"); m_context << Instruction::DUP2 << Instruction::MSTORE; @@ -173,9 +173,9 @@ void CompilerUtils::loadFromMemoryDynamic( if (auto arrayType = dynamic_cast(&_type)) { - solAssert(!arrayType->isDynamicallySized(), ""); - solAssert(!_fromCalldata, ""); - solAssert(_padToWordBoundaries, ""); + solAssert(!arrayType->isDynamicallySized()); + solAssert(!_fromCalldata); + solAssert(_padToWordBoundaries); if (_keepUpdatedMemoryOffset) m_context << arrayType->memoryDataSize() << Instruction::ADD; } @@ -251,7 +251,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem // Use the new Yul-based decoding function auto stackHeightBefore = m_context.stackHeight(); abiDecodeV2(_typeParameters, _fromMemory); - solAssert(m_context.stackHeight() - stackHeightBefore == sizeOnStack(_typeParameters) - 2, ""); + solAssert(m_context.stackHeight() - stackHeightBefore == sizeOnStack(_typeParameters) - 2); return; } @@ -290,7 +290,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem ); // @todo If base type is an array or struct, it is still calldata-style encoded, so // we would have to convert it like below. - solAssert(arrayType.location() == DataLocation::Memory, ""); + solAssert(arrayType.location() == DataLocation::Memory); if (arrayType.isDynamicallySized()) { // compute data pointer @@ -430,7 +430,7 @@ void CompilerUtils::encodeToMemory( // stack: ... bool const encoderV2 = m_context.useABICoderV2(); TypePointers targetTypes = _targetTypes.empty() ? _givenTypes : _targetTypes; - solAssert(targetTypes.size() == _givenTypes.size(), ""); + solAssert(targetTypes.size() == _givenTypes.size()); for (Type const*& t: targetTypes) { Type const* tEncoding = t->fullEncodingType(_encodeAsLibraryTypes, encoderV2, !_padToWordBoundaries); @@ -449,7 +449,7 @@ void CompilerUtils::encodeToMemory( ); auto stackHeightBefore = m_context.stackHeight(); abiEncodeV2(_givenTypes, targetTypes, _encodeAsLibraryTypes, _padToWordBoundaries); - solAssert(stackHeightBefore - m_context.stackHeight() == sizeOnStack(_givenTypes), ""); + solAssert(stackHeightBefore - m_context.stackHeight() == sizeOnStack(_givenTypes)); return; } @@ -489,8 +489,8 @@ void CompilerUtils::encodeToMemory( { // special case: convert storage reference type to value type - this is only // possible for library calls where we just forward the storage reference - solAssert(_encodeAsLibraryTypes, ""); - solAssert(_givenTypes[i]->sizeOnStack() == 1, ""); + solAssert(_encodeAsLibraryTypes); + solAssert(_givenTypes[i]->sizeOnStack() == 1); } else if ( _givenTypes[i]->dataStoredIn(DataLocation::Storage) || @@ -638,7 +638,7 @@ void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type) { if (_type.baseType()->hasSimpleZeroValueInMemory()) { - solAssert(_type.baseType()->isValueType(), ""); + solAssert(_type.baseType()->isValueType()); Whiskers templ(R"({ let size := mul(length, ) // cheap way of zero-initializing a memory range @@ -774,9 +774,9 @@ void CompilerUtils::convertType( if (stackTypeCategory == Type::Category::UserDefinedValueType) { - solAssert(_cleanupNeeded, ""); + solAssert(_cleanupNeeded); auto& userDefined = dynamic_cast(_typeOnStack); - solAssert(_typeOnStack == _targetType || _targetType == userDefined.underlyingType(), ""); + solAssert(_typeOnStack == _targetType || _targetType == userDefined.underlyingType()); return convertType( userDefined.underlyingType(), _targetType, @@ -787,9 +787,9 @@ void CompilerUtils::convertType( } if (targetTypeCategory == Type::Category::UserDefinedValueType) { - solAssert(_cleanupNeeded, ""); + solAssert(_cleanupNeeded); auto& userDefined = dynamic_cast(_targetType); - solAssert(_typeOnStack.isImplicitlyConvertibleTo(userDefined.underlyingType()), ""); + solAssert(_typeOnStack.isImplicitlyConvertibleTo(userDefined.underlyingType())); return convertType( _typeOnStack, userDefined.underlyingType(), @@ -829,7 +829,7 @@ void CompilerUtils::convertType( } else if (targetTypeCategory == Type::Category::Address) { - solAssert(typeOnStack.numBytes() * 8 == 160, ""); + solAssert(typeOnStack.numBytes() * 8 == 160); rightShiftNumberOnStack(256 - 160); } else @@ -849,7 +849,7 @@ void CompilerUtils::convertType( break; } case Type::Category::Enum: - solAssert(_targetType == _typeOnStack || targetTypeCategory == Type::Category::Integer, ""); + solAssert(_targetType == _typeOnStack || targetTypeCategory == Type::Category::Integer); if (enumOverflowCheckPending) { EnumType const& enumType = dynamic_cast(_typeOnStack); @@ -885,13 +885,13 @@ void CompilerUtils::convertType( cleanHigherOrderBits(*typeOnStack); } else if (stackTypeCategory == Type::Category::Address) - solAssert(targetBytesType.numBytes() * 8 == 160, ""); + solAssert(targetBytesType.numBytes() * 8 == 160); leftShiftNumberOnStack(256 - targetBytesType.numBytes() * 8); } else if (targetTypeCategory == Type::Category::Enum) { solAssert(stackTypeCategory != Type::Category::Address, "Invalid conversion to EnumType requested."); - solAssert(_typeOnStack.mobileType(), ""); + solAssert(_typeOnStack.mobileType()); // just clean convertType(_typeOnStack, *_typeOnStack.mobileType(), true); EnumType const& enumType = dynamic_cast(_targetType); @@ -964,13 +964,13 @@ void CompilerUtils::convertType( if (targetTypeCategory == Type::Category::FixedBytes) { unsigned const numBytes = dynamic_cast(_targetType).numBytes(); - solAssert(data.size() <= 32, ""); + solAssert(data.size() <= 32); m_context << (u256(h256(data, h256::AlignLeft)) & (~(u256(-1) >> (8 * numBytes)))); } else if (targetTypeCategory == Type::Category::Array) { auto const& arrayType = dynamic_cast(_targetType); - solAssert(arrayType.isByteArray(), ""); + solAssert(arrayType.isByteArray()); size_t storageSize = 32 + ((data.size() + 31) / 32) * 32; allocateMemory(storageSize); // stack: mempos @@ -995,10 +995,10 @@ void CompilerUtils::convertType( typeOnStack.isByteArray() && !typeOnStack.isString(), "Array types other than bytes not convertible to bytesNN." ); - solAssert(typeOnStack.isDynamicallySized(), ""); + solAssert(typeOnStack.isDynamicallySized()); bool fromCalldata = typeOnStack.dataStoredIn(DataLocation::CallData); - solAssert(typeOnStack.sizeOnStack() == (fromCalldata ? 2 : 1), ""); + solAssert(typeOnStack.sizeOnStack() == (fromCalldata ? 2 : 1)); if (fromCalldata) m_context << Instruction::SWAP1; @@ -1012,7 +1012,7 @@ void CompilerUtils::convertType( ); break; } - solAssert(targetTypeCategory == stackTypeCategory, ""); + solAssert(targetTypeCategory == stackTypeCategory); auto const& targetType = dynamic_cast(_targetType); switch (targetType.location()) { @@ -1034,9 +1034,9 @@ void CompilerUtils::convertType( typeOnStack.baseType()->isDynamicallyEncoded() ) { - solAssert(m_context.useABICoderV2(), ""); + solAssert(m_context.useABICoderV2()); // stack: offset length(optional in case of dynamically sized array) - solAssert(typeOnStack.sizeOnStack() == (typeOnStack.isDynamicallySized() ? 2 : 1), ""); + solAssert(typeOnStack.sizeOnStack() == (typeOnStack.isDynamicallySized() ? 2 : 1)); if (typeOnStack.isDynamicallySized()) m_context << Instruction::SWAP1; @@ -1122,9 +1122,9 @@ void CompilerUtils::convertType( typeOnStack.arrayType().isByteArray() && !typeOnStack.arrayType().isString(), "Array types other than bytes not convertible to bytesNN." ); - solAssert(typeOnStack.isDynamicallySized(), ""); - solAssert(typeOnStack.dataStoredIn(DataLocation::CallData), ""); - solAssert(typeOnStack.sizeOnStack() == 2, ""); + solAssert(typeOnStack.isDynamicallySized()); + solAssert(typeOnStack.dataStoredIn(DataLocation::CallData)); + solAssert(typeOnStack.sizeOnStack() == 2); m_context << Instruction::SWAP1; m_context.callYulFunction( @@ -1138,7 +1138,7 @@ void CompilerUtils::convertType( break; } - solAssert(_targetType.category() == Type::Category::Array, ""); + solAssert(_targetType.category() == Type::Category::Array); auto const& targetArrayType = dynamic_cast(_targetType); solAssert( typeOnStack.arrayType().isImplicitlyConvertibleTo(targetArrayType) || @@ -1147,8 +1147,7 @@ void CompilerUtils::convertType( solAssert( typeOnStack.arrayType().dataStoredIn(DataLocation::CallData) && typeOnStack.arrayType().isDynamicallySized() && - !typeOnStack.arrayType().baseType()->isDynamicallyEncoded(), - "" + !typeOnStack.arrayType().baseType()->isDynamicallyEncoded() ); if (!_targetType.dataStoredIn(DataLocation::CallData)) return convertType(typeOnStack.arrayType(), _targetType); @@ -1156,7 +1155,7 @@ void CompilerUtils::convertType( } case Type::Category::Struct: { - solAssert(targetTypeCategory == stackTypeCategory, ""); + solAssert(targetTypeCategory == stackTypeCategory); auto& targetType = dynamic_cast(_targetType); auto& typeOnStack = dynamic_cast(_typeOnStack); switch (targetType.location()) @@ -1185,7 +1184,7 @@ void CompilerUtils::convertType( // stack: for (auto const& member: typeOnStack->members(nullptr)) { - solAssert(!member.type->containsNestedMapping(), ""); + solAssert(!member.type->containsNestedMapping()); pair const& offsets = typeOnStack->storageOffsetsOfMember(member.name); _context << offsets.first << Instruction::DUP3 << Instruction::ADD; _context << u256(offsets.second); @@ -1212,7 +1211,7 @@ void CompilerUtils::convertType( { if (typeOnStack.isDynamicallyEncoded()) { - solAssert(m_context.useABICoderV2(), ""); + solAssert(m_context.useABICoderV2()); m_context.callYulFunction( m_context.utilFunctions().conversionFunction(typeOnStack, targetType), 1, @@ -1234,7 +1233,7 @@ void CompilerUtils::convertType( } break; case DataLocation::CallData: - solAssert(_typeOnStack == _targetType, ""); + solAssert(_typeOnStack == _targetType); // nothing to do break; } @@ -1244,7 +1243,7 @@ void CompilerUtils::convertType( { TupleType const& sourceTuple = dynamic_cast(_typeOnStack); TupleType const& targetTuple = dynamic_cast(_targetType); - solAssert(targetTuple.components().size() == sourceTuple.components().size(), ""); + solAssert(targetTuple.components().size() == sourceTuple.components().size()); unsigned depth = sourceTuple.sizeOnStack(); for (size_t i = 0; i < sourceTuple.components().size(); ++i) { @@ -1252,7 +1251,7 @@ void CompilerUtils::convertType( Type const* targetType = targetTuple.components()[i]; if (!sourceType) { - solAssert(!targetType, ""); + solAssert(!targetType); continue; } unsigned sourceSize = sourceType->sizeOnStack(); @@ -1294,7 +1293,7 @@ void CompilerUtils::convertType( break; default: // we used to allow conversions from function to address - solAssert(!(stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Address), ""); + solAssert(!(stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Address)); if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Function) { FunctionType const& typeOnStack = dynamic_cast(_typeOnStack); @@ -1351,14 +1350,14 @@ void CompilerUtils::pushZeroValue(Type const& _type) } if (referenceType->location() == DataLocation::CallData) { - solAssert(referenceType->sizeOnStack() == 1 || referenceType->sizeOnStack() == 2, ""); + solAssert(referenceType->sizeOnStack() == 1 || referenceType->sizeOnStack() == 2); m_context << Instruction::CALLDATASIZE; if (referenceType->sizeOnStack() == 2) m_context << 0; return; } - solAssert(referenceType->location() == DataLocation::Memory, ""); + solAssert(referenceType->location() == DataLocation::Memory); if (auto arrayType = dynamic_cast(&_type)) if (arrayType->isDynamicallySized()) { @@ -1386,7 +1385,7 @@ void CompilerUtils::pushZeroValue(Type const& _type) } else if (auto arrayType = dynamic_cast(type)) { - solAssert(!arrayType->isDynamicallySized(), ""); + solAssert(!arrayType->isDynamicallySized()); if (arrayType->length() > 0) { _context << arrayType->length() << Instruction::SWAP1; @@ -1486,7 +1485,7 @@ void CompilerUtils::popStackSlots(size_t _amount) void CompilerUtils::popAndJump(unsigned _toHeight, evmasm::AssemblyItem const& _jumpTo) { - solAssert(m_context.stackHeight() >= _toHeight, ""); + solAssert(m_context.stackHeight() >= _toHeight); unsigned amount = m_context.stackHeight() - _toHeight; popStackSlots(amount); m_context.appendJumpTo(_jumpTo); @@ -1554,7 +1553,7 @@ void CompilerUtils::storeStringData(bytesConstRef _data) unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWords) { - solAssert(_type.isValueType(), ""); + solAssert(_type.isValueType()); Type const* type = &_type; if (auto const* userDefined = dynamic_cast(type)) type = &userDefined->underlyingType(); @@ -1606,7 +1605,7 @@ void CompilerUtils::cleanHigherOrderBits(IntegerType const& _typeOnStack) void CompilerUtils::leftShiftNumberOnStack(unsigned _bits) { - solAssert(_bits < 256, ""); + solAssert(_bits < 256); if (m_context.evmVersion().hasBitwiseShifting()) m_context << _bits << Instruction::SHL; else @@ -1615,7 +1614,7 @@ void CompilerUtils::leftShiftNumberOnStack(unsigned _bits) void CompilerUtils::rightShiftNumberOnStack(unsigned _bits) { - solAssert(_bits < 256, ""); + solAssert(_bits < 256); // NOTE: If we add signed right shift, SAR rounds differently than SDIV if (m_context.evmVersion().hasBitwiseShifting()) m_context << _bits << Instruction::SHR; @@ -1630,7 +1629,7 @@ unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWords, "Memory store of types with stack size != 1 not allowed (Type: " + _type.toString(true) + ")." ); - solAssert(!_type.isDynamicallyEncoded(), ""); + solAssert(!_type.isDynamicallyEncoded()); unsigned numBytes = _type.calldataEncodedSize(_padToWords); diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index cb4bd3553..217ec14b0 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -3219,7 +3219,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) solAssert(fromType.arrayType().isByteArray(), "Array types other than bytes not convertible to bytesNN."); return bytesToFixedBytesConversionFunction(fromType.arrayType(), dynamic_cast(_to)); } - solAssert(_to.category() == Type::Category::Array, ""); + solAssert(_to.category() == Type::Category::Array); auto const& targetType = dynamic_cast(_to); solAssert( @@ -3229,8 +3229,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) solAssert( fromType.arrayType().dataStoredIn(DataLocation::CallData) && fromType.arrayType().isDynamicallySized() && - !fromType.arrayType().baseType()->isDynamicallyEncoded(), - "" + !fromType.arrayType().baseType()->isDynamicallyEncoded() ); if (!targetType.dataStoredIn(DataLocation::CallData)) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 24d695d39..420c48baa 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -95,7 +95,7 @@ struct CopyTranslate: public yul::ASTCopier return ASTCopier::translate(_identifier); yul::Expression translated = translateReference(_identifier); - solAssert(holds_alternative(translated), ""); + solAssert(holds_alternative(translated)); return get(std::move(translated)); } @@ -115,14 +115,14 @@ private: if (suffix.empty() && varDecl->isLocalVariable()) { auto const& var = m_context.localVariable(*varDecl); - solAssert(var.type().sizeOnStack() == 1, ""); + solAssert(var.type().sizeOnStack() == 1); value = var.commaSeparatedList(); } else if (varDecl->isConstant()) { VariableDeclaration const* variable = rootConstVariableDeclaration(*varDecl); - solAssert(variable, ""); + solAssert(variable); if (variable->value()->annotation().type->category() == Type::Category::RationalNumber) { @@ -130,7 +130,7 @@ private: if (auto const* bytesType = dynamic_cast(variable->type())) intValue <<= 256 - 8 * bytesType->numBytes(); else - solAssert(variable->type()->category() == Type::Category::Integer, ""); + solAssert(variable->type()->category() == Type::Category::Integer); value = intValue.str(); } else if (auto const* literal = dynamic_cast(variable->value().get())) @@ -141,20 +141,20 @@ private: { case Type::Category::Bool: case Type::Category::Address: - solAssert(type->category() == variable->annotation().type->category(), ""); + solAssert(type->category() == variable->annotation().type->category()); value = toCompactHexWithPrefix(type->literalValue(literal)); break; case Type::Category::StringLiteral: { auto const& stringLiteral = dynamic_cast(*type); - solAssert(variable->type()->category() == Type::Category::FixedBytes, ""); + solAssert(variable->type()->category() == Type::Category::FixedBytes); unsigned const numBytes = dynamic_cast(*variable->type()).numBytes(); - solAssert(stringLiteral.value().size() <= numBytes, ""); + solAssert(stringLiteral.value().size() <= numBytes); value = formatNumber(u256(h256(stringLiteral.value(), h256::AlignLeft))); break; } default: - solAssert(false, ""); + solAssert(false); } } else @@ -167,25 +167,25 @@ private: else if (suffix == "offset") value = to_string(m_context.storageLocationOfStateVariable(*varDecl).second); else - solAssert(false, ""); + solAssert(false); } else if (varDecl->type()->dataStoredIn(DataLocation::Storage)) { - solAssert(suffix == "slot" || suffix == "offset", ""); - solAssert(varDecl->isLocalVariable(), ""); + solAssert(suffix == "slot" || suffix == "offset"); + solAssert(varDecl->isLocalVariable()); if (suffix == "slot") value = IRVariable{*varDecl}.part("slot").name(); else if (varDecl->type()->isValueType()) value = IRVariable{*varDecl}.part("offset").name(); else { - solAssert(!IRVariable{*varDecl}.hasPart("offset"), ""); + solAssert(!IRVariable{*varDecl}.hasPart("offset")); value = "0"; } } else if (varDecl->type()->dataStoredIn(DataLocation::CallData)) { - solAssert(suffix == "offset" || suffix == "length", ""); + solAssert(suffix == "offset" || suffix == "length"); value = IRVariable{*varDecl}.part(suffix).name(); } else if ( @@ -193,15 +193,15 @@ private: functionType && functionType->kind() == FunctionType::Kind::External ) { - solAssert(suffix == "selector" || suffix == "address", ""); - solAssert(varDecl->type()->sizeOnStack() == 2, ""); + solAssert(suffix == "selector" || suffix == "address"); + solAssert(varDecl->type()->sizeOnStack() == 2); if (suffix == "selector") value = IRVariable{*varDecl}.part("functionSelector").name(); else value = IRVariable{*varDecl}.part("address").name(); } else - solAssert(false, ""); + solAssert(false); if (isdigit(value.front())) return yul::Literal{_identifier.debugData, yul::LiteralKind::Number, yul::YulString{value}, {}}; @@ -268,7 +268,7 @@ void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _va setLocation(_varDecl); solAssert(_varDecl.immutable() || m_context.isStateVariable(_varDecl), "Must be immutable or a state variable."); - solAssert(!_varDecl.isConstant(), ""); + solAssert(!_varDecl.isConstant()); if (!_varDecl.value()) return; @@ -355,7 +355,7 @@ string IRGeneratorForStatements::constantValueFunction(VariableDeclaration const templ("sourceLocationComment", dispenseLocationComment(_constant, m_context)); templ("functionName", functionName); IRGeneratorForStatements generator(m_context, m_utils); - solAssert(_constant.value(), ""); + solAssert(_constant.value()); Type const& constantType = *_constant.type(); templ("value", generator.evaluateExpression(*_constant.value(), constantType).commaSeparatedList()); templ("code", generator.code()); @@ -386,7 +386,7 @@ void IRGeneratorForStatements::endVisit(VariableDeclarationStatement const& _var for (size_t i = 0; i < _varDeclStatement.declarations().size(); ++i) if (auto const& decl = _varDeclStatement.declarations()[i]) { - solAssert(tupleType->components()[i], ""); + solAssert(tupleType->components()[i]); define(m_context.addLocalVariable(*decl), IRVariable(*expression).tupleComponent(i)); } } @@ -443,7 +443,7 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment) TokenTraits::AssignmentToBinaryOp(assignmentOperator); if (TokenTraits::isShiftOp(binaryOperator)) - solAssert(type(_assignment.rightHandSide()).mobileType(), ""); + solAssert(type(_assignment.rightHandSide()).mobileType()); IRVariable value = type(_assignment.leftHandSide()).isValueType() ? convert( @@ -460,11 +460,11 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment) if (assignmentOperator != Token::Assign) { solAssert(type(_assignment.leftHandSide()).isValueType(), "Compound operators only available for value types."); - solAssert(binaryOperator != Token::Exp, ""); - solAssert(type(_assignment) == type(_assignment.leftHandSide()), ""); + solAssert(binaryOperator != Token::Exp); + solAssert(type(_assignment) == type(_assignment.leftHandSide())); IRVariable leftIntermediate = readFromLValue(*m_currentLValue); - solAssert(type(_assignment) == leftIntermediate.type(), ""); + solAssert(type(_assignment) == leftIntermediate.type()); define(_assignment) << ( TokenTraits::isShiftOp(binaryOperator) ? @@ -523,14 +523,14 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple) { bool willBeWrittenTo = _tuple.annotation().willBeWrittenTo; if (willBeWrittenTo) - solAssert(!m_currentLValue, ""); + solAssert(!m_currentLValue); if (_tuple.components().size() == 1) { - solAssert(_tuple.components().front(), ""); + solAssert(_tuple.components().front()); _tuple.components().front()->accept(*this); setLocation(_tuple); if (willBeWrittenTo) - solAssert(!!m_currentLValue, ""); + solAssert(!!m_currentLValue); else define(_tuple, *_tuple.components().front()); } @@ -544,7 +544,7 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple) setLocation(_tuple); if (willBeWrittenTo) { - solAssert(!!m_currentLValue, ""); + solAssert(!!m_currentLValue); lvalues.emplace_back(std::move(m_currentLValue)); m_currentLValue.reset(); } @@ -568,7 +568,7 @@ bool IRGeneratorForStatements::visit(Block const& _block) { if (_block.unchecked()) { - solAssert(m_context.arithmetic() == Arithmetic::Checked, ""); + solAssert(m_context.arithmetic() == Arithmetic::Checked); m_context.setArithmetic(Arithmetic::Wrapping); } return true; @@ -578,7 +578,7 @@ void IRGeneratorForStatements::endVisit(Block const& _block) { if (_block.unchecked()) { - solAssert(m_context.arithmetic() == Arithmetic::Wrapping, ""); + solAssert(m_context.arithmetic() == Arithmetic::Wrapping); m_context.setArithmetic(Arithmetic::Checked); } } @@ -607,7 +607,7 @@ bool IRGeneratorForStatements::visit(IfStatement const& _ifStatement) void IRGeneratorForStatements::endVisit(PlaceholderStatement const& _placeholder) { - solAssert(m_placeholderCallback, ""); + solAssert(m_placeholderCallback); setLocation(_placeholder); appendCode() << m_placeholderCallback(); } @@ -776,7 +776,7 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) { setLocation(_binOp); - solAssert(!!_binOp.annotation().commonType, ""); + solAssert(!!_binOp.annotation().commonType); Type const* commonType = _binOp.annotation().commonType; langutil::Token op = _binOp.getOperator(); @@ -799,7 +799,7 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) if (TokenTraits::isCompareOp(op)) { - solAssert(commonType->isValueType(), ""); + solAssert(commonType->isValueType()); bool isSigned = false; if (auto type = dynamic_cast(commonType)) @@ -855,7 +855,7 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) else if (auto rationalNumberType = dynamic_cast(_binOp.leftExpression().annotation().type)) { solAssert(rationalNumberType->integerType(), "Invalid literal as the base for exponentiation."); - solAssert(dynamic_cast(commonType), ""); + solAssert(dynamic_cast(commonType)); define(_binOp) << m_utils.overflowCheckedIntLiteralExpFunction( *rationalNumberType, @@ -951,7 +951,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) { FunctionDefinition const* functionDef = ASTNode::resolveFunctionCall(_functionCall, &m_context.mostDerivedContract()); - solAssert(!functionType->takesArbitraryParameters(), ""); + solAssert(!functionType->takesArbitraryParameters()); vector args; if (functionType->bound()) @@ -962,7 +962,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) if (functionDef) { - solAssert(functionDef->isImplemented(), ""); + solAssert(functionDef->isImplemented()); define(_functionCall) << m_context.enqueueFunctionForCodeGeneration(*functionDef) << @@ -1065,7 +1065,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) case FunctionType::Kind::Error: { ErrorDefinition const* error = dynamic_cast(ASTNode::referencedDeclaration(_functionCall.expression())); - solAssert(error, ""); + solAssert(error); revertWithError( error->functionType(true)->externalSignature(), error->functionType(true)->parameterTypes(), @@ -1076,7 +1076,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) case FunctionType::Kind::Wrap: case FunctionType::Kind::Unwrap: { - solAssert(arguments.size() == 1, ""); + solAssert(arguments.size() == 1); FunctionType::Kind kind = functionType->kind(); if (kind == FunctionType::Kind::Wrap) solAssert( @@ -1086,7 +1086,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) "" ); else - solAssert(type(*arguments.at(0)).category() == Type::Category::UserDefinedValueType, ""); + solAssert(type(*arguments.at(0)).category() == Type::Category::UserDefinedValueType); define(_functionCall, *arguments.at(0)); break; @@ -1120,7 +1120,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) case FunctionType::Kind::ABIEncodeWithSignature: { bool const isPacked = functionType->kind() == FunctionType::Kind::ABIEncodePacked; - solAssert(functionType->padArguments() != isPacked, ""); + solAssert(functionType->padArguments() != isPacked); bool const hasSelectorOrSignature = functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector || functionType->kind() == FunctionType::Kind::ABIEncodeCall || @@ -1134,7 +1134,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) if (functionType->kind() == FunctionType::Kind::ABIEncodeCall) { - solAssert(arguments.size() == 2, ""); + solAssert(arguments.size() == 2); // Account for tuples with one component which become that component if (type(*arguments[1]).category() == Type::Category::Tuple) { @@ -1257,7 +1257,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) referenceType && referenceType->dataStoredIn(DataLocation::CallData) ) { - solAssert(referenceType->isImplicitlyConvertibleTo(*TypeProvider::bytesCalldata()), ""); + solAssert(referenceType->isImplicitlyConvertibleTo(*TypeProvider::bytesCalldata())); IRVariable var = convert(*arguments[0], *TypeProvider::bytesCalldata()); templ("abiDecode", m_context.abiFunctions().tupleDecoder(targetTypes, false)); templ("offset", var.part("offset").name()); @@ -1279,8 +1279,8 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) } case FunctionType::Kind::Revert: { - solAssert(arguments.size() == parameterTypes.size(), ""); - solAssert(arguments.size() <= 1, ""); + solAssert(arguments.size() == parameterTypes.size()); + solAssert(arguments.size() <= 1); solAssert( arguments.empty() || arguments.front()->annotation().type->isImplicitlyConvertibleTo(*TypeProvider::stringMemory()), @@ -1299,7 +1299,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) case FunctionType::Kind::ObjectCreation: { ArrayType const& arrayType = dynamic_cast(*_functionCall.annotation().type); - solAssert(arguments.size() == 1, ""); + solAssert(arguments.size() == 1); IRVariable value = convert(*arguments[0], *TypeProvider::uint256()); define(_functionCall) << @@ -1311,7 +1311,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) } case FunctionType::Kind::KECCAK256: { - solAssert(arguments.size() == 1, ""); + solAssert(arguments.size() == 1); ArrayType const* arrayType = TypeProvider::bytesMemory(); @@ -1339,10 +1339,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) } case FunctionType::Kind::ArrayPop: { - solAssert(functionType->bound(), ""); - solAssert(functionType->parameterTypes().empty(), ""); + solAssert(functionType->bound()); + solAssert(functionType->parameterTypes().empty()); ArrayType const* arrayType = dynamic_cast(functionType->selfType()); - solAssert(arrayType, ""); + solAssert(arrayType); define(_functionCall) << m_utils.storageArrayPopFunction(*arrayType) << "(" << @@ -1353,7 +1353,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) case FunctionType::Kind::ArrayPush: { ArrayType const* arrayType = dynamic_cast(functionType->selfType()); - solAssert(arrayType, ""); + solAssert(arrayType); if (arguments.empty()) { @@ -1414,8 +1414,8 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) {FunctionType::Kind::AddMod, "addmod"}, {FunctionType::Kind::MulMod, "mulmod"}, }; - solAssert(functions.find(functionType->kind()) != functions.end(), ""); - solAssert(arguments.size() == 3 && parameterTypes.size() == 3, ""); + solAssert(functions.find(functionType->kind()) != functions.end()); + solAssert(arguments.size() == 3 && parameterTypes.size() == 3); IRVariable modulus(m_context.newYulVariable(), *(parameterTypes[2])); define(modulus, *arguments[2]); @@ -1440,7 +1440,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) {FunctionType::Kind::Selfdestruct, "selfdestruct"}, {FunctionType::Kind::BlockHash, "blockhash"}, }; - solAssert(functions.find(functionType->kind()) != functions.end(), ""); + solAssert(functions.find(functionType->kind()) != functions.end()); string args; for (size_t i = 0; i < arguments.size(); ++i) @@ -1497,7 +1497,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) t("saltSet", functionType->saltSet()); if (functionType->saltSet()) t("salt", IRVariable(_functionCall.expression()).part("salt").name()); - solAssert(IRVariable(_functionCall).stackSlots().size() == 1, ""); + solAssert(IRVariable(_functionCall).stackSlots().size() == 1); t("address", IRVariable(_functionCall).commaSeparatedList()); t("isTryCall", _functionCall.annotation().tryCall); if (_functionCall.annotation().tryCall) @@ -1511,7 +1511,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) case FunctionType::Kind::Send: case FunctionType::Kind::Transfer: { - solAssert(arguments.size() == 1 && parameterTypes.size() == 1, ""); + solAssert(arguments.size() == 1 && parameterTypes.size() == 1); string address{IRVariable(_functionCall.expression()).part("address").name()}; string value{expressionAsType(*arguments[0], *(parameterTypes[0]))}; Whiskers templ(R"( @@ -1540,10 +1540,10 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) case FunctionType::Kind::RIPEMD160: case FunctionType::Kind::SHA256: { - solAssert(!_functionCall.annotation().tryCall, ""); - solAssert(!functionType->valueSet(), ""); - solAssert(!functionType->gasSet(), ""); - solAssert(!functionType->bound(), ""); + solAssert(!_functionCall.annotation().tryCall); + solAssert(!functionType->valueSet()); + solAssert(!functionType->gasSet()); + solAssert(!functionType->bound()); static map> precompiles = { {FunctionType::Kind::ECRecover, std::make_tuple(1, 0)}, @@ -1618,7 +1618,7 @@ void IRGeneratorForStatements::endVisit(FunctionCallOptions const& _options) for (size_t i = 0; i < _options.names().size(); ++i) { string const& name = *_options.names()[i]; - solAssert(name == "salt" || name == "gas" || name == "value", ""); + solAssert(name == "salt" || name == "gas" || name == "value"); define(IRVariable(_options).part(name), *_options.options()[i]); } @@ -1636,7 +1636,7 @@ bool IRGeneratorForStatements::visit(MemberAccess const& _memberAccess) innerExpression->expression().annotation().type->category() == Type::Category::Address ) { - solAssert(innerExpression->annotation().type->category() == Type::Category::Array, ""); + solAssert(innerExpression->annotation().type->category() == Type::Category::Array); // Skip visiting
.code innerExpression->expression().accept(*this); @@ -1657,7 +1657,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) if (memberFunctionType && memberFunctionType->bound()) { define(IRVariable(_memberAccess).part("self"), _memberAccess.expression()); - solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, ""); + solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static); if (memberFunctionType->kind() == FunctionType::Kind::Internal) assignInternalFunctionIDIfNotCalledDirectly( _memberAccess, @@ -1673,9 +1673,9 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) else { auto const& functionDefinition = dynamic_cast(memberFunctionType->declaration()); - solAssert(memberFunctionType->kind() == FunctionType::Kind::DelegateCall, ""); + solAssert(memberFunctionType->kind() == FunctionType::Kind::DelegateCall); auto contract = dynamic_cast(functionDefinition.scope()); - solAssert(contract && contract->isLibrary(), ""); + solAssert(contract && contract->isLibrary()); define(IRVariable(_memberAccess).part("address")) << linkerSymbol(*contract) << "\n"; define(IRVariable(_memberAccess).part("functionSelector")) << memberFunctionType->externalIdentifier() << "\n"; } @@ -1688,7 +1688,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) { ContractType const& type = dynamic_cast(*_memberAccess.expression().annotation().type); if (type.isSuper()) - solAssert(false, ""); + solAssert(false); // ordinary contract type else if (Declaration const* declaration = _memberAccess.annotation().referencedDeclaration) @@ -1736,7 +1736,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) ")\n"; else if (set{"send", "transfer"}.count(member)) { - solAssert(dynamic_cast(*_memberAccess.expression().annotation().type).stateMutability() == StateMutability::Payable, ""); + solAssert(dynamic_cast(*_memberAccess.expression().annotation().type).stateMutability() == StateMutability::Payable); define(IRVariable{_memberAccess}.part("address"), _memberAccess.expression()); } else if (set{"call", "callcode", "delegatecall", "staticcall"}.count(member)) @@ -1764,7 +1764,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) functionType.kind() == FunctionType::Kind::Internal ) { - solAssert(functionType.hasDeclaration(), ""); + solAssert(functionType.hasDeclaration()); solAssert( functionType.kind() == FunctionType::Kind::Error || functionType.declaration().isPartOfExternalInterface(), @@ -1832,7 +1832,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) { Type const* arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); auto const& contractType = dynamic_cast(*arg); - solAssert(!contractType.isSuper(), ""); + solAssert(!contractType.isSuper()); ContractDefinition const& contract = contractType.contractDefinition(); m_context.subObjectsCreated().insert(&contract); appendCode() << Whiskers(R"( @@ -1856,7 +1856,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) { Type const* arg = dynamic_cast(*_memberAccess.expression().annotation().type).typeArgument(); auto const& contractType = dynamic_cast(*arg); - solAssert(!contractType.isSuper(), ""); + solAssert(!contractType.isSuper()); ContractDefinition const& contract = contractType.contractDefinition(); define(_memberAccess) << formatNumber(u256{contract.interfaceId()} << (256 - 32)) << "\n"; } @@ -1983,7 +1983,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) } else if (member == "pop" || member == "push") { - solAssert(type.location() == DataLocation::Storage, ""); + solAssert(type.location() == DataLocation::Storage); define(IRVariable{_memberAccess}.part("slot"), IRVariable{_memberAccess.expression()}.part("slot")); } else @@ -2019,8 +2019,8 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) *_memberAccess.annotation().referencedDeclaration ).resolveVirtual(m_context.mostDerivedContract(), super); - solAssert(resolvedFunctionDef.functionType(true), ""); - solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal, ""); + solAssert(resolvedFunctionDef.functionType(true)); + solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal); assignInternalFunctionIDIfNotCalledDirectly(_memberAccess, resolvedFunctionDef); } else if (auto const* variable = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) @@ -2078,19 +2078,19 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) // The old code generator had a generic "else" case here // without any specific code being generated, // but it would still be better to have an exhaustive list. - solAssert(false, ""); + solAssert(false); } else if (EnumType const* enumType = dynamic_cast(&actualType)) define(_memberAccess) << to_string(enumType->memberValue(_memberAccess.memberName())) << "\n"; else if (dynamic_cast(&actualType)) - solAssert(member == "wrap" || member == "unwrap", ""); + solAssert(member == "wrap" || member == "unwrap"); else if (auto const* arrayType = dynamic_cast(&actualType)) - solAssert(arrayType->isByteArray() && member == "concat", ""); + solAssert(arrayType->isByteArray() && member == "concat"); else // The old code generator had a generic "else" case here // without any specific code being generated, // but it would still be better to have an exhaustive list. - solAssert(false, ""); + solAssert(false); break; } case Type::Category::Module: @@ -2106,17 +2106,17 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) ); if (auto variable = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) { - solAssert(variable->isConstant(), ""); + solAssert(variable->isConstant()); handleVariableReference(*variable, static_cast(_memberAccess)); } else if (auto const* function = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) { auto funType = dynamic_cast(_memberAccess.annotation().type); - solAssert(function && function->isFree(), ""); - solAssert(function->functionType(true), ""); - solAssert(function->functionType(true)->kind() == FunctionType::Kind::Internal, ""); - solAssert(funType->kind() == FunctionType::Kind::Internal, ""); - solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, ""); + solAssert(function && function->isFree()); + solAssert(function->functionType(true)); + solAssert(function->functionType(true)->kind() == FunctionType::Kind::Internal); + solAssert(funType->kind() == FunctionType::Kind::Internal); + solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static); assignInternalFunctionIDIfNotCalledDirectly(_memberAccess, *function); } @@ -2140,7 +2140,7 @@ bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm) yul::Statement modified = bodyCopier(_inlineAsm.operations()); - solAssert(holds_alternative(modified), ""); + solAssert(holds_alternative(modified)); // Do not provide dialect so that we get the full type information. appendCode() << yul::AsmPrinter()(std::get(modified)) << "\n"; @@ -2183,7 +2183,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) dynamic_cast(baseType).arrayType(); if (baseType.category() == Type::Category::ArraySlice) - solAssert(arrayType.dataStoredIn(DataLocation::CallData) && arrayType.isDynamicallySized(), ""); + solAssert(arrayType.dataStoredIn(DataLocation::CallData) && arrayType.isDynamicallySized()); solAssert(_indexAccess.indexExpression(), "Index expression expected."); @@ -2276,8 +2276,8 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) } else if (baseType.category() == Type::Category::TypeType) { - solAssert(baseType.sizeOnStack() == 0, ""); - solAssert(_indexAccess.annotation().type->sizeOnStack() == 0, ""); + solAssert(baseType.sizeOnStack() == 0); + solAssert(_indexAccess.annotation().type->sizeOnStack() == 0); // no-op - this seems to be a lone array type (`structType[];`) } else @@ -2302,7 +2302,7 @@ void IRGeneratorForStatements::endVisit(IndexRangeAccess const& _indexRangeAcces { case DataLocation::CallData: { - solAssert(baseType.isDynamicallySized(), ""); + solAssert(baseType.isDynamicallySized()); IRVariable sliceStart{m_context.newYulVariable(), *TypeProvider::uint256()}; if (_indexRangeAccess.startExpression()) define(sliceStart, IRVariable{*_indexRangeAccess.startExpression()}); @@ -2340,18 +2340,18 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier) switch (magicVar->type()->category()) { case Type::Category::Contract: - solAssert(_identifier.name() == "this", ""); + solAssert(_identifier.name() == "this"); define(_identifier) << "address()\n"; break; case Type::Category::Integer: - solAssert(_identifier.name() == "now", ""); + solAssert(_identifier.name() == "now"); define(_identifier) << "timestamp()\n"; break; case Type::Category::TypeType: { auto typeType = dynamic_cast(magicVar->type()); if (auto contractType = dynamic_cast(typeType->actualType())) - solAssert(!contractType->isSuper() || _identifier.name() == "super", ""); + solAssert(!contractType->isSuper() || _identifier.name() == "super"); break; } default: @@ -2361,11 +2361,11 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier) } else if (FunctionDefinition const* functionDef = dynamic_cast(declaration)) { - solAssert(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual, ""); + solAssert(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual); FunctionDefinition const& resolvedFunctionDef = functionDef->resolveVirtual(m_context.mostDerivedContract()); - solAssert(resolvedFunctionDef.functionType(true), ""); - solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal, ""); + solAssert(resolvedFunctionDef.functionType(true)); + solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal); assignInternalFunctionIDIfNotCalledDirectly(_identifier, resolvedFunctionDef); } else if (VariableDeclaration const* varDecl = dynamic_cast(declaration)) @@ -2460,9 +2460,9 @@ void IRGeneratorForStatements::appendExternalFunctionCall( ) { FunctionType const& funType = dynamic_cast(type(_functionCall.expression())); - solAssert(!funType.takesArbitraryParameters(), ""); - solAssert(_arguments.size() == funType.parameterTypes().size(), ""); - solAssert(!funType.isBareCall(), ""); + solAssert(!funType.takesArbitraryParameters()); + solAssert(_arguments.size() == funType.parameterTypes().size()); + solAssert(!funType.isBareCall()); FunctionType::Kind const funKind = funType.kind(); solAssert( @@ -2566,7 +2566,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall( string const retVars = IRVariable(_functionCall).commaSeparatedList(); templ("retVars", retVars); - solAssert(retVars.empty() == returnInfo.returnTypes.empty(), ""); + solAssert(retVars.empty() == returnInfo.returnTypes.empty()); templ("abiDecode", m_context.abiFunctions().tupleDecoder(returnInfo.returnTypes, true)); templ("dynamicReturnSize", returnInfo.dynamicReturnSize); @@ -2575,7 +2575,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall( bool encodeForLibraryCall = funKind == FunctionType::Kind::DelegateCall; - solAssert(funType.padArguments(), ""); + solAssert(funType.padArguments()); templ("encodeArgs", m_context.abiFunctions().tupleEncoder(argumentTypes, parameterTypes, encodeForLibraryCall)); templ("argumentString", joinHumanReadablePrefixed(argumentStrings)); @@ -2628,7 +2628,7 @@ void IRGeneratorForStatements::appendBareCall( ); FunctionType::Kind const funKind = funType.kind(); - solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall(), ""); + solAssert(funKind != FunctionType::Kind::BareStaticCall || m_context.evmVersion().hasStaticCall()); solAssert(funKind != FunctionType::Kind::BareCallCode, "Callcode has been removed."); solAssert( funKind == FunctionType::Kind::BareCall || @@ -2636,7 +2636,7 @@ void IRGeneratorForStatements::appendBareCall( funKind == FunctionType::Kind::BareStaticCall, "" ); - solAssert(!_functionCall.annotation().tryCall, ""); + solAssert(!_functionCall.annotation().tryCall); Whiskers templ(R"( let := () @@ -2848,7 +2848,7 @@ string IRGeneratorForStatements::binaryOperation( "Not yet implemented - FixedPointType." ); IntegerType const* type = dynamic_cast(&_type); - solAssert(type, ""); + solAssert(type); bool checked = m_context.arithmetic() == Arithmetic::Checked; switch (_operator) { @@ -2888,9 +2888,9 @@ std::string IRGeneratorForStatements::shiftOperation( "Not yet implemented - FixedPointType." ); IntegerType const* amountType = dynamic_cast(&_amountToShift.type()); - solAssert(amountType, ""); + solAssert(amountType); - solAssert(_operator == Token::SHL || _operator == Token::SAR, ""); + solAssert(_operator == Token::SHL || _operator == Token::SAR); return Whiskers(R"( @@ -2909,7 +2909,7 @@ std::string IRGeneratorForStatements::shiftOperation( void IRGeneratorForStatements::appendAndOrOperatorCode(BinaryOperation const& _binOp) { langutil::Token const op = _binOp.getOperator(); - solAssert(op == Token::Or || op == Token::And, ""); + solAssert(op == Token::Or || op == Token::And); _binOp.leftExpression().accept(*this); setLocation(_binOp); @@ -2956,7 +2956,7 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable if (_memory.byteArrayElement) { - solAssert(_lvalue.type == *TypeProvider::byte(), ""); + solAssert(_lvalue.type == *TypeProvider::byte()); appendCode() << "mstore8(" + _memory.address + ", byte(0, " + prepared.commaSeparatedList() + "))\n"; } else @@ -2980,9 +2980,9 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable } else { - solAssert(_lvalue.type.sizeOnStack() == 1, ""); + solAssert(_lvalue.type.sizeOnStack() == 1); auto const* valueReferenceType = dynamic_cast(&_value.type()); - solAssert(valueReferenceType && valueReferenceType->dataStoredIn(DataLocation::Memory), ""); + solAssert(valueReferenceType && valueReferenceType->dataStoredIn(DataLocation::Memory)); appendCode() << "mstore(" + _memory.address + ", " + _value.part("mpos").name() + ")\n"; } }, @@ -2991,7 +2991,7 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable { solUnimplementedAssert(_lvalue.type.isValueType()); solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1); - solAssert(_lvalue.type == *_immutable.variable->type(), ""); + solAssert(_lvalue.type == *_immutable.variable->type()); size_t memOffset = m_context.immutableMemoryOffset(*_immutable.variable); IRVariable prepared(m_context.newYulVariable(), _lvalue.type); @@ -3051,7 +3051,7 @@ IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue) [&](IRLValue::Immutable const& _immutable) { solUnimplementedAssert(_lvalue.type.isValueType()); solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1); - solAssert(_lvalue.type == *_immutable.variable->type(), ""); + solAssert(_lvalue.type == *_immutable.variable->type()); if (m_context.executionContext() == IRGenerationContext::ExecutionContext::Creation) { string readFunction = m_utils.readFromMemory(*_immutable.variable->type()); @@ -3073,13 +3073,13 @@ IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue) void IRGeneratorForStatements::setLValue(Expression const& _expression, IRLValue _lvalue) { - solAssert(!m_currentLValue, ""); + solAssert(!m_currentLValue); if (_expression.annotation().willBeWrittenTo) { m_currentLValue.emplace(std::move(_lvalue)); if (_lvalue.type.dataStoredIn(DataLocation::CallData)) - solAssert(holds_alternative(_lvalue.kind), ""); + solAssert(holds_alternative(_lvalue.kind)); } else // Only define the expression, if it will not be written to. @@ -3153,7 +3153,7 @@ bool IRGeneratorForStatements::visit(TryStatement const& _tryStatement) size_t i = 0; for (ASTPointer const& varDecl: successClause.parameters()->parameters()) { - solAssert(varDecl, ""); + solAssert(varDecl); define(m_context.addLocalVariable(*varDecl), successClause.parameters()->parameters().size() == 1 ? IRVariable(externalCall) : @@ -3194,7 +3194,7 @@ void IRGeneratorForStatements::handleCatch(TryStatement const& _tryStatement) appendCode() << runFallback << " := 0\n"; if (errorClause->parameters()) { - solAssert(errorClause->parameters()->parameters().size() == 1, ""); + solAssert(errorClause->parameters()->parameters().size() == 1); IRVariable const& var = m_context.addLocalVariable(*errorClause->parameters()->parameters().front()); define(var) << dataVariable << "\n"; } @@ -3215,7 +3215,7 @@ void IRGeneratorForStatements::handleCatch(TryStatement const& _tryStatement) appendCode() << runFallback << " := 0\n"; if (panicClause->parameters()) { - solAssert(panicClause->parameters()->parameters().size() == 1, ""); + solAssert(panicClause->parameters()->parameters().size() == 1); IRVariable const& var = m_context.addLocalVariable(*panicClause->parameters()->parameters().front()); define(var) << code << "\n"; } @@ -3241,7 +3241,7 @@ void IRGeneratorForStatements::handleCatchFallback(TryCatchClause const& _fallba setLocation(_fallback); if (_fallback.parameters()) { - solAssert(m_context.evmVersion().supportsReturndata(), ""); + solAssert(m_context.evmVersion().supportsReturndata()); solAssert( _fallback.parameters()->parameters().size() == 1 && _fallback.parameters()->parameters().front() && @@ -3277,7 +3277,7 @@ void IRGeneratorForStatements::revertWithError( for (ASTPointer const& arg: _errorArguments) { errorArgumentVars += IRVariable(*arg).stackSlots(); - solAssert(arg->annotation().type, ""); + solAssert(arg->annotation().type); errorArgumentTypes.push_back(arg->annotation().type); } templ("argumentVars", joinHumanReadablePrefixed(errorArgumentVars)); @@ -3295,6 +3295,6 @@ bool IRGeneratorForStatements::visit(TryCatchClause const& _clause) string IRGeneratorForStatements::linkerSymbol(ContractDefinition const& _library) const { - solAssert(_library.isLibrary(), ""); + solAssert(_library.isLibrary()); return "linkersymbol(" + util::escapeAndQuoteString(_library.fullyQualifiedName()) + ")"; }