From c82f9b9fabd4ab1ba30ea917434b09813d46a6f9 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Thu, 19 Aug 2021 13:41:20 +0200 Subject: [PATCH 001/232] Mark recursive calls in yul control flow graph. --- libyul/backends/evm/ControlFlowGraph.h | 3 + .../backends/evm/ControlFlowGraphBuilder.cpp | 85 ++++++++++++++++--- 2 files changed, 74 insertions(+), 14 deletions(-) diff --git a/libyul/backends/evm/ControlFlowGraph.h b/libyul/backends/evm/ControlFlowGraph.h index 60bec498b..5a404938b 100644 --- a/libyul/backends/evm/ControlFlowGraph.h +++ b/libyul/backends/evm/ControlFlowGraph.h @@ -131,6 +131,9 @@ struct CFG std::shared_ptr debugData; std::reference_wrapper function; std::reference_wrapper functionCall; + /// True, if the call is recursive, i.e. entering the function involves a control flow path (potentially involving + /// more intermediate function calls) that leads back to this very call. + bool recursive = false; }; struct Assignment { diff --git a/libyul/backends/evm/ControlFlowGraphBuilder.cpp b/libyul/backends/evm/ControlFlowGraphBuilder.cpp index f3a1d5823..f4077f177 100644 --- a/libyul/backends/evm/ControlFlowGraphBuilder.cpp +++ b/libyul/backends/evm/ControlFlowGraphBuilder.cpp @@ -47,22 +47,14 @@ using namespace solidity; using namespace solidity::yul; using namespace std; -std::unique_ptr ControlFlowGraphBuilder::build( - AsmAnalysisInfo const& _analysisInfo, - Dialect const& _dialect, - Block const& _block -) +namespace +{ +// Removes edges to blocks that are not reachable. +void cleanUnreachable(CFG& _cfg) { - auto result = std::make_unique(); - result->entry = &result->makeBlock(); - - ControlFlowGraphBuilder builder(*result, _analysisInfo, _dialect); - builder.m_currentBlock = result->entry; - builder(_block); - // Determine which blocks are reachable from the entry. - util::BreadthFirstSearch reachabilityCheck{{result->entry}}; - for (auto const& functionInfo: result->functionInfo | ranges::views::values) + util::BreadthFirstSearch reachabilityCheck{{_cfg.entry}}; + for (auto const& functionInfo: _cfg.functionInfo | ranges::views::values) reachabilityCheck.verticesToTraverse.emplace_back(functionInfo.entry); reachabilityCheck.run([&](CFG::BasicBlock* _node, auto&& _addChild) { @@ -85,6 +77,71 @@ std::unique_ptr ControlFlowGraphBuilder::build( cxx20::erase_if(node->entries, [&](CFG::BasicBlock* entry) -> bool { return !reachabilityCheck.visited.count(entry); }); +} +// Sets the ``recursive`` member to ``true`` for all recursive function calls. +void markRecursiveCalls(CFG& _cfg) +{ + map> callsPerBlock; + auto const& findCalls = [&](CFG::BasicBlock* _block) + { + if (auto* calls = util::valueOrNullptr(callsPerBlock, _block)) + return *calls; + vector& calls = callsPerBlock[_block]; + util::BreadthFirstSearch{{_block}}.run([&](CFG::BasicBlock* _block, auto _addChild) { + for (auto& operation: _block->operations) + if (auto* functionCall = get_if(&operation.operation)) + calls.emplace_back(functionCall); + std::visit(util::GenericVisitor{ + [&](CFG::BasicBlock::MainExit const&) {}, + [&](CFG::BasicBlock::Jump const& _jump) + { + _addChild(_jump.target); + }, + [&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) + { + _addChild(_conditionalJump.zero); + _addChild(_conditionalJump.nonZero); + }, + [&](CFG::BasicBlock::FunctionReturn const&) {}, + [&](CFG::BasicBlock::Terminated const&) {}, + }, _block->exit); + }); + return calls; + }; + for (auto& functionInfo: _cfg.functionInfo | ranges::views::values) + for (CFG::FunctionCall* call: findCalls(functionInfo.entry)) + { + util::BreadthFirstSearch breadthFirstSearch{{call}}; + breadthFirstSearch.run([&](CFG::FunctionCall* _call, auto _addChild) { + auto& calledFunctionInfo = _cfg.functionInfo.at(&_call->function.get()); + if (&calledFunctionInfo == &functionInfo) + { + call->recursive = true; + breadthFirstSearch.abort(); + return; + } + for (CFG::FunctionCall* nestedCall: findCalls(_cfg.functionInfo.at(&_call->function.get()).entry)) + _addChild(nestedCall); + }); + } +} +} + +std::unique_ptr ControlFlowGraphBuilder::build( + AsmAnalysisInfo const& _analysisInfo, + Dialect const& _dialect, + Block const& _block +) +{ + auto result = std::make_unique(); + result->entry = &result->makeBlock(); + + ControlFlowGraphBuilder builder(*result, _analysisInfo, _dialect); + builder.m_currentBlock = result->entry; + builder(_block); + + cleanUnreachable(*result); + markRecursiveCalls(*result); // TODO: It might be worthwhile to run some further simplifications on the graph itself here. // E.g. if there is a jump to a node that has the jumping node as its only entry, the nodes can be fused, etc. From 803901fa7e7b14394747a846b486e7ef343252b8 Mon Sep 17 00:00:00 2001 From: priyansh786 Date: Mon, 30 Aug 2021 22:52:28 +0530 Subject: [PATCH 002/232] Don't create empty expectation files when updating test expectations --- test/cmdlineTests.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index b5742e3bb..5d87357f0 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -71,6 +71,15 @@ function update_expectation { local newExpectation="${1}" local expectationFile="${2}" + if [[ $newExpectation == "" || $newExpectation -eq 0 && $expectationFile == */exit ]] + then + if [[ -f $expectationFile ]] + then + rm "$expectationFile" + fi + return + fi + echo "$newExpectation" > "$expectationFile" printLog "File $expectationFile updated to match the expectation." } From f7916f2940d3266a28c001a08a474f0c6eb3df01 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 7 Jul 2021 14:53:56 +0200 Subject: [PATCH 003/232] Add override exception for interface functions. --- Changelog.md | 1 + docs/contracts/inheritance.rst | 7 +++++++ docs/contracts/interfaces.rst | 8 ++++---- libsolidity/analysis/OverrideChecker.cpp | 5 +++-- .../interface/overrides_multiple.sol | 2 -- .../interface/overrides_single.sol | 1 - .../override/calldata_memory_interface.sol | 8 ++++---- .../calldata_memory_interface_instantiate.sol | 2 +- .../calldata_memory_interface_struct.sol | 4 ++-- .../change_return_types_in_interface.sol | 1 - .../common_base_and_unique_implementation.sol | 12 ++++++------ .../common_base_and_unique_mention.sol | 4 ++-- ...ace_intermediate_public_state_variable.sol | 2 +- ...ate_public_state_variable_and_function.sol | 6 +++--- ...tate_variable_and_function_implemented.sol | 6 +++--- .../override/function_state_variable.sol | 2 +- ...implement_interface_by_public_variable.sol | 2 +- .../interface_exception/abstract_needed.sol | 8 ++++++++ .../interface_exception/diamond_needed.sol | 19 +++++++++++++++++++ .../interface_exception/regular_optional.sol | 11 +++++++++++ .../override/override_interface.sol | 2 ++ ...blic_var_implements_parallel_interface.sol | 8 ++++---- 22 files changed, 83 insertions(+), 38 deletions(-) create mode 100644 test/libsolidity/syntaxTests/inheritance/override/interface_exception/abstract_needed.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/interface_exception/diamond_needed.sol create mode 100644 test/libsolidity/syntaxTests/inheritance/override/interface_exception/regular_optional.sol diff --git a/Changelog.md b/Changelog.md index 25a4b1a32..def68a275 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,7 @@ ### 0.8.8 (unreleased) Language Features: + * Inheritance: A function that overrides only a single interface function does not require the ``override`` specifier. Compiler Features: diff --git a/docs/contracts/inheritance.rst b/docs/contracts/inheritance.rst index 24d2fd2ff..b77feda0a 100644 --- a/docs/contracts/inheritance.rst +++ b/docs/contracts/inheritance.rst @@ -303,6 +303,13 @@ contracts can no longer change the behaviour of that function. outside of interfaces. In interfaces, all functions are automatically considered ``virtual``. +.. note:: + + Starting from Solidity 0.8.8, the ``override`` keyword is not + required when overriding an interface function, except for the + case where the function is defined in multiple bases. + + Public state variables can override external functions if the parameter and return types of the function matches the getter function of the variable: diff --git a/docs/contracts/interfaces.rst b/docs/contracts/interfaces.rst index bfaf1bf2e..ae5a15e99 100644 --- a/docs/contracts/interfaces.rst +++ b/docs/contracts/interfaces.rst @@ -33,10 +33,10 @@ Interfaces are denoted by their own keyword: Contracts can inherit interfaces as they would inherit other contracts. -All functions declared in interfaces are implicitly ``virtual``, which means that -they can be overridden. This does not automatically mean that an overriding function -can be overridden again - this is only possible if the overriding -function is marked ``virtual``. +All functions declared in interfaces are implicitly ``virtual`` and any +functions that override them do not need the ``override`` keyword. +This does not automatically mean that an overriding function can be overridden again - +this is only possible if the overriding function is marked ``virtual``. Interfaces can inherit from other interfaces. This has the same rules as normal inheritance. diff --git a/libsolidity/analysis/OverrideChecker.cpp b/libsolidity/analysis/OverrideChecker.cpp index 18a40be40..6f44f92ac 100644 --- a/libsolidity/analysis/OverrideChecker.cpp +++ b/libsolidity/analysis/OverrideChecker.cpp @@ -86,7 +86,8 @@ private: int currentNode = static_cast(numNodes++); nodes[_function] = currentNode; nodeInv[currentNode] = _function; - if (_function.overrides()) + + if (!_function.baseFunctions().empty()) for (auto const& baseFunction: _function.baseFunctions()) addEdge(currentNode, visit(baseFunction)); else @@ -518,7 +519,7 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr "Override changes modifier signature." ); - if (!_overriding.overrides()) + if (!_overriding.overrides() && !(_super.isFunction() && _super.contract().isInterface())) overrideError( _overriding, _super, diff --git a/test/libsolidity/syntaxTests/inheritance/interface/overrides_multiple.sol b/test/libsolidity/syntaxTests/inheritance/interface/overrides_multiple.sol index 96f741471..9c2f39bd9 100644 --- a/test/libsolidity/syntaxTests/inheritance/interface/overrides_multiple.sol +++ b/test/libsolidity/syntaxTests/inheritance/interface/overrides_multiple.sol @@ -23,8 +23,6 @@ interface Sub is SuperA, SuperB { } // ---- -// TypeError 9456: (572-616): Overriding function is missing "override" specifier. -// TypeError 9456: (572-616): Overriding function is missing "override" specifier. // TypeError 4327: (572-616): Function needs to specify overridden contracts "SuperA" and "SuperB". // TypeError 4327: (647-655): Function needs to specify overridden contracts "SuperA" and "SuperB". // TypeError 4327: (705-721): Function needs to specify overridden contract "SuperB". diff --git a/test/libsolidity/syntaxTests/inheritance/interface/overrides_single.sol b/test/libsolidity/syntaxTests/inheritance/interface/overrides_single.sol index 106fb8975..bed7026dd 100644 --- a/test/libsolidity/syntaxTests/inheritance/interface/overrides_single.sol +++ b/test/libsolidity/syntaxTests/inheritance/interface/overrides_single.sol @@ -11,4 +11,3 @@ interface Sub is Super { } // ---- -// TypeError 9456: (197-241): Overriding function is missing "override" specifier. diff --git a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface.sol b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface.sol index 33b66a86f..7be022c02 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface.sol @@ -6,9 +6,9 @@ interface I { } contract C is I { uint dummy; - function f(uint[] memory) public override pure {} - function g(uint[] memory) public override view { dummy; } - function h(uint[] memory) public override { dummy = 42; } - function i(uint[] memory) public override payable {} + function f(uint[] memory) public pure {} + function g(uint[] memory) public view { dummy; } + function h(uint[] memory) public { dummy = 42; } + function i(uint[] memory) public payable {} } // ---- diff --git a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface_instantiate.sol b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface_instantiate.sol index 1a1ec2971..2c1045802 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface_instantiate.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface_instantiate.sol @@ -2,7 +2,7 @@ interface I { function f(uint[] calldata) external pure; } contract A is I { - function f(uint[] memory) public override pure {} + function f(uint[] memory) public pure {} } contract C { function f() public { diff --git a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface_struct.sol b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface_struct.sol index e77836724..1ba73bb97 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface_struct.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/calldata_memory_interface_struct.sol @@ -9,8 +9,8 @@ interface I { contract C is I { uint dummy; function f(S memory) public override pure {} - function g(S memory) public override view { dummy; } + function g(S memory) public view { dummy; } function h(S memory) public override { dummy = 42; } - function i(S memory) public override payable {} + function i(S memory) public payable {} } // ---- diff --git a/test/libsolidity/syntaxTests/inheritance/override/change_return_types_in_interface.sol b/test/libsolidity/syntaxTests/inheritance/override/change_return_types_in_interface.sol index 8a477b70d..2ac2734c5 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/change_return_types_in_interface.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/change_return_types_in_interface.sol @@ -7,5 +7,4 @@ contract B is I { function f() public pure returns (uint, uint) {} } // ---- -// TypeError 9456: (182-230): Overriding function is missing "override" specifier. // TypeError 4822: (182-230): Overriding function return types differ. diff --git a/test/libsolidity/syntaxTests/inheritance/override/common_base_and_unique_implementation.sol b/test/libsolidity/syntaxTests/inheritance/override/common_base_and_unique_implementation.sol index 0164d4dd1..cc065bbee 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/common_base_and_unique_implementation.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/common_base_and_unique_implementation.sol @@ -3,15 +3,15 @@ interface I { function g() external; } abstract contract A is I { - function f() external override {} - function g() external override virtual; + function f() external {} + function g() external virtual; } abstract contract B is I { - function g() external override {} - function f() external override virtual; + function g() external {} + function f() external virtual; } contract C is A, B { } // ---- -// TypeError 6480: (292-314): Derived contract must override function "f". Two or more base classes define function with same name and parameter types. -// TypeError 6480: (292-314): Derived contract must override function "g". Two or more base classes define function with same name and parameter types. +// TypeError 6480: (256-278): Derived contract must override function "f". Two or more base classes define function with same name and parameter types. +// TypeError 6480: (256-278): Derived contract must override function "g". Two or more base classes define function with same name and parameter types. diff --git a/test/libsolidity/syntaxTests/inheritance/override/common_base_and_unique_mention.sol b/test/libsolidity/syntaxTests/inheritance/override/common_base_and_unique_mention.sol index c258bd219..7a4244941 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/common_base_and_unique_mention.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/common_base_and_unique_mention.sol @@ -3,10 +3,10 @@ interface I { function g() external; } abstract contract A is I { - function f() external override {} + function f() external {} } abstract contract B is I { - function g() external override {} + function g() external {} } contract C is A, B { } diff --git a/test/libsolidity/syntaxTests/inheritance/override/diamond_interface_intermediate_public_state_variable.sol b/test/libsolidity/syntaxTests/inheritance/override/diamond_interface_intermediate_public_state_variable.sol index 1903f08ae..7d0a0740c 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/diamond_interface_intermediate_public_state_variable.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/diamond_interface_intermediate_public_state_variable.sol @@ -3,7 +3,7 @@ interface I { } abstract contract A is I { - uint public override f; + uint public f; } abstract contract B is I { diff --git a/test/libsolidity/syntaxTests/inheritance/override/diamond_interface_intermediate_public_state_variable_and_function.sol b/test/libsolidity/syntaxTests/inheritance/override/diamond_interface_intermediate_public_state_variable_and_function.sol index 90c747dc4..4ea1ab4c0 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/diamond_interface_intermediate_public_state_variable_and_function.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/diamond_interface_intermediate_public_state_variable_and_function.sol @@ -3,12 +3,12 @@ interface I { } contract A is I { - uint public override f; + uint public f; } abstract contract B is I { - function f() external virtual override returns (uint); + function f() external virtual returns (uint); } abstract contract C is A, B {} // ---- -// TypeError 6480: (185-215): Derived contract must override function "f". Two or more base classes define function with same name and parameter types. Since one of the bases defines a public state variable which cannot be overridden, you have to change the inheritance layout or the names of the functions. +// TypeError 6480: (167-197): Derived contract must override function "f". Two or more base classes define function with same name and parameter types. Since one of the bases defines a public state variable which cannot be overridden, you have to change the inheritance layout or the names of the functions. diff --git a/test/libsolidity/syntaxTests/inheritance/override/diamond_interface_intermediate_public_state_variable_and_function_implemented.sol b/test/libsolidity/syntaxTests/inheritance/override/diamond_interface_intermediate_public_state_variable_and_function_implemented.sol index add03e5cb..90efce554 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/diamond_interface_intermediate_public_state_variable_and_function_implemented.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/diamond_interface_intermediate_public_state_variable_and_function_implemented.sol @@ -3,12 +3,12 @@ interface I { } contract A is I { - uint public override f; + uint public f; } abstract contract B is I { - function f() external virtual override returns (uint) { return 2; } + function f() external virtual returns (uint) { return 2; } } abstract contract C is A, B {} // ---- -// TypeError 6480: (198-228): Derived contract must override function "f". Two or more base classes define function with same name and parameter types. Since one of the bases defines a public state variable which cannot be overridden, you have to change the inheritance layout or the names of the functions. +// TypeError 6480: (180-210): Derived contract must override function "f". Two or more base classes define function with same name and parameter types. Since one of the bases defines a public state variable which cannot be overridden, you have to change the inheritance layout or the names of the functions. diff --git a/test/libsolidity/syntaxTests/inheritance/override/function_state_variable.sol b/test/libsolidity/syntaxTests/inheritance/override/function_state_variable.sol index d1e5eb306..ccb567099 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/function_state_variable.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/function_state_variable.sol @@ -1,3 +1,3 @@ interface ERC20 { function x() external returns (uint); } -contract C is ERC20 { uint public override x; } +contract C is ERC20 { uint public x; } // ---- diff --git a/test/libsolidity/syntaxTests/inheritance/override/implement_interface_by_public_variable.sol b/test/libsolidity/syntaxTests/inheritance/override/implement_interface_by_public_variable.sol index 5f493f515..d98e253c5 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/implement_interface_by_public_variable.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/implement_interface_by_public_variable.sol @@ -1,6 +1,6 @@ interface X { function test() external returns (uint256); } contract Y is X { - uint256 public override test = 42; + uint256 public test = 42; } contract T { constructor() { new Y(); } diff --git a/test/libsolidity/syntaxTests/inheritance/override/interface_exception/abstract_needed.sol b/test/libsolidity/syntaxTests/inheritance/override/interface_exception/abstract_needed.sol new file mode 100644 index 000000000..97290af9c --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/interface_exception/abstract_needed.sol @@ -0,0 +1,8 @@ +abstract contract I { + function f() external virtual; +} +contract C is I { + function f() external {} +} +// ---- +// TypeError 9456: (75-99): Overriding function is missing "override" specifier. diff --git a/test/libsolidity/syntaxTests/inheritance/override/interface_exception/diamond_needed.sol b/test/libsolidity/syntaxTests/inheritance/override/interface_exception/diamond_needed.sol new file mode 100644 index 000000000..6c46e0a8b --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/interface_exception/diamond_needed.sol @@ -0,0 +1,19 @@ +interface I { + function f() external; + function g() external; + function h() external; +} +interface J { + function f() external; + function g() external; + function h() external; +} +contract C is I, J { + function f() external {} + function g() external override {} + function h() external override(I) {} +} +// ---- +// TypeError 4327: (198-222): Function needs to specify overridden contracts "I" and "J". +// TypeError 4327: (246-254): Function needs to specify overridden contracts "I" and "J". +// TypeError 4327: (281-292): Function needs to specify overridden contract "J". diff --git a/test/libsolidity/syntaxTests/inheritance/override/interface_exception/regular_optional.sol b/test/libsolidity/syntaxTests/inheritance/override/interface_exception/regular_optional.sol new file mode 100644 index 000000000..b2f1d7c13 --- /dev/null +++ b/test/libsolidity/syntaxTests/inheritance/override/interface_exception/regular_optional.sol @@ -0,0 +1,11 @@ +interface I { + function f() external; + function g() external; + function h() external; +} +contract C is I { + function f() external {} + function g() external override {} + function h() external override(I) {} +} +// ---- diff --git a/test/libsolidity/syntaxTests/inheritance/override/override_interface.sol b/test/libsolidity/syntaxTests/inheritance/override/override_interface.sol index 8b70bdbb6..9f2635511 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/override_interface.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/override_interface.sol @@ -1,9 +1,11 @@ interface A { function test() external returns (uint256); function test2() external returns (uint256); + function test3() external returns (uint256); } contract X is A { function test() external override returns (uint256) {} function test2() external override(A) returns (uint256) {} + function test3() external returns (uint256) {} } // ---- diff --git a/test/libsolidity/syntaxTests/inheritance/override/public_var_implements_parallel_interface.sol b/test/libsolidity/syntaxTests/inheritance/override/public_var_implements_parallel_interface.sol index dc2f7b16a..eeb2574d5 100644 --- a/test/libsolidity/syntaxTests/inheritance/override/public_var_implements_parallel_interface.sol +++ b/test/libsolidity/syntaxTests/inheritance/override/public_var_implements_parallel_interface.sol @@ -11,11 +11,11 @@ contract X is A, B { function goo() external virtual override(A, B) returns (uint) {} } abstract contract T is A { - function foo() external virtual override returns (uint); - function goo() external virtual override returns (uint); + function foo() external virtual returns (uint); + function goo() external virtual returns (uint); } contract Y is X, T { } // ---- -// TypeError 6480: (484-506): Derived contract must override function "foo". Two or more base classes define function with same name and parameter types. Since one of the bases defines a public state variable which cannot be overridden, you have to change the inheritance layout or the names of the functions. -// TypeError 6480: (484-506): Derived contract must override function "goo". Two or more base classes define function with same name and parameter types. +// TypeError 6480: (466-488): Derived contract must override function "foo". Two or more base classes define function with same name and parameter types. Since one of the bases defines a public state variable which cannot be overridden, you have to change the inheritance layout or the names of the functions. +// TypeError 6480: (466-488): Derived contract must override function "goo". Two or more base classes define function with same name and parameter types. From 9033660b22686f6a6237b7a4b6e955451aafbf04 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 31 Aug 2021 14:32:32 +0200 Subject: [PATCH 004/232] Clarify function call options example. --- docs/control-structures.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 95a55f6c6..37a4fcd12 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -105,8 +105,10 @@ otherwise, the ``value`` option would not be available. .. warning:: Be careful that ``feed.info{value: 10, gas: 800}`` only locally sets the ``value`` and amount of ``gas`` sent with the function call, and the - parentheses at the end perform the actual call. So in this case, the - function is not called and the ``value`` and ``gas`` settings are lost. + parentheses at the end perform the actual call. So + ``feed.info{value: 10, gas: 800}`` does not call the function and + the ``value`` and ``gas`` settings are lost, only + ``feed.info{value: 10, gas: 800}()`` performs the function call. Due to the fact that the EVM considers a call to a non-existing contract to always succeed, Solidity uses the ``extcodesize`` opcode to check that From 58e4cc62e0a62ee050f0835af78f04ce7f22ad61 Mon Sep 17 00:00:00 2001 From: benldrmn Date: Sat, 14 Aug 2021 21:29:59 +0300 Subject: [PATCH 005/232] Increase use of C++ constexpr constant expressions in code base as described in issue #7720 --- CODING_STYLE.md | 2 +- libsolidity/analysis/DocStringTagParser.cpp | 3 ++- libyul/Utilities.cpp | 2 +- test/EVMHost.cpp | 2 +- test/ExecutionFramework.h | 5 ++--- test/tools/fuzzer_common.cpp | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CODING_STYLE.md b/CODING_STYLE.md index 1d897a53f..674c2addd 100644 --- a/CODING_STYLE.md +++ b/CODING_STYLE.md @@ -81,7 +81,7 @@ tuple myNamespace::meanAndSigma(vector const& _v) - Copyright - License (e.g. see COPYING) 2. Never use `#ifdef`/`#define`/`#endif` file guards. Prefer `#pragma` once as first line below file comment. -3. Prefer static const variable to value macros. +3. Prefer static constexpr variables to value macros. 4. Prefer inline constexpr functions to function macros. 5. Split complex macro on multiple lines with `\`. diff --git a/libsolidity/analysis/DocStringTagParser.cpp b/libsolidity/analysis/DocStringTagParser.cpp index 52fb4aebe..137cdb409 100644 --- a/libsolidity/analysis/DocStringTagParser.cpp +++ b/libsolidity/analysis/DocStringTagParser.cpp @@ -34,6 +34,7 @@ #include #include +#include using namespace std; using namespace solidity; @@ -233,7 +234,7 @@ void DocStringTagParser::parseDocStrings( for (auto const& [tagName, tagValue]: _annotation.docTags) { - string static const customPrefix("custom:"); + string_view static constexpr customPrefix("custom:"); if (tagName == "custom" || tagName == "custom:") m_errorReporter.docstringParsingError( 6564_error, diff --git a/libyul/Utilities.cpp b/libyul/Utilities.cpp index 38fe379aa..8db0e44ff 100644 --- a/libyul/Utilities.cpp +++ b/libyul/Utilities.cpp @@ -42,7 +42,7 @@ string solidity::yul::reindent(string const& _code) { int constexpr indentationWidth = 4; - auto const static countBraces = [](string const& _s) noexcept -> int + auto constexpr static countBraces = [](string const& _s) noexcept -> int { auto const i = _s.find("//"); auto const e = i == _s.npos ? end(_s) : next(begin(_s), static_cast(i)); diff --git a/test/EVMHost.cpp b/test/EVMHost.cpp index 6d925f4d2..6c5cb6912 100644 --- a/test/EVMHost.cpp +++ b/test/EVMHost.cpp @@ -856,7 +856,7 @@ void EVMHostPrinter::selfdestructRecords() void EVMHostPrinter::callRecords() { - static const auto callKind = [](evmc_call_kind _kind) -> string + static auto constexpr callKind = [](evmc_call_kind _kind) -> string { switch (_kind) { diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h index d6912c5d0..7a10d72e3 100644 --- a/test/ExecutionFramework.h +++ b/test/ExecutionFramework.h @@ -49,9 +49,8 @@ namespace solidity::test using rational = boost::rational; // The ether and gwei denominations; here for ease of use where needed within code. -static const u256 gwei = u256(1) << 9; -static const u256 ether = u256(1) << 18; - +static u256 const gwei = u256(1) << 9; +static u256 const ether = u256(1) << 18; class ExecutionFramework { diff --git a/test/tools/fuzzer_common.cpp b/test/tools/fuzzer_common.cpp index 5a1849ea6..332b9fc04 100644 --- a/test/tools/fuzzer_common.cpp +++ b/test/tools/fuzzer_common.cpp @@ -78,7 +78,7 @@ void FuzzerUtil::testCompilerJsonInterface(string const& _input, bool _optimize, void FuzzerUtil::forceSMT(StringMap& _input) { // Add SMT checker pragma if not already present in source - static const char* smtPragma = "pragma experimental SMTChecker;"; + static auto constexpr smtPragma = "pragma experimental SMTChecker;"; for (auto &sourceUnit: _input) if (sourceUnit.second.find(smtPragma) == string::npos) sourceUnit.second += smtPragma; From d07b796675d8750d07b9cb9ccd7508fb23219bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 25 Jun 2021 12:40:01 +0200 Subject: [PATCH 006/232] Disallow modifier declarations and definitions in interfaces --- Changelog.md | 3 ++- docs/contracts/interfaces.rst | 4 +++- libsolidity/analysis/TypeChecker.cpp | 24 ++++++++++++------- .../analysis/FunctionCallGraph.cpp | 5 ++-- .../modifiers/definition_in_contract.sol | 11 +++++++++ .../definition_in_contract_unimplemented.sol | 7 ++++++ .../modifiers/definition_in_interface.sol | 12 ++++++++++ .../modifiers/definition_in_library.sol | 5 ++++ .../definition_in_library_unimplemented.sol | 7 ++++++ .../definition_in_library_virtual.sol | 4 ++++ .../use_on_interface_function.sol} | 1 + 11 files changed, 71 insertions(+), 12 deletions(-) create mode 100644 test/libsolidity/syntaxTests/modifiers/definition_in_contract.sol create mode 100644 test/libsolidity/syntaxTests/modifiers/definition_in_contract_unimplemented.sol create mode 100644 test/libsolidity/syntaxTests/modifiers/definition_in_interface.sol create mode 100644 test/libsolidity/syntaxTests/modifiers/definition_in_library.sol create mode 100644 test/libsolidity/syntaxTests/modifiers/definition_in_library_unimplemented.sol create mode 100644 test/libsolidity/syntaxTests/modifiers/definition_in_library_virtual.sol rename test/libsolidity/syntaxTests/{nameAndTypeResolution/588_interface_function_modifier.sol => modifiers/use_on_interface_function.sol} (67%) diff --git a/Changelog.md b/Changelog.md index def68a275..1bbf51ff2 100644 --- a/Changelog.md +++ b/Changelog.md @@ -13,9 +13,10 @@ Compiler Features: Bugfixes: + * SMTChecker: Fix false negative caused by ``push`` on storage array references returned by internal functions. * SMTChecker: Fix false positive in external calls from constructors. * SMTChecker: Fix internal error on some multi-source uses of ``abi.*``, cryptographic functions and constants. - * SMTChecker: Fix false negative caused by ``push`` on storage array references returned by internal functions. + * Type Checker: Disallow modifier declarations and definitions in interfaces. diff --git a/docs/contracts/interfaces.rst b/docs/contracts/interfaces.rst index ae5a15e99..a4581a15f 100644 --- a/docs/contracts/interfaces.rst +++ b/docs/contracts/interfaces.rst @@ -6,12 +6,14 @@ Interfaces ********** -Interfaces are similar to abstract contracts, but they cannot have any functions implemented. There are further restrictions: +Interfaces are similar to abstract contracts, but they cannot have any functions implemented. +There are further restrictions: - They cannot inherit from other contracts, but they can inherit from other interfaces. - All declared functions must be external. - They cannot declare a constructor. - They cannot declare state variables. +- They cannot declare modifiers. Some of these restrictions might be lifted in the future. diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 2f545c7ef..f6e89886f 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -314,14 +314,22 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance) void TypeChecker::endVisit(ModifierDefinition const& _modifier) { - if (_modifier.virtualSemantics()) - if (auto const* contractDef = dynamic_cast(_modifier.scope())) - if (contractDef->isLibrary()) - m_errorReporter.typeError( - 3275_error, - _modifier.location(), - "Modifiers in a library cannot be virtual." - ); + if (auto const* contractDef = dynamic_cast(_modifier.scope())) + { + if (_modifier.virtualSemantics() && contractDef->isLibrary()) + m_errorReporter.typeError( + 3275_error, + _modifier.location(), + "Modifiers in a library cannot be virtual." + ); + + if (contractDef->isInterface()) + m_errorReporter.typeError( + 6408_error, + _modifier.location(), + "Modifiers cannot be defined or declared in interfaces." + ); + } if (!_modifier.isImplemented() && !_modifier.virtualSemantics()) m_errorReporter.typeError(8063_error, _modifier.location(), "Modifiers without implementation must be marked virtual."); diff --git a/test/libsolidity/analysis/FunctionCallGraph.cpp b/test/libsolidity/analysis/FunctionCallGraph.cpp index af6eac2c4..30477aa2e 100644 --- a/test/libsolidity/analysis/FunctionCallGraph.cpp +++ b/test/libsolidity/analysis/FunctionCallGraph.cpp @@ -1114,7 +1114,6 @@ BOOST_AUTO_TEST_CASE(interfaces_and_abstract_contracts) unique_ptr compilerStack = parseAndAnalyzeContracts(R"( interface I { event Ev(uint); - modifier m() virtual; function ext1() external; function ext2() external; @@ -1126,6 +1125,8 @@ BOOST_AUTO_TEST_CASE(interfaces_and_abstract_contracts) } abstract contract C is J { + modifier m() virtual; + function ext3() external override virtual; function ext4() external { inr2();} function inr1() internal virtual; @@ -1167,7 +1168,7 @@ BOOST_AUTO_TEST_CASE(interfaces_and_abstract_contracts) {"Entry", "function C.ext4()"}, {"function C.ext4()", "function C.inr2()"}, {"function C.inr2()", "function C.inr1()"}, - {"function C.inr2()", "modifier I.m"}, + {"function C.inr2()", "modifier C.m"}, }}, {"D", { {"Entry", "function D.ext1()"}, diff --git a/test/libsolidity/syntaxTests/modifiers/definition_in_contract.sol b/test/libsolidity/syntaxTests/modifiers/definition_in_contract.sol new file mode 100644 index 000000000..9b0a805ad --- /dev/null +++ b/test/libsolidity/syntaxTests/modifiers/definition_in_contract.sol @@ -0,0 +1,11 @@ +contract C { + modifier m { _; } + modifier mv virtual { _; } +} + +abstract contract A { + modifier m { _; } + modifier mv virtual { _; } + modifier muv virtual; +} +// ---- diff --git a/test/libsolidity/syntaxTests/modifiers/definition_in_contract_unimplemented.sol b/test/libsolidity/syntaxTests/modifiers/definition_in_contract_unimplemented.sol new file mode 100644 index 000000000..2018ae4ea --- /dev/null +++ b/test/libsolidity/syntaxTests/modifiers/definition_in_contract_unimplemented.sol @@ -0,0 +1,7 @@ +contract C { + modifier mu; + modifier muv virtual; +} +// ---- +// TypeError 3656: (0-57): Contract "C" should be marked as abstract. +// TypeError 8063: (17-29): Modifiers without implementation must be marked virtual. diff --git a/test/libsolidity/syntaxTests/modifiers/definition_in_interface.sol b/test/libsolidity/syntaxTests/modifiers/definition_in_interface.sol new file mode 100644 index 000000000..2f8281bde --- /dev/null +++ b/test/libsolidity/syntaxTests/modifiers/definition_in_interface.sol @@ -0,0 +1,12 @@ +interface I { + modifier m { _; } + modifier mu; + modifier mv virtual { _; } + modifier muv virtual; +} +// ---- +// TypeError 6408: (18-35): Modifiers cannot be defined or declared in interfaces. +// TypeError 6408: (40-52): Modifiers cannot be defined or declared in interfaces. +// TypeError 8063: (40-52): Modifiers without implementation must be marked virtual. +// TypeError 6408: (57-83): Modifiers cannot be defined or declared in interfaces. +// TypeError 6408: (88-109): Modifiers cannot be defined or declared in interfaces. diff --git a/test/libsolidity/syntaxTests/modifiers/definition_in_library.sol b/test/libsolidity/syntaxTests/modifiers/definition_in_library.sol new file mode 100644 index 000000000..6acbf3a0f --- /dev/null +++ b/test/libsolidity/syntaxTests/modifiers/definition_in_library.sol @@ -0,0 +1,5 @@ +library L { + modifier mv virtual { _; } +} +// ---- +// TypeError 3275: (16-42): Modifiers in a library cannot be virtual. diff --git a/test/libsolidity/syntaxTests/modifiers/definition_in_library_unimplemented.sol b/test/libsolidity/syntaxTests/modifiers/definition_in_library_unimplemented.sol new file mode 100644 index 000000000..5fbc35682 --- /dev/null +++ b/test/libsolidity/syntaxTests/modifiers/definition_in_library_unimplemented.sol @@ -0,0 +1,7 @@ +library L { + modifier mu; + modifier muv virtual; +} +// ---- +// TypeError 8063: (16-28): Modifiers without implementation must be marked virtual. +// TypeError 3275: (33-54): Modifiers in a library cannot be virtual. diff --git a/test/libsolidity/syntaxTests/modifiers/definition_in_library_virtual.sol b/test/libsolidity/syntaxTests/modifiers/definition_in_library_virtual.sol new file mode 100644 index 000000000..173a94536 --- /dev/null +++ b/test/libsolidity/syntaxTests/modifiers/definition_in_library_virtual.sol @@ -0,0 +1,4 @@ +library L { + modifier m { _; } +} +// ---- diff --git a/test/libsolidity/syntaxTests/nameAndTypeResolution/588_interface_function_modifier.sol b/test/libsolidity/syntaxTests/modifiers/use_on_interface_function.sol similarity index 67% rename from test/libsolidity/syntaxTests/nameAndTypeResolution/588_interface_function_modifier.sol rename to test/libsolidity/syntaxTests/modifiers/use_on_interface_function.sol index e506828d0..febdd9615 100644 --- a/test/libsolidity/syntaxTests/nameAndTypeResolution/588_interface_function_modifier.sol +++ b/test/libsolidity/syntaxTests/modifiers/use_on_interface_function.sol @@ -4,3 +4,4 @@ interface I { } // ---- // SyntaxError 5842: (16-60): Functions in interfaces cannot have modifiers. +// TypeError 6408: (63-82): Modifiers cannot be defined or declared in interfaces. From 427aec2cb4be8ddbba567f5a4faeac7aef496a33 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Tue, 31 Aug 2021 12:08:35 +0200 Subject: [PATCH 007/232] Circle CI: Introduce default evm version parameter; remove hard-coded setting. --- .circleci/config.yml | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index bf047b5a6..402bd8ff1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -23,6 +23,9 @@ parameters: type: string # solbuildpackpusher/solidity-buildpack-deps:emscripten-6 default: "solbuildpackpusher/solidity-buildpack-deps@sha256:092da5817bc032c91a806b4f73db2a1a31e5cc4c066d94d43eedd9f365df7154" + evm-version: + type: string + default: london orbs: win: circleci/windows@2.2.0 @@ -523,7 +526,7 @@ jobs: t_ubu_codecov: <<: *test_ubuntu2004 environment: - EVM: constantinople + EVM: << pipeline.parameters.evm-version >> OPTIMIZE: 1 steps: - checkout @@ -642,7 +645,7 @@ jobs: macos: xcode: "11.0.0" environment: - EVM: constantinople + EVM: << pipeline.parameters.evm-version >> OPTIMIZE: 0 TERM: xterm steps: @@ -731,7 +734,7 @@ jobs: # See https://github.com/ethereum/solidity/pull/11332 - image: archlinux:base-20210131.0.14634 environment: - EVM: constantinople + EVM: << pipeline.parameters.evm-version >> OPTIMIZE: 0 TERM: xterm # For Archlinux we do not have prebuilt docker images and we would need to build evmone from source, @@ -756,7 +759,7 @@ jobs: docker: - image: << pipeline.parameters.ubuntu-2004-docker-image >> environment: - EVM: constantinople + EVM: << pipeline.parameters.evm-version >> SOLTEST_FLAGS: --enforce-via-yul OPTIMIZE: 0 TERM: xterm @@ -772,7 +775,7 @@ jobs: t_ubu_clang_soltest: &t_ubu_clang_soltest <<: *test_ubuntu2004_clang environment: - EVM: constantinople + EVM: << pipeline.parameters.evm-version >> OPTIMIZE: 0 t_ubu_release_soltest: &t_ubu_release_soltest @@ -795,23 +798,25 @@ jobs: ASAN_OPTIONS: check_initialization_order=true:detect_stack_use_after_return=true:strict_init_order=true:strict_string_checks=true:detect_invalid_pointer_pairs=2 <<: *run_cmdline_tests_steps - t_ubu_asan_constantinople: + t_ubu_asan: <<: *test_asan environment: - EVM: constantinople + EVM: << pipeline.parameters.evm-version >> OPTIMIZE: 0 SOLTEST_FLAGS: --no-smt ASAN_OPTIONS: check_initialization_order=true:detect_stack_use_after_return=true:strict_init_order=true:strict_string_checks=true:detect_invalid_pointer_pairs=2 - t_ubu_asan_constantinople_clang: + t_ubu_asan_clang: <<: *test_ubuntu2004_clang environment: - EVM: constantinople + EVM: << pipeline.parameters.evm-version >> OPTIMIZE: 0 SOLTEST_FLAGS: --no-smt ASAN_OPTIONS: check_initialization_order=true:detect_stack_use_after_return=true:strict_init_order=true:strict_string_checks=true:detect_invalid_pointer_pairs=2 t_ubu_ubsan_clang: + environment: + EVM: << pipeline.parameters.evm-version >> docker: - image: << pipeline.parameters.ubuntu-2004-clang-docker-image >> steps: @@ -1230,8 +1235,8 @@ workflows: # ASan build and tests - b_ubu_asan: *workflow_trigger_on_tags - b_ubu_asan_clang: *workflow_trigger_on_tags - - t_ubu_asan_constantinople: *workflow_ubuntu2004_asan - - t_ubu_asan_constantinople_clang: *workflow_ubuntu2004_asan_clang + - t_ubu_asan: *workflow_ubuntu2004_asan + - t_ubu_asan_clang: *workflow_ubuntu2004_asan_clang - t_ubu_asan_cli: *workflow_ubuntu2004_asan # UBSan build and tests From 2b28f87abf9fcb9cb1a7d44776464e129aa10e85 Mon Sep 17 00:00:00 2001 From: Marenz Date: Thu, 26 Aug 2021 18:03:16 +0200 Subject: [PATCH 008/232] Add type().min/max for enums --- Changelog.md | 1 + docs/types/value-types.rst | 13 ++++++++++- libsolidity/analysis/TypeChecker.cpp | 7 ++++-- libsolidity/ast/TypeProvider.cpp | 5 +++-- libsolidity/ast/Types.cpp | 13 +++++++++-- libsolidity/ast/Types.h | 6 +++++ libsolidity/codegen/ExpressionCompiler.cpp | 11 +++++----- .../codegen/ir/IRGeneratorForStatements.cpp | 22 +++++++++++++++---- libsolidity/formal/SMTEncoder.cpp | 6 +++-- .../semanticTests/enums/minmax.sol | 12 ++++++++++ .../concat/bytes_concat_on_type_info.sol | 2 +- .../metaTypes/codeAccess_super.sol | 2 +- .../metaTypes/interfaceid_super.sol | 2 +- .../syntaxTests/metaTypes/super_name.sol | 2 +- .../syntaxTests/metaTypes/typeRecursive.sol | 2 +- .../metaTypes/unsupportedArgForType.sol | 2 +- .../syntaxTests/tryCatch/no_special.sol | 2 +- 17 files changed, 85 insertions(+), 25 deletions(-) create mode 100644 test/libsolidity/semanticTests/enums/minmax.sol diff --git a/Changelog.md b/Changelog.md index 1bbf51ff2..b187d009c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ Language Features: * Inheritance: A function that overrides only a single interface function does not require the ``override`` specifier. + * Type System: Support ``type().min`` and ``type().max`` for enums. Compiler Features: diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index 776cddf19..e3d6ed0d7 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -587,11 +587,14 @@ Enums cannot have more than 256 members. The data representation is the same as for enums in C: The options are represented by subsequent unsigned integer values starting from ``0``. +Using ``type(NameOfEnum).min`` and ``type(NameOfEnum).max`` you can get the +smallest and respectively largest value of the given enum. + .. code-block:: solidity // SPDX-License-Identifier: GPL-3.0 - pragma solidity >=0.4.16 <0.9.0; + pragma solidity ^0.8.8; contract test { enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill } @@ -612,6 +615,14 @@ subsequent unsigned integer values starting from ``0``. function getDefaultChoice() public pure returns (uint) { return uint(defaultChoice); } + + function getLargestValue() public pure returns (ActionChoices) { + return type(ActionChoices).max; + } + + function getSmallestValue() public pure returns (ActionChoices) { + return type(ActionChoices).min; + } } .. note:: diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index f6e89886f..61c4208af 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -246,7 +246,10 @@ TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(Functio Type::Category typeCategory = typeTypePtr->actualType()->category(); if (auto const* contractType = dynamic_cast(typeTypePtr->actualType())) wrongType = contractType->isSuper(); - else if (typeCategory != Type::Category::Integer) + else if ( + typeCategory != Type::Category::Integer && + typeCategory != Type::Category::Enum + ) wrongType = true; } else @@ -257,7 +260,7 @@ TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(Functio 4259_error, arguments.front()->location(), "Invalid type for argument in the function call. " - "A contract type or an integer type is required, but " + + "An enum type, contract type or an integer type is required, but " + type(*arguments.front())->toString(true) + " provided." ); diff --git a/libsolidity/ast/TypeProvider.cpp b/libsolidity/ast/TypeProvider.cpp index cc810708e..ee7a65004 100644 --- a/libsolidity/ast/TypeProvider.cpp +++ b/libsolidity/ast/TypeProvider.cpp @@ -566,9 +566,10 @@ MagicType const* TypeProvider::meta(Type const* _type) solAssert( _type && ( _type->category() == Type::Category::Contract || - _type->category() == Type::Category::Integer + _type->category() == Type::Category::Integer || + _type->category() == Type::Category::Enum ), - "Only contracts or integer types supported for now." + "Only enum, contracts or integer types supported for now." ); return createAndGet(_type); } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index e0928fe35..0fe9a728f 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -3961,9 +3961,10 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const solAssert( m_typeArgument && ( m_typeArgument->category() == Type::Category::Contract || - m_typeArgument->category() == Type::Category::Integer + m_typeArgument->category() == Type::Category::Integer || + m_typeArgument->category() == Type::Category::Enum ), - "Only contracts or integer types supported for now" + "Only enums, contracts or integer types supported for now" ); if (m_typeArgument->category() == Type::Category::Contract) @@ -3989,6 +3990,14 @@ MemberList::MemberMap MagicType::nativeMembers(ASTNode const*) const {"max", integerTypePointer}, }); } + else if (m_typeArgument->category() == Type::Category::Enum) + { + EnumType const* enumTypePointer = dynamic_cast(m_typeArgument); + return MemberList::MemberMap({ + {"min", enumTypePointer}, + {"max", enumTypePointer}, + }); + } } } solAssert(false, "Unknown kind of magic."); diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 50a8fb6ca..57f5201f6 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -1071,6 +1071,12 @@ public: /// @returns the value that the string has in the Enum unsigned int memberValue(ASTString const& _member) const; size_t numberOfMembers() const; + unsigned int minValue() const { return 0; } + unsigned int maxValue() const + { + solAssert(numberOfMembers() <= 256, ""); + return static_cast(numberOfMembers()) - 1; + } private: EnumDefinition const& m_enum; diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 4c86aa980..210504868 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1784,12 +1784,13 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) else if (member == "min" || member == "max") { MagicType const* arg = dynamic_cast(_memberAccess.expression().annotation().type); - IntegerType const* integerType = dynamic_cast(arg->typeArgument()); - - if (member == "min") - m_context << integerType->min(); + if (IntegerType const* integerType = dynamic_cast(arg->typeArgument())) + m_context << (member == "min" ? integerType->min() : integerType->max()); + else if (EnumType const* enumType = dynamic_cast(arg->typeArgument())) + m_context << (member == "min" ? enumType->minValue() : enumType->maxValue()); else - m_context << integerType->max(); + solAssert(false, "min/max not available for the given type."); + } else if ((set{"encode", "encodePacked", "encodeWithSelector", "encodeWithSignature", "decode"}).count(member)) { diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index bee0e1611..66e54e893 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1785,12 +1785,26 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) else if (member == "min" || member == "max") { MagicType const* arg = dynamic_cast(_memberAccess.expression().annotation().type); - IntegerType const* integerType = dynamic_cast(arg->typeArgument()); - if (member == "min") - define(_memberAccess) << formatNumber(integerType->min()) << "\n"; + string requestedValue; + if (IntegerType const* integerType = dynamic_cast(arg->typeArgument())) + { + if (member == "min") + requestedValue = formatNumber(integerType->min()); + else + requestedValue = formatNumber(integerType->max()); + } + else if (EnumType const* enumType = dynamic_cast(arg->typeArgument())) + { + if (member == "min") + requestedValue = to_string(enumType->minValue()); + else + requestedValue = to_string(enumType->maxValue()); + } else - define(_memberAccess) << formatNumber(integerType->max()) << "\n"; + solAssert(false, "min/max requested on unexpected type."); + + define(_memberAccess) << requestedValue << "\n"; } else if (set{"encode", "encodePacked", "encodeWithSelector", "encodeWithSignature", "decode"}.count(member)) { diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index 6ecb57a7f..6fcc08ca8 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -1284,8 +1284,10 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess) auto const& memberName = _memberAccess.memberName(); if (memberName == "min" || memberName == "max") { - IntegerType const& integerType = dynamic_cast(*magicType->typeArgument()); - defineExpr(_memberAccess, memberName == "min" ? integerType.minValue() : integerType.maxValue()); + if (IntegerType const* integerType = dynamic_cast(magicType->typeArgument())) + defineExpr(_memberAccess, memberName == "min" ? integerType->minValue() : integerType->maxValue()); + else if (EnumType const* enumType = dynamic_cast(magicType->typeArgument())) + defineExpr(_memberAccess, memberName == "min" ? enumType->minValue() : enumType->maxValue()); } else if (memberName == "interfaceId") { diff --git a/test/libsolidity/semanticTests/enums/minmax.sol b/test/libsolidity/semanticTests/enums/minmax.sol new file mode 100644 index 000000000..3b298a6fa --- /dev/null +++ b/test/libsolidity/semanticTests/enums/minmax.sol @@ -0,0 +1,12 @@ +contract test { + enum MinMax { A, B, C, D } + + function min() public returns(uint) { return uint(type(MinMax).min); } + function max() public returns(uint) { return uint(type(MinMax).max); } +} + +// ==== +// compileViaYul: also +// ---- +// min() -> 0 +// max() -> 3 diff --git a/test/libsolidity/syntaxTests/array/concat/bytes_concat_on_type_info.sol b/test/libsolidity/syntaxTests/array/concat/bytes_concat_on_type_info.sol index e25bac278..741667e7c 100644 --- a/test/libsolidity/syntaxTests/array/concat/bytes_concat_on_type_info.sol +++ b/test/libsolidity/syntaxTests/array/concat/bytes_concat_on_type_info.sol @@ -5,4 +5,4 @@ contract C { } } // ---- -// TypeError 4259: (93-98): Invalid type for argument in the function call. A contract type or an integer type is required, but type(bytes) provided. +// TypeError 4259: (93-98): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(bytes) provided. diff --git a/test/libsolidity/syntaxTests/metaTypes/codeAccess_super.sol b/test/libsolidity/syntaxTests/metaTypes/codeAccess_super.sol index e7b3a6845..7d057e132 100644 --- a/test/libsolidity/syntaxTests/metaTypes/codeAccess_super.sol +++ b/test/libsolidity/syntaxTests/metaTypes/codeAccess_super.sol @@ -10,4 +10,4 @@ contract SuperTest is Other { } } // ---- -// TypeError 4259: (177-182): Invalid type for argument in the function call. A contract type or an integer type is required, but type(contract super SuperTest) provided. +// TypeError 4259: (177-182): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(contract super SuperTest) provided. diff --git a/test/libsolidity/syntaxTests/metaTypes/interfaceid_super.sol b/test/libsolidity/syntaxTests/metaTypes/interfaceid_super.sol index 328870447..0740b31cf 100644 --- a/test/libsolidity/syntaxTests/metaTypes/interfaceid_super.sol +++ b/test/libsolidity/syntaxTests/metaTypes/interfaceid_super.sol @@ -14,4 +14,4 @@ abstract contract Test is ERC165 { } } // ---- -// TypeError 4259: (592-597): Invalid type for argument in the function call. A contract type or an integer type is required, but type(contract super Test) provided. +// TypeError 4259: (592-597): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(contract super Test) provided. diff --git a/test/libsolidity/syntaxTests/metaTypes/super_name.sol b/test/libsolidity/syntaxTests/metaTypes/super_name.sol index 5b9ac73a1..5795b8190 100644 --- a/test/libsolidity/syntaxTests/metaTypes/super_name.sol +++ b/test/libsolidity/syntaxTests/metaTypes/super_name.sol @@ -50,4 +50,4 @@ contract D is B, C { } } // ---- -// TypeError 4259: (426-431): Invalid type for argument in the function call. A contract type or an integer type is required, but type(contract super B) provided. +// TypeError 4259: (426-431): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(contract super B) provided. diff --git a/test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol b/test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol index c28d2fe05..427caf4d0 100644 --- a/test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol +++ b/test/libsolidity/syntaxTests/metaTypes/typeRecursive.sol @@ -4,4 +4,4 @@ contract Test { } } // ---- -// TypeError 4259: (65-75): Invalid type for argument in the function call. A contract type or an integer type is required, but type(contract Test) provided. +// TypeError 4259: (65-75): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(contract Test) provided. diff --git a/test/libsolidity/syntaxTests/metaTypes/unsupportedArgForType.sol b/test/libsolidity/syntaxTests/metaTypes/unsupportedArgForType.sol index 050ae044c..9ed26dc6f 100644 --- a/test/libsolidity/syntaxTests/metaTypes/unsupportedArgForType.sol +++ b/test/libsolidity/syntaxTests/metaTypes/unsupportedArgForType.sol @@ -6,4 +6,4 @@ contract Test { } } // ---- -// TypeError 4259: (154-155): Invalid type for argument in the function call. A contract type or an integer type is required, but type(struct Test.S) provided. +// TypeError 4259: (154-155): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(struct Test.S) provided. diff --git a/test/libsolidity/syntaxTests/tryCatch/no_special.sol b/test/libsolidity/syntaxTests/tryCatch/no_special.sol index 6cfed6eda..d760e6ee3 100644 --- a/test/libsolidity/syntaxTests/tryCatch/no_special.sol +++ b/test/libsolidity/syntaxTests/tryCatch/no_special.sol @@ -14,4 +14,4 @@ contract C { // ---- // TypeError 5347: (72-76): Try can only be used with external function calls and contract creation calls. // TypeError 2536: (119-128): Try can only be used with external function calls and contract creation calls. -// TypeError 4259: (176-183): Invalid type for argument in the function call. A contract type or an integer type is required, but type(address) provided. +// TypeError 4259: (176-183): Invalid type for argument in the function call. An enum type, contract type or an integer type is required, but type(address) provided. From 7b05d3bc7063a7e13a7e8214c0ce7dfd867ff4ac Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Wed, 1 Sep 2021 12:42:36 +0200 Subject: [PATCH 009/232] CMake: Remove unsigned-integer-overflow check from UBSan compiler flags because it is too noisy. --- cmake/EthCompilerSettings.cmake | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index d26060383..44268e699 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -200,6 +200,10 @@ if (SANITIZE) elseif (sanitizer STREQUAL "undefined") # The following flags not used by fuzzer but used by us may create problems, so consider # disabling them: alignment, pointer-overflow. + # The following flag is not used by us to reduce terminal noise + # i.e., warnings printed on stderr: unsigned-integer-overflow + # Note: The C++ standard does not officially consider unsigned integer overflows + # to be undefined behavior since they are implementation independent. # Flags are alphabetically sorted and are for clang v10.0 list(APPEND undefinedSanitizerChecks alignment @@ -217,18 +221,12 @@ if (SANITIZE) returns-nonnull-attribute shift signed-integer-overflow - unsigned-integer-overflow unreachable vla-bound vptr ) list(JOIN undefinedSanitizerChecks "," sanitizerChecks) - list(REMOVE_ITEM undefinedSanitizerChecks unsigned-integer-overflow) - # The fuzzer excludes reports of unsigned-integer-overflow. Hence, we remove it - # from the -fno-sanitize-recover checks. Consider reducing this list if we do not - # want to be notified about other failed checks. - list(JOIN undefinedSanitizerChecks "," dontRecoverFromChecks) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=${sanitizerChecks} -fno-sanitize-recover=${dontRecoverFromChecks}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=${sanitizerChecks} -fno-sanitize-recover=${sanitizerChecks}") endif() endif() From 5849e0c16ec4852c70eb3299b0e4cd9067c1744e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 1 Sep 2021 18:59:13 +0200 Subject: [PATCH 010/232] Re-enable SMT tests on Arch Linux - Z3 4.8.12 has already been released --- .circleci/config.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 402bd8ff1..26ac6893d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -739,10 +739,7 @@ jobs: TERM: xterm # For Archlinux we do not have prebuilt docker images and we would need to build evmone from source, # thus we forgo semantics tests to speed things up. - # FIXME: Z3 4.8.11 prerelease is now in main Arch Linux repos but it makes some of our SMT - # tests hang. Disabling SMT tests until we get a proper release. - # See https://github.com/Z3Prover/z3/issues/5330 for more details. - SOLTEST_FLAGS: --no-semantic-tests --no-smt + SOLTEST_FLAGS: --no-semantic-tests steps: - run: name: Install runtime dependencies From 4e76914622a2ead5563894de4285b0943bd596ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 1 Sep 2021 19:00:03 +0200 Subject: [PATCH 011/232] Switch back to using the latest ArchLinux docker image --- .circleci/config.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 26ac6893d..8a0e11d9a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -589,9 +589,7 @@ jobs: b_archlinux: docker: - # FIXME: Newer releases won't work until CircleCI updates its host machines. - # See https://github.com/ethereum/solidity/pull/11332 - - image: archlinux:base-20210131.0.14634 + - image: archlinux:base environment: TERM: xterm MAKEFLAGS: -j 3 @@ -730,9 +728,7 @@ jobs: t_archlinux_soltest: &t_archlinux_soltest docker: - # FIXME: Newer releases won't work until CircleCI updates its host machines. - # See https://github.com/ethereum/solidity/pull/11332 - - image: archlinux:base-20210131.0.14634 + - image: archlinux:base environment: EVM: << pipeline.parameters.evm-version >> OPTIMIZE: 0 From 4700c2b973cd76f396dd2488b0aabd90868bd166 Mon Sep 17 00:00:00 2001 From: Marenz Date: Wed, 1 Sep 2021 18:29:19 +0200 Subject: [PATCH 012/232] Properly export symbols from aliased imports. --- Changelog.md | 1 + libsolidity/analysis/NameAndTypeResolver.cpp | 7 ++++++- .../syntaxTests/imports/alias_import_not_forwarded.sol | 8 ++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 test/libsolidity/syntaxTests/imports/alias_import_not_forwarded.sol diff --git a/Changelog.md b/Changelog.md index 1bbf51ff2..d5945cec5 100644 --- a/Changelog.md +++ b/Changelog.md @@ -13,6 +13,7 @@ Compiler Features: Bugfixes: + * Name Resolver: Fix that when importing an aliased symbol using ``import {AliasedName} from "a.sol"`` it would use the original name of the symbol and not the aliased one. * SMTChecker: Fix false negative caused by ``push`` on storage array references returned by internal functions. * SMTChecker: Fix false positive in external calls from constructors. * SMTChecker: Fix internal error on some multi-source uses of ``abi.*``, cryptographic functions and constants. diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 20c4f2c46..001221bc5 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -102,7 +102,12 @@ bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, mapname(), + &alias.location, + false, + m_errorReporter )) error = true; } diff --git a/test/libsolidity/syntaxTests/imports/alias_import_not_forwarded.sol b/test/libsolidity/syntaxTests/imports/alias_import_not_forwarded.sol new file mode 100644 index 000000000..1a7bb40fe --- /dev/null +++ b/test/libsolidity/syntaxTests/imports/alias_import_not_forwarded.sol @@ -0,0 +1,8 @@ +==== Source: dummy ==== +contract Dummy { string public constant FOO = "FOO"; } +==== Source: hasAlias ==== +import {Dummy as AliasedDummy} from "dummy"; +==== Source: Main ==== +import {AliasedDummy} from "hasAlias"; +contract TestAlias is AliasedDummy {} +// ---- From 106c591dde4c38a7c51f30924552ac4582e61277 Mon Sep 17 00:00:00 2001 From: Leo Alt Date: Mon, 30 Aug 2021 18:21:22 +0200 Subject: [PATCH 013/232] Support the external call option --- Changelog.md | 1 + libsolidity/formal/CHC.cpp | 28 ++++++++++++++++--- libsolidity/formal/SMTEncoder.cpp | 13 ++++++++- libsolidity/formal/SMTEncoder.h | 4 +++ .../external_calls/call_with_value_1.sol | 14 ++++++++++ .../external_calls/call_with_value_2.sol | 15 ++++++++++ .../external_calls/call_with_value_3.sol | 15 ++++++++++ .../external_call_this_with_value_1.sol | 14 ++++++++++ .../external_call_this_with_value_2.sol | 15 ++++++++++ .../external_call_with_value_1.sol | 18 ++++++++++++ .../external_call_with_value_2.sol | 18 ++++++++++++ .../external_call_with_value_3.sol | 18 ++++++++++++ 12 files changed, 168 insertions(+), 5 deletions(-) create mode 100644 test/libsolidity/smtCheckerTests/external_calls/call_with_value_1.sol create mode 100644 test/libsolidity/smtCheckerTests/external_calls/call_with_value_2.sol create mode 100644 test/libsolidity/smtCheckerTests/external_calls/call_with_value_3.sol create mode 100644 test/libsolidity/smtCheckerTests/external_calls/external_call_this_with_value_1.sol create mode 100644 test/libsolidity/smtCheckerTests/external_calls/external_call_this_with_value_2.sol create mode 100644 test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_1.sol create mode 100644 test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_2.sol create mode 100644 test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_3.sol diff --git a/Changelog.md b/Changelog.md index b187d009c..509d940d4 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,6 +10,7 @@ Compiler Features: * Immutable variables can be read at construction time once they are initialized. * SMTChecker: Support low level ``call`` as external calls to unknown code. * SMTChecker: Add constraints to better correlate ``address(this).balance`` and ``msg.value``. + * SMTChecker: Support the ``value`` option for external function calls. * Commandline Interface: Disallowed the ``--experimental-via-ir`` option to be used with Standard Json, Assembler and Linker modes. diff --git a/libsolidity/formal/CHC.cpp b/libsolidity/formal/CHC.cpp index 140b2a27d..b7292221b 100644 --- a/libsolidity/formal/CHC.cpp +++ b/libsolidity/formal/CHC.cpp @@ -34,6 +34,7 @@ #include +#include #include #ifdef HAVE_Z3_DLOPEN @@ -743,13 +744,15 @@ void CHC::externalFunctionCall(FunctionCall const& _funCall) /// so we just add the nondet_interface predicate. solAssert(m_currentContract, ""); - if (isTrustedExternalCall(&_funCall.expression())) + auto [callExpr, callOptions] = functionCallExpression(_funCall); + + if (isTrustedExternalCall(callExpr)) { externalFunctionCallToTrustedCode(_funCall); return; } - FunctionType const& funType = dynamic_cast(*_funCall.expression().annotation().type); + FunctionType const& funType = dynamic_cast(*callExpr->annotation().type); auto kind = funType.kind(); solAssert( kind == FunctionType::Kind::External || @@ -773,6 +776,19 @@ void CHC::externalFunctionCall(FunctionCall const& _funCall) if (!m_currentFunction || m_currentFunction->isConstructor()) return; + if (callOptions) + { + optional valueIndex; + for (auto&& [i, name]: callOptions->names() | ranges::views::enumerate) + if (name && *name == "value") + { + valueIndex = i; + break; + } + solAssert(valueIndex, ""); + state().addBalance(state().thisAddress(), 0 - expr(*callOptions->options().at(*valueIndex))); + } + auto preCallState = vector{state().state()} + currentStateVariables(); if (!usesStaticCall) @@ -829,6 +845,8 @@ void CHC::externalFunctionCallToTrustedCode(FunctionCall const& _funCall) state().newTx(); // set the transaction sender as this contract m_context.addAssertion(state().txMember("msg.sender") == state().thisAddress()); + // set the transaction value as 0 + m_context.addAssertion(state().txMember("msg.value") == 0); // set the origin to be the current transaction origin m_context.addAssertion(state().txMember("tx.origin") == txOrigin); @@ -1451,10 +1469,12 @@ smtutil::Expression CHC::predicate(FunctionCall const& _funCall) return smtutil::Expression(true); auto contractAddressValue = [this](FunctionCall const& _f) { - FunctionType const& funType = dynamic_cast(*_f.expression().annotation().type); + auto [callExpr, callOptions] = functionCallExpression(_f); + + FunctionType const& funType = dynamic_cast(*callExpr->annotation().type); if (funType.kind() == FunctionType::Kind::Internal) return state().thisAddress(); - if (MemberAccess const* callBase = dynamic_cast(&_f.expression())) + if (MemberAccess const* callBase = dynamic_cast(callExpr)) return expr(callBase->expression()); solAssert(false, "Unreachable!"); }; diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index 6fcc08ca8..411fa2757 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -2590,6 +2590,16 @@ Expression const* SMTEncoder::innermostTuple(Expression const& _expr) return expr; } +pair SMTEncoder::functionCallExpression(FunctionCall const& _funCall) +{ + Expression const* callExpr = &_funCall.expression(); + auto const* callOptions = dynamic_cast(callExpr); + if (callOptions) + callExpr = &callOptions->expression(); + + return {callExpr, callOptions}; +} + Expression const* SMTEncoder::cleanExpression(Expression const& _expr) { auto const* expr = &_expr; @@ -2713,7 +2723,8 @@ FunctionDefinition const* SMTEncoder::functionCallToDefinition( if (*_funCall.annotation().kind != FunctionCallKind::FunctionCall) return {}; - Expression const* calledExpr = &_funCall.expression(); + auto [calledExpr, callOptions] = functionCallExpression(_funCall); + if (TupleExpression const* fun = dynamic_cast(calledExpr)) { solAssert(fun->components().size() == 1, ""); diff --git a/libsolidity/formal/SMTEncoder.h b/libsolidity/formal/SMTEncoder.h index 7cf4b065e..28270acc0 100644 --- a/libsolidity/formal/SMTEncoder.h +++ b/libsolidity/formal/SMTEncoder.h @@ -71,6 +71,10 @@ public: /// otherwise _expr. static Expression const* innermostTuple(Expression const& _expr); + /// @returns {_funCall.expression(), nullptr} if function call option values are not given, and + /// {_funCall.expression().expression(), _funCall.expression()} if they are. + static std::pair functionCallExpression(FunctionCall const& _funCall); + /// @returns the expression after stripping redundant syntactic sugar. /// Currently supports stripping: /// 1. 1-tuple; i.e. ((x)) -> x diff --git a/test/libsolidity/smtCheckerTests/external_calls/call_with_value_1.sol b/test/libsolidity/smtCheckerTests/external_calls/call_with_value_1.sol new file mode 100644 index 000000000..ed27a4df8 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/external_calls/call_with_value_1.sol @@ -0,0 +1,14 @@ +contract C { + function g(address payable i) public { + require(address(this).balance == 100); + i.call{value: 10}(""); + // Disabled due to Spacer nondeterminism + //assert(address(this).balance == 90); // should hold + // Disabled due to Spacer nondeterminism + //assert(address(this).balance == 100); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 9302: (96-117): Return value of low-level calls not used. diff --git a/test/libsolidity/smtCheckerTests/external_calls/call_with_value_2.sol b/test/libsolidity/smtCheckerTests/external_calls/call_with_value_2.sol new file mode 100644 index 000000000..792bb0730 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/external_calls/call_with_value_2.sol @@ -0,0 +1,15 @@ +contract C { + function g(address payable i) public { + require(address(this).balance == 100); + i.call{value: 0}(""); + assert(address(this).balance == 100); // should hold + assert(address(this).balance == 20); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 9302: (96-116): Return value of low-level calls not used. +// Warning 6328: (120-156): CHC: Assertion violation might happen here. +// Warning 6328: (175-210): CHC: Assertion violation happens here.\nCounterexample:\n\ni = 0\n\nTransaction trace:\nC.constructor()\nC.g(0)\n i.call{value: 0}("") -- untrusted external call +// Warning 4661: (120-156): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/call_with_value_3.sol b/test/libsolidity/smtCheckerTests/external_calls/call_with_value_3.sol new file mode 100644 index 000000000..6cbe24136 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/external_calls/call_with_value_3.sol @@ -0,0 +1,15 @@ +contract C { + function g(address payable i) public { + require(address(this).balance > 100); + i.call{value: 20}(""); + assert(address(this).balance > 0); // should hold + // Disabled due to Spacer nondeterminism + //assert(address(this).balance == 0); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 9302: (95-116): Return value of low-level calls not used. +// Warning 6328: (120-153): CHC: Assertion violation might happen here. +// Warning 4661: (120-153): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_call_this_with_value_1.sol b/test/libsolidity/smtCheckerTests/external_calls/external_call_this_with_value_1.sol new file mode 100644 index 000000000..06390b12c --- /dev/null +++ b/test/libsolidity/smtCheckerTests/external_calls/external_call_this_with_value_1.sol @@ -0,0 +1,14 @@ +contract C { + function g() public { + require(address(this).balance == 100); + this.h{value: 10}(); + assert(address(this).balance == 100); // should hold + assert(address(this).balance == 90); // should fail + } + + function h() external payable {} +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (157-192): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_call_this_with_value_2.sol b/test/libsolidity/smtCheckerTests/external_calls/external_call_this_with_value_2.sol new file mode 100644 index 000000000..fc2d844d9 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/external_calls/external_call_this_with_value_2.sol @@ -0,0 +1,15 @@ +contract C { + function g(uint i) public { + require(address(this).balance == 100); + this.h{value: i}(); + assert(address(this).balance == 100); // should hold + assert(address(this).balance == 90); // should fail + } + + function h() external payable {} +} +// ==== +// SMTEngine: all +// SMTIgnoreCex: yes +// ---- +// Warning 6328: (162-197): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_1.sol b/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_1.sol new file mode 100644 index 000000000..a5ac8ded9 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_1.sol @@ -0,0 +1,18 @@ +interface I { + function f() external payable; +} + +contract C { + function g(I i) public { + require(address(this).balance == 100); + i.f{value: 10}(); + assert(address(this).balance == 90); // should hold + // Disabled due to Spacer nondeterminism + //assert(address(this).balance == 100); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (151-186): CHC: Assertion violation might happen here. +// Warning 4661: (151-186): BMC: 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 new file mode 100644 index 000000000..4b51d9d9e --- /dev/null +++ b/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_2.sol @@ -0,0 +1,18 @@ +interface I { + function f() external payable; +} + +contract C { + function g(I i) public { + require(address(this).balance == 100); + i.f{value: 0}(); + assert(address(this).balance == 100); // should hold + assert(address(this).balance == 90); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (150-186): CHC: Assertion violation might happen here. +// 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_call_with_value_3.sol b/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_3.sol new file mode 100644 index 000000000..d0e4c84aa --- /dev/null +++ b/test/libsolidity/smtCheckerTests/external_calls/external_call_with_value_3.sol @@ -0,0 +1,18 @@ +interface I { + function f() external payable; +} + +contract C { + function g(I i) public { + require(address(this).balance > 100); + i.f{value: 20}(); + assert(address(this).balance > 0); // should hold + assert(address(this).balance == 0); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (150-183): CHC: Assertion violation might happen here. +// Warning 6328: (202-236): CHC: Assertion violation happens here.\nCounterexample:\n\ni = 0\n\nTransaction trace:\nC.constructor()\nC.g(0)\n i.f{value: 20}() -- untrusted external call +// Warning 4661: (150-183): BMC: Assertion violation happens here. From 5caa15879bf4453d0eb40bd23a46ff065b900ba4 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 31 Aug 2021 17:22:13 +0200 Subject: [PATCH 014/232] Allow and require use-src to be repeated for each object. --- libsolidity/codegen/ir/IRGenerator.cpp | 6 +++-- libyul/Object.cpp | 22 +++++++------------ libyul/Object.h | 10 ++------- libyul/ObjectParser.cpp | 22 +++++++++++-------- libyul/ObjectParser.h | 8 ++----- libyul/backends/wasm/EVMToEwasmTranslator.cpp | 1 + .../constant_optimizer_yul/output | 1 + test/cmdlineTests/exp_base_literal/output | 1 + .../output | 2 ++ .../ir_compiler_subobjects/output | 4 ++++ .../output | 1 + .../output | 1 + .../keccak_optimization_deploy_code/output | 1 + .../keccak_optimization_low_runs/output | 1 + test/cmdlineTests/name_simplifier/output | 1 + .../cmdlineTests/optimizer_array_sload/output | 1 + test/cmdlineTests/revert_strings/output | 1 + .../output.json | 1 + .../standard_ir_requested/output.json | 1 + .../standard_viair_requested/output.json | 3 +++ test/cmdlineTests/viair_abicoder_v1/output | 1 + test/cmdlineTests/viair_subobjects/output | 4 ++++ test/cmdlineTests/yul_optimizer_steps/output | 1 + .../yul_source_locations/output.json | 2 ++ .../yul_string_format_ascii/output.json | 1 + .../output.json | 1 + .../output.json | 1 + .../yul_string_format_ascii_long/output.json | 1 + .../yul_string_format_hex/output.json | 1 + test/libyul/ObjectParser.cpp | 5 +++-- .../libyul/objectCompiler/sourceLocations.yul | 1 + 31 files changed, 67 insertions(+), 41 deletions(-) diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 418d112e0..47a57eb08 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -133,7 +133,7 @@ string IRGenerator::generate( }; Whiskers t(R"( - /// @use-src + /// @use-src object "" { code { @@ -147,6 +147,7 @@ string IRGenerator::generate( } + /// @use-src object "" { code { @@ -177,7 +178,7 @@ string IRGenerator::generate( ", " ); - t("useSrcMap", useSrcMap); + t("useSrcMapCreation", useSrcMap); t("sourceLocationComment", sourceLocationComment(_contract, m_context)); t("CreationObject", IRNames::creationObject(_contract)); @@ -219,6 +220,7 @@ string IRGenerator::generate( m_context.initializeInternalDispatch(move(internalDispatchMap)); // Do not register immutables to avoid assignment. + t("useSrcMapDeployed", useSrcMap); t("DeployedObject", IRNames::deployedObject(_contract)); t("library_address", IRNames::libraryAddressImmutable()); t("dispatch", dispatchRoutine(_contract)); diff --git a/libyul/Object.cpp b/libyul/Object.cpp index 05ad9cb82..a87281cac 100644 --- a/libyul/Object.cpp +++ b/libyul/Object.cpp @@ -50,38 +50,32 @@ string indent(std::string const& _input) } -string Data::toString(Dialect const*, optional) const +string Data::toString(Dialect const*) const { return "data \"" + name.str() + "\" hex\"" + util::toHex(data) + "\""; } string Object::toString(Dialect const* _dialect) const { + yulAssert(code, "No code"); + yulAssert(debugData, "No debug data"); + string useSrcComment; - if (debugData && debugData->sourceNames) + if (debugData->sourceNames) useSrcComment = "/// @use-src " + joinHumanReadable(ranges::views::transform(*debugData->sourceNames, [](auto&& _pair) { return to_string(_pair.first) + ":" + util::escapeAndQuoteString(*_pair.second); })) + "\n"; - return useSrcComment + toString(_dialect, debugData ? debugData->sourceNames : optional{}); -} -string Object::toString(Dialect const* _dialect, std::optional _sourceNames) const -{ - yulAssert(code, "No code"); - string inner = "code " + AsmPrinter{_dialect, _sourceNames}(*code); + string inner = "code " + AsmPrinter{_dialect, debugData->sourceNames}(*code); for (auto const& obj: subObjects) - { - if (auto const* o = dynamic_cast(obj.get())) - yulAssert(!o->debugData || !o->debugData->sourceNames, ""); - inner += "\n" + obj->toString(_dialect, _sourceNames); - } + inner += "\n" + obj->toString(_dialect); - return "object \"" + name.str() + "\" {\n" + indent(inner) + "\n}"; + return useSrcComment + "object \"" + name.str() + "\" {\n" + indent(inner) + "\n}"; } set Object::qualifiedDataNames() const diff --git a/libyul/Object.h b/libyul/Object.h index 9b7519b1e..39fb092d3 100644 --- a/libyul/Object.h +++ b/libyul/Object.h @@ -49,11 +49,8 @@ struct ObjectNode /// Name of the object. /// Can be empty since .yul files can also just contain code, without explicitly placing it in an object. YulString name; -protected: - virtual std::string toString(Dialect const* _dialect, std::optional _sourceNames) const = 0; - /// Object should have access to toString - friend struct Object; + virtual std::string toString(Dialect const* _dialect) const = 0; }; /** @@ -65,8 +62,7 @@ struct Data: public ObjectNode bytes data; -protected: - std::string toString(Dialect const* _dialect, std::optional _sourceNames) const override; + std::string toString(Dialect const* _dialect) const override; }; @@ -114,8 +110,6 @@ public: /// @returns the name of the special metadata data object. static std::string metadataName() { return ".metadata"; } -protected: - std::string toString(Dialect const* _dialect, std::optional _sourceNames) const override; }; } diff --git a/libyul/ObjectParser.cpp b/libyul/ObjectParser.cpp index 8ce5896cf..afd4b7d94 100644 --- a/libyul/ObjectParser.cpp +++ b/libyul/ObjectParser.cpp @@ -45,14 +45,15 @@ shared_ptr ObjectParser::parse(shared_ptr const& _scanner, bool { shared_ptr object; m_scanner = _scanner; - m_sourceNameMapping = tryParseSourceNameMapping(); if (currentToken() == Token::LBrace) { // Special case: Code-only form. object = make_shared(); object->name = "object"_yulstring; - object->code = parseBlock(); + auto sourceNameMapping = tryParseSourceNameMapping(); + object->debugData = make_shared(ObjectDebugData{sourceNameMapping}); + object->code = parseBlock(sourceNameMapping); if (!object->code) return nullptr; } @@ -60,7 +61,6 @@ shared_ptr ObjectParser::parse(shared_ptr const& _scanner, bool object = parseObject(); if (!_reuseScanner) expectToken(Token::EOS); - object->debugData = make_shared(ObjectDebugData{m_sourceNameMapping}); return object; } catch (FatalError const&) @@ -75,16 +75,20 @@ shared_ptr ObjectParser::parseObject(Object* _containingObject) { RecursionGuard guard(*this); + shared_ptr ret = make_shared(); + + auto sourceNameMapping = tryParseSourceNameMapping(); + ret->debugData = make_shared(ObjectDebugData{sourceNameMapping}); + if (currentToken() != Token::Identifier || currentLiteral() != "object") fatalParserError(4294_error, "Expected keyword \"object\"."); advance(); - shared_ptr ret = make_shared(); ret->name = parseUniqueName(_containingObject); expectToken(Token::LBrace); - ret->code = parseCode(); + ret->code = parseCode(move(sourceNameMapping)); while (currentToken() != Token::RBrace) { @@ -103,13 +107,13 @@ shared_ptr ObjectParser::parseObject(Object* _containingObject) return ret; } -shared_ptr ObjectParser::parseCode() +shared_ptr ObjectParser::parseCode(optional _sourceNames) { if (currentToken() != Token::Identifier || currentLiteral() != "code") fatalParserError(4846_error, "Expected keyword \"code\"."); advance(); - return parseBlock(); + return parseBlock(move(_sourceNames)); } optional ObjectParser::tryParseSourceNameMapping() const @@ -166,9 +170,9 @@ optional ObjectParser::tryParseSourceNameMapping() const return nullopt; } -shared_ptr ObjectParser::parseBlock() +shared_ptr ObjectParser::parseBlock(optional _sourceNames) { - Parser parser(m_errorReporter, m_dialect, m_sourceNameMapping); + Parser parser(m_errorReporter, m_dialect, move(_sourceNames)); shared_ptr block = parser.parseInline(m_scanner); yulAssert(block || m_errorReporter.hasErrors(), "Invalid block but no error!"); return block; diff --git a/libyul/ObjectParser.h b/libyul/ObjectParser.h index 86a5ef77c..716a191ea 100644 --- a/libyul/ObjectParser.h +++ b/libyul/ObjectParser.h @@ -55,13 +55,11 @@ public: /// @returns an empty shared pointer on error. std::shared_ptr parse(std::shared_ptr const& _scanner, bool _reuseScanner); - std::optional const& sourceNameMapping() const noexcept { return m_sourceNameMapping; } - private: std::optional tryParseSourceNameMapping() const; std::shared_ptr parseObject(Object* _containingObject = nullptr); - std::shared_ptr parseCode(); - std::shared_ptr parseBlock(); + std::shared_ptr parseCode(std::optional _sourceNames); + std::shared_ptr parseBlock(std::optional _sourceNames); void parseData(Object& _containingObject); /// Tries to parse a name that is non-empty and unique inside the containing object. @@ -69,8 +67,6 @@ private: void addNamedSubObject(Object& _container, YulString _name, std::shared_ptr _subObject); Dialect const& m_dialect; - - std::optional m_sourceNameMapping; }; } diff --git a/libyul/backends/wasm/EVMToEwasmTranslator.cpp b/libyul/backends/wasm/EVMToEwasmTranslator.cpp index a5d355ede..eb7a60a32 100644 --- a/libyul/backends/wasm/EVMToEwasmTranslator.cpp +++ b/libyul/backends/wasm/EVMToEwasmTranslator.cpp @@ -93,6 +93,7 @@ Object EVMToEwasmTranslator::run(Object const& _object) Object ret; ret.name = _object.name; ret.code = make_shared(move(ast)); + ret.debugData = _object.debugData; ret.analysisInfo = make_shared(); ErrorList errors; diff --git a/test/cmdlineTests/constant_optimizer_yul/output b/test/cmdlineTests/constant_optimizer_yul/output index 7fdb98670..46df0ba95 100644 --- a/test/cmdlineTests/constant_optimizer_yul/output +++ b/test/cmdlineTests/constant_optimizer_yul/output @@ -21,6 +21,7 @@ object "C_12" { return(128, _1) } } + /// @use-src 0:"constant_optimizer_yul/input.sol", 1:"#utility.yul" object "C_12_deployed" { code { { diff --git a/test/cmdlineTests/exp_base_literal/output b/test/cmdlineTests/exp_base_literal/output index 1872afbe4..4b1484e3d 100644 --- a/test/cmdlineTests/exp_base_literal/output +++ b/test/cmdlineTests/exp_base_literal/output @@ -38,6 +38,7 @@ object "C_81" { } } + /// @use-src 0:"exp_base_literal/input.sol", 1:"#utility.yul" object "C_81_deployed" { code { /// @src 0:82:370 diff --git a/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output b/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output index 1af925406..541dac88b 100644 --- a/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output +++ b/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output @@ -18,6 +18,7 @@ object "C_7" { return(128, _1) } } + /// @use-src 0:"ir_compiler_inheritance_nosubobjects/input.sol", 1:"#utility.yul" object "C_7_deployed" { code { { @@ -50,6 +51,7 @@ object "D_10" { return(128, _1) } } + /// @use-src 0:"ir_compiler_inheritance_nosubobjects/input.sol", 1:"#utility.yul" object "D_10_deployed" { code { { diff --git a/test/cmdlineTests/ir_compiler_subobjects/output b/test/cmdlineTests/ir_compiler_subobjects/output index ba93e6886..8de953f11 100644 --- a/test/cmdlineTests/ir_compiler_subobjects/output +++ b/test/cmdlineTests/ir_compiler_subobjects/output @@ -18,6 +18,7 @@ object "C_3" { return(128, _1) } } + /// @use-src 0:"ir_compiler_subobjects/input.sol", 1:"#utility.yul" object "C_3_deployed" { code { { @@ -50,6 +51,7 @@ object "D_16" { return(128, _1) } } + /// @use-src 0:"ir_compiler_subobjects/input.sol", 1:"#utility.yul" object "D_16_deployed" { code { { @@ -88,6 +90,7 @@ object "D_16" { revert(0, 0) } } + /// @use-src 0:"ir_compiler_subobjects/input.sol", 1:"#utility.yul" object "C_3" { code { { @@ -99,6 +102,7 @@ object "D_16" { return(128, _1) } } + /// @use-src 0:"ir_compiler_subobjects/input.sol", 1:"#utility.yul" object "C_3_deployed" { code { { diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output index 89ee1b5d9..b7cdc74e9 100644 --- a/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output @@ -18,6 +18,7 @@ object "D_12" { return(128, _1) } } + /// @use-src 0:"ir_with_assembly_no_memoryguard_creation/input.sol", 1:"#utility.yul" object "D_12_deployed" { code { { diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output index 1fcf2fcc8..0dece56bd 100644 --- a/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output @@ -18,6 +18,7 @@ object "D_8" { return(128, _1) } } + /// @use-src 0:"ir_with_assembly_no_memoryguard_runtime/input.sol", 1:"#utility.yul" object "D_8_deployed" { code { { diff --git a/test/cmdlineTests/keccak_optimization_deploy_code/output b/test/cmdlineTests/keccak_optimization_deploy_code/output index 83c7c3929..4e80153d4 100644 --- a/test/cmdlineTests/keccak_optimization_deploy_code/output +++ b/test/cmdlineTests/keccak_optimization_deploy_code/output @@ -22,6 +22,7 @@ object "C_12" { return(128, _1) } } + /// @use-src 0:"keccak_optimization_deploy_code/input.sol", 1:"#utility.yul" object "C_12_deployed" { code { { diff --git a/test/cmdlineTests/keccak_optimization_low_runs/output b/test/cmdlineTests/keccak_optimization_low_runs/output index 203600cfa..2632b38df 100644 --- a/test/cmdlineTests/keccak_optimization_low_runs/output +++ b/test/cmdlineTests/keccak_optimization_low_runs/output @@ -18,6 +18,7 @@ object "C_7" { return(128, _1) } } + /// @use-src 0:"keccak_optimization_low_runs/input.sol", 1:"#utility.yul" object "C_7_deployed" { code { { diff --git a/test/cmdlineTests/name_simplifier/output b/test/cmdlineTests/name_simplifier/output index be3cb3780..b8c202c53 100644 --- a/test/cmdlineTests/name_simplifier/output +++ b/test/cmdlineTests/name_simplifier/output @@ -18,6 +18,7 @@ object "C_59" { return(128, _1) } } + /// @use-src 0:"name_simplifier/input.sol", 1:"#utility.yul" object "C_59_deployed" { code { { diff --git a/test/cmdlineTests/optimizer_array_sload/output b/test/cmdlineTests/optimizer_array_sload/output index 36dc23663..2355d5993 100644 --- a/test/cmdlineTests/optimizer_array_sload/output +++ b/test/cmdlineTests/optimizer_array_sload/output @@ -18,6 +18,7 @@ object "Arraysum_34" { return(128, _1) } } + /// @use-src 0:"optimizer_array_sload/input.sol", 1:"#utility.yul" object "Arraysum_34_deployed" { code { { diff --git a/test/cmdlineTests/revert_strings/output b/test/cmdlineTests/revert_strings/output index 6fa650eb1..8a9bc748c 100644 --- a/test/cmdlineTests/revert_strings/output +++ b/test/cmdlineTests/revert_strings/output @@ -53,6 +53,7 @@ object "C_15" { } } + /// @use-src 0:"revert_strings/input.sol", 1:"#utility.yul" object "C_15_deployed" { code { /// @src 0:59:147 diff --git a/test/cmdlineTests/standard_irOptimized_requested/output.json b/test/cmdlineTests/standard_irOptimized_requested/output.json index 8b9ada71a..bb5b9de14 100644 --- a/test/cmdlineTests/standard_irOptimized_requested/output.json +++ b/test/cmdlineTests/standard_irOptimized_requested/output.json @@ -25,6 +25,7 @@ object \"C_7\" { function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { revert(0, 0) } } + /// @use-src 0:\"A\", 1:\"#utility.yul\" object \"C_7_deployed\" { code { /// @src 0:79:121 diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index 2eb815d33..3d9bb9135 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -37,6 +37,7 @@ object \"C_7\" { } } + /// @use-src 0:\"A\", 1:\"#utility.yul\" object \"C_7_deployed\" { code { /// @src 0:79:121 diff --git a/test/cmdlineTests/standard_viair_requested/output.json b/test/cmdlineTests/standard_viair_requested/output.json index dca052187..aa3291a25 100644 --- a/test/cmdlineTests/standard_viair_requested/output.json +++ b/test/cmdlineTests/standard_viair_requested/output.json @@ -37,6 +37,7 @@ object \"C_3\" { } } + /// @use-src 0:\"A\", 1:\"#utility.yul\" object \"C_3_deployed\" { code { /// @src 0:79:92 @@ -113,6 +114,7 @@ object \"D_16\" { } } + /// @use-src 0:\"A\", 1:\"#utility.yul\" object \"D_16_deployed\" { code { /// @src 0:93:146 @@ -244,6 +246,7 @@ object \"D_16\" { } } + /// @use-src 0:\"A\", 1:\"#utility.yul\" object \"C_3_deployed\" { code { /// @src 0:79:92 diff --git a/test/cmdlineTests/viair_abicoder_v1/output b/test/cmdlineTests/viair_abicoder_v1/output index d42a032f8..ca9bbdc5e 100644 --- a/test/cmdlineTests/viair_abicoder_v1/output +++ b/test/cmdlineTests/viair_abicoder_v1/output @@ -38,6 +38,7 @@ object "test_11" { } } + /// @use-src 0:"viair_abicoder_v1/input.sol", 1:"#utility.yul" object "test_11_deployed" { code { /// @src 0:79:169 diff --git a/test/cmdlineTests/viair_subobjects/output b/test/cmdlineTests/viair_subobjects/output index 9ca620d06..bfdec9087 100644 --- a/test/cmdlineTests/viair_subobjects/output +++ b/test/cmdlineTests/viair_subobjects/output @@ -24,6 +24,7 @@ object "C_3" { return(128, _1) } } + /// @use-src 0:"viair_subobjects/input.sol", 1:"#utility.yul" object "C_3_deployed" { code { { @@ -62,6 +63,7 @@ object "D_16" { return(128, _1) } } + /// @use-src 0:"viair_subobjects/input.sol", 1:"#utility.yul" object "D_16_deployed" { code { { @@ -100,6 +102,7 @@ object "D_16" { revert(0, 0) } } + /// @use-src 0:"viair_subobjects/input.sol", 1:"#utility.yul" object "C_3" { code { { @@ -111,6 +114,7 @@ object "D_16" { return(128, _1) } } + /// @use-src 0:"viair_subobjects/input.sol", 1:"#utility.yul" object "C_3_deployed" { code { { diff --git a/test/cmdlineTests/yul_optimizer_steps/output b/test/cmdlineTests/yul_optimizer_steps/output index af9ef0988..bdd97296d 100644 --- a/test/cmdlineTests/yul_optimizer_steps/output +++ b/test/cmdlineTests/yul_optimizer_steps/output @@ -25,6 +25,7 @@ object "C_7" { function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { revert(0, 0) } } + /// @use-src 0:"yul_optimizer_steps/input.sol", 1:"#utility.yul" object "C_7_deployed" { code { { diff --git a/test/cmdlineTests/yul_source_locations/output.json b/test/cmdlineTests/yul_source_locations/output.json index 100249924..c5d04aebb 100644 --- a/test/cmdlineTests/yul_source_locations/output.json +++ b/test/cmdlineTests/yul_source_locations/output.json @@ -156,6 +156,7 @@ object \"C_54\" { } } + /// @use-src 0:\"C\", 1:\"D\", 2:\"#utility.yul\" object \"C_54_deployed\" { code { /// @src 0:79:428 @@ -780,6 +781,7 @@ object \"D_72\" { } } + /// @use-src 0:\"C\", 1:\"D\", 2:\"#utility.yul\" object \"D_72_deployed\" { code { /// @src 1:91:166 diff --git a/test/cmdlineTests/yul_string_format_ascii/output.json b/test/cmdlineTests/yul_string_format_ascii/output.json index a48cc0d68..d6bce8b6a 100644 --- a/test/cmdlineTests/yul_string_format_ascii/output.json +++ b/test/cmdlineTests/yul_string_format_ascii/output.json @@ -37,6 +37,7 @@ object \"C_11\" { } } + /// @use-src 0:\"A\", 1:\"#utility.yul\" object \"C_11_deployed\" { code { /// @src 0:78:164 diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json index 6dabd7fdd..ccf999086 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json @@ -37,6 +37,7 @@ object \"C_11\" { } } + /// @use-src 0:\"A\", 1:\"#utility.yul\" object \"C_11_deployed\" { code { /// @src 0:78:158 diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json index e02016c0e..f29e4347e 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json @@ -37,6 +37,7 @@ object \"C_11\" { } } + /// @use-src 0:\"A\", 1:\"#utility.yul\" object \"C_11_deployed\" { code { /// @src 0:78:159 diff --git a/test/cmdlineTests/yul_string_format_ascii_long/output.json b/test/cmdlineTests/yul_string_format_ascii_long/output.json index f9110a134..d701ce599 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/output.json @@ -37,6 +37,7 @@ object \"C_11\" { } } + /// @use-src 0:\"A\", 1:\"#utility.yul\" object \"C_11_deployed\" { code { /// @src 0:78:243 diff --git a/test/cmdlineTests/yul_string_format_hex/output.json b/test/cmdlineTests/yul_string_format_hex/output.json index 0bce08e79..ac437ccec 100644 --- a/test/cmdlineTests/yul_string_format_hex/output.json +++ b/test/cmdlineTests/yul_string_format_hex/output.json @@ -37,6 +37,7 @@ object \"C_11\" { } } + /// @use-src 0:\"A\", 1:\"#utility.yul\" object \"C_11_deployed\" { code { /// @src 0:78:159 diff --git a/test/libyul/ObjectParser.cpp b/test/libyul/ObjectParser.cpp index 1d4e0abc7..987933a9f 100644 --- a/test/libyul/ObjectParser.cpp +++ b/test/libyul/ObjectParser.cpp @@ -121,8 +121,9 @@ tuple, ErrorList> tryGetSourceLocationMapping(string _so Dialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(EVMVersion::berlin()); ObjectParser objectParser{reporter, dialect}; CharStream stream(move(source), ""); - objectParser.parse(make_shared(stream), false); - return {objectParser.sourceNameMapping(), std::move(errors)}; + auto object = objectParser.parse(make_shared(stream), false); + BOOST_REQUIRE(object && object->debugData); + return {object->debugData->sourceNames, std::move(errors)}; } } diff --git a/test/libyul/objectCompiler/sourceLocations.yul b/test/libyul/objectCompiler/sourceLocations.yul index f98f74f77..4e75d05e7 100644 --- a/test/libyul/objectCompiler/sourceLocations.yul +++ b/test/libyul/objectCompiler/sourceLocations.yul @@ -10,6 +10,7 @@ object "a" { datasize("sub") ) } + /// @use-src 3: "abc.sol" , 2: "def.sol" object "sub" { code { /// @src 2:70:72 From f881409ea48329986bf2980c55ec4882a9a23b64 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 5 Jul 2021 18:13:44 +0200 Subject: [PATCH 015/232] Stack layout generator for new code generation. --- libsolutil/CommonData.h | 53 ++ libyul/CMakeLists.txt | 3 + libyul/backends/evm/ControlFlowGraph.h | 16 +- libyul/backends/evm/StackHelpers.h | 424 ++++++++++++++ libyul/backends/evm/StackLayoutGenerator.cpp | 578 +++++++++++++++++++ libyul/backends/evm/StackLayoutGenerator.h | 97 ++++ test/CMakeLists.txt | 2 + test/InteractiveTests.h | 2 + test/libyul/ControlFlowGraphTest.cpp | 21 +- test/libyul/StackLayoutGeneratorTest.cpp | 267 +++++++++ test/libyul/StackLayoutGeneratorTest.h | 43 ++ test/libyul/yulStackLayout/complex.yul | 318 ++++++++++ test/libyul/yulStackLayout/for.yul | 91 +++ test/libyul/yulStackLayout/function.yul | 117 ++++ test/libyul/yulStackLayout/if.yul | 51 ++ test/libyul/yulStackLayout/stub.yul | 17 + test/libyul/yulStackLayout/switch.yul | 107 ++++ test/libyul/yulStackLayout/variables.yul | 51 ++ test/tools/CMakeLists.txt | 1 + 19 files changed, 2237 insertions(+), 22 deletions(-) create mode 100644 libyul/backends/evm/StackHelpers.h create mode 100644 libyul/backends/evm/StackLayoutGenerator.cpp create mode 100644 libyul/backends/evm/StackLayoutGenerator.h create mode 100644 test/libyul/StackLayoutGeneratorTest.cpp create mode 100644 test/libyul/StackLayoutGeneratorTest.h create mode 100644 test/libyul/yulStackLayout/complex.yul create mode 100644 test/libyul/yulStackLayout/for.yul create mode 100644 test/libyul/yulStackLayout/function.yul create mode 100644 test/libyul/yulStackLayout/if.yul create mode 100644 test/libyul/yulStackLayout/stub.yul create mode 100644 test/libyul/yulStackLayout/switch.yul create mode 100644 test/libyul/yulStackLayout/variables.yul diff --git a/libsolutil/CommonData.h b/libsolutil/CommonData.h index 7c2370370..774cedf0a 100644 --- a/libsolutil/CommonData.h +++ b/libsolutil/CommonData.h @@ -52,6 +52,21 @@ template std::vector& operator+=(std::vector& _a, U&& _ std::move(_b.begin(), _b.end(), std::back_inserter(_a)); return _a; } + +/// Concatenate the contents of a container onto a list +template std::list& operator+=(std::list& _a, U& _b) +{ + for (auto const& i: _b) + _a.push_back(T(i)); + return _a; +} +/// Concatenate the contents of a container onto a list, move variant. +template std::list& operator+=(std::list& _a, U&& _b) +{ + std::move(_b.begin(), _b.end(), std::back_inserter(_a)); + return _a; +} + /// Concatenate the contents of a container onto a multiset template std::multiset& operator+=(std::multiset& _a, U& _b) { @@ -321,6 +336,44 @@ void joinMap(std::map& _a, std::map&& _b, F _conflictSolver) } } +namespace detail +{ + +template +auto findOffset(Container&& _container, Value&& _value, int) +-> decltype(_container.find(_value) == _container.end(), std::distance(_container.begin(), _container.find(_value)), std::optional()) +{ + auto it = _container.find(std::forward(_value)); + auto end = _container.end(); + if (it == end) + return std::nullopt; + return std::distance(_container.begin(), it); +} +template +auto findOffset(Range&& _range, Value&& _value, void*) +-> decltype(std::find(std::begin(_range), std::end(_range), std::forward(_value)) == std::end(_range), std::optional()) +{ + auto begin = std::begin(_range); + auto end = std::end(_range); + auto it = std::find(begin, end, std::forward(_value)); + if (it == end) + return std::nullopt; + return std::distance(begin, it); +} + +} + +/// @returns an std::optional containing the offset of the first element in @a _range that is equal to @a _value, +/// if any, or std::nullopt otherwise. +/// Uses a linear search (``std::find``) unless @a _range is a container and provides a +/// suitable ``.find`` function (e.g. it will use the logarithmic ``.find`` function in ``std::set`` instead). +template +auto findOffset(Range&& _range, std::remove_reference_t const& _value) +-> decltype(detail::findOffset(std::forward(_range), _value, 0)) +{ + return detail::findOffset(std::forward(_range), _value, 0); +} + // String conversion functions, mainly to/from hex/nibble/byte representations. enum class WhenError diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index 5e816d988..278f80545 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -68,6 +68,9 @@ add_library(yul backends/evm/EVMMetrics.h backends/evm/NoOutputAssembly.h backends/evm/NoOutputAssembly.cpp + backends/evm/StackHelpers.h + backends/evm/StackLayoutGenerator.h + backends/evm/StackLayoutGenerator.cpp backends/evm/VariableReferenceCounter.h backends/evm/VariableReferenceCounter.cpp backends/wasm/EVMToEwasmTranslator.cpp diff --git a/libyul/backends/evm/ControlFlowGraph.h b/libyul/backends/evm/ControlFlowGraph.h index 5a404938b..b78a37843 100644 --- a/libyul/backends/evm/ControlFlowGraph.h +++ b/libyul/backends/evm/ControlFlowGraph.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -54,8 +55,19 @@ struct FunctionCallReturnLabelSlot /// the function. struct FunctionReturnLabelSlot { - bool operator==(FunctionReturnLabelSlot const&) const { return true; } - bool operator<(FunctionReturnLabelSlot const&) const { return false; } + std::reference_wrapper function; + bool operator==(FunctionReturnLabelSlot const& _rhs) const + { + // There can never be return label slots of different functions on stack simultaneously. + yulAssert(&function.get() == &_rhs.function.get(), ""); + return true; + } + bool operator<(FunctionReturnLabelSlot const& _rhs) const + { + // There can never be return label slots of different functions on stack simultaneously. + yulAssert(&function.get() == &_rhs.function.get(), ""); + return false; + } static constexpr bool canBeFreelyGenerated = false; }; /// A slot containing the current value of a particular variable. diff --git a/libyul/backends/evm/StackHelpers.h b/libyul/backends/evm/StackHelpers.h new file mode 100644 index 000000000..80e7d3834 --- /dev/null +++ b/libyul/backends/evm/StackHelpers.h @@ -0,0 +1,424 @@ +/* + 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 + +#pragma once + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +namespace solidity::yul +{ + +inline std::string stackSlotToString(StackSlot const& _slot) +{ + return std::visit(util::GenericVisitor{ + [](FunctionCallReturnLabelSlot const& _ret) -> std::string { return "RET[" + _ret.call.get().functionName.name.str() + "]"; }, + [](FunctionReturnLabelSlot const&) -> std::string { return "RET"; }, + [](VariableSlot const& _var) { return _var.variable.get().name.str(); }, + [](LiteralSlot const& _lit) { return util::toCompactHexWithPrefix(_lit.value); }, + [](TemporarySlot const& _tmp) -> std::string { return "TMP[" + _tmp.call.get().functionName.name.str() + ", " + std::to_string(_tmp.index) + "]"; }, + [](JunkSlot const&) -> std::string { return "JUNK"; } + }, _slot); +} + +inline std::string stackToString(Stack const& _stack) +{ + std::string result("[ "); + for (auto const& slot: _stack) + result += stackSlotToString(slot) + ' '; + result += ']'; + return result; +} + + +// Abstraction of stack shuffling operations. Can be defined as actual concept once we switch to C++20. +// Used as an interface for the stack shuffler below. +// The shuffle operation class is expected to internally keep track of a current stack layout (the "source layout") +// that the shuffler is supposed to shuffle to a fixed target stack layout. +// The shuffler works iteratively. At each iteration it instantiates an instance of the shuffle operations and +// queries it for various information about the current source stack layout and the target layout, as described +// in the interface below. +// Based on that information the shuffler decides which is the next optimal operation to perform on the stack +// and calls the corresponding entry point in the shuffling operations (swap, pushOrDupTarget or pop). +/* +template +concept ShuffleOperationConcept = requires(ShuffleOperations ops, size_t sourceOffset, size_t targetOffset, size_t depth) { + // Returns true, iff the current slot at sourceOffset in source layout is a suitable slot at targetOffset. + { ops.isCompatible(sourceOffset, targetOffset) } -> std::convertible_to; + // Returns true, iff the slots at the two given source offsets are identical. + { ops.sourceIsSame(sourceOffset, sourceOffset) } -> std::convertible_to; + // Returns a positive integer n, if the slot at the given source offset needs n more copies. + // Returns a negative integer -n, if the slot at the given source offsets occurs n times too many. + // Returns zero if the amount of occurrences, in the current source layout, of the slot at the given source offset + // matches the desired amount of occurrences in the target. + { ops.sourceMultiplicity(sourceOffset) } -> std::convertible_to; + // Returns a positive integer n, if the slot at the given target offset needs n more copies. + // Returns a negative integer -n, if the slot at the given target offsets occurs n times too many. + // Returns zero if the amount of occurrences, in the current source layout, of the slot at the given target offset + // matches the desired amount of occurrences in the target. + { ops.targetMultiplicity(targetOffset) } -> std::convertible_to; + // Returns true, iff any slot is compatible with the given target offset. + { ops.targetIsArbitrary(targetOffset) } -> std::convertible_to; + // Returns the number of slots in the source layout. + { ops.sourceSize() } -> std::convertible_to; + // Returns the number of slots in the target layout. + { ops.targetSize() } -> std::convertible_to; + // Swaps the top most slot in the source with the slot `depth` slots below the top. + // In terms of EVM opcodes this is supposed to be a `SWAP`. + // In terms of vectors this is supposed to be `std::swap(source.at(source.size() - depth - 1, source.top))`. + { ops.swap(depth) }; + // Pops the top most slot in the source, i.e. the slot at offset ops.sourceSize() - 1. + // In terms of EVM opcodes this is `POP`. + // In terms of vectors this is `source.pop();`. + { ops.pop() }; + // Dups or pushes the slot that is supposed to end up at the given target offset. + { ops.pushOrDupTarget(targetOffset) }; +}; +*/ +/// Helper class that can perform shuffling of a source stack layout to a target stack layout via +/// abstracted shuffle operations. +template +class Shuffler +{ +public: + /// Executes the stack shuffling operations. Instantiates an instance of ShuffleOperations + /// in each iteration. Each iteration performs exactly one operation that modifies the stack. + /// After `shuffle`, source and target have the same size and all slots in the source layout are + /// compatible with the slots at the same target offset. + template + static void shuffle(Args&&... args) + { + bool needsMoreShuffling = true; + // The shuffling algorithm should always terminate in polynomial time, but we provide a limit + // in case it does not terminate due to a bug. + size_t iterationCount = 0; + while (iterationCount < 1000 && (needsMoreShuffling = shuffleStep(std::forward(args)...))) + ++iterationCount; + yulAssert(!needsMoreShuffling, "Could not create stack layout after 1000 iterations."); + } +private: + // If dupping an ideal slot causes a slot that will still be required to become unreachable, then dup + // the latter slot first. + // @returns true, if it performed a dup. + static bool dupDeepSlotIfRequired(ShuffleOperations& _ops) + { + // Check if the stack is large enough for anything to potentially become unreachable. + if (_ops.sourceSize() < 15) + return false; + // Check whether any deep slot might still be needed later (i.e. we still need to reach it with a DUP or SWAP). + for (size_t sourceOffset: ranges::views::iota(0u, _ops.sourceSize() - 15)) + { + // This slot needs to be moved. + if (!_ops.isCompatible(sourceOffset, sourceOffset)) + { + // If the current top fixes the slot, swap it down now. + if (_ops.isCompatible(_ops.sourceSize() - 1, sourceOffset)) + { + _ops.swap(_ops.sourceSize() - sourceOffset - 1); + return true; + } + // Bring up a slot to fix this now, if possible. + if (bringUpTargetSlot(_ops, sourceOffset)) + return true; + // Otherwise swap up the slot that will fix the offending slot. + for (auto offset: ranges::views::iota(sourceOffset + 1, _ops.sourceSize())) + if (_ops.isCompatible(offset, sourceOffset)) + { + _ops.swap(_ops.sourceSize() - offset - 1); + return true; + } + // Otherwise give up - we will need stack compression or stack limit evasion. + } + // We need another copy of this slot. + else if (_ops.sourceMultiplicity(sourceOffset) > 0) + { + // If this slot occurs again later, we skip this occurrence. + if (ranges::any_of( + ranges::views::iota(sourceOffset + 1, _ops.sourceSize()), + [&](size_t _offset) { return _ops.sourceIsSame(sourceOffset, _offset); } + )) + continue; + // Bring up the target slot that would otherwise become unreachable. + for (size_t targetOffset: ranges::views::iota(0u, _ops.targetSize())) + if (!_ops.targetIsArbitrary(targetOffset) && _ops.isCompatible(sourceOffset, targetOffset)) + { + _ops.pushOrDupTarget(targetOffset); + return true; + } + } + } + return false; + } + /// Finds a slot to dup or push with the aim of eventually fixing @a _targetOffset in the target. + /// In the simplest case, the slot at @a _targetOffset has a multiplicity > 0, i.e. it can directly be dupped or pushed + /// and the next iteration will fix @a _targetOffset. + /// But, in general, there may already be enough copies of the slot that is supposed to end up at @a _targetOffset + /// on stack, s.t. it cannot be dupped again. In that case there has to be a copy of the desired slot on stack already + /// elsewhere that is not yet in place (`nextOffset` below). The fact that ``nextOffset`` is not in place means that + /// we can (recursively) try bringing up the slot that is supposed to end up at ``nextOffset`` in the *target*. + /// When the target slot at ``nextOffset`` is fixed, the current source slot at ``nextOffset`` will be + /// at the stack top, which is the slot required at @a _targetOffset. + static bool bringUpTargetSlot(ShuffleOperations& _ops, size_t _targetOffset) + { + std::list toVisit{_targetOffset}; + std::set visited; + + while (!toVisit.empty()) + { + auto offset = *toVisit.begin(); + toVisit.erase(toVisit.begin()); + visited.emplace(offset); + if (_ops.targetMultiplicity(offset) > 0) + { + _ops.pushOrDupTarget(offset); + return true; + } + // There must be another slot we can dup/push that will lead to the target slot at ``offset`` to be fixed. + for (auto nextOffset: ranges::views::iota(0u, std::min(_ops.sourceSize(), _ops.targetSize()))) + if ( + !_ops.isCompatible(nextOffset, nextOffset) && + _ops.isCompatible(nextOffset, offset) + ) + if (!visited.count(nextOffset)) + toVisit.emplace_back(nextOffset); + } + return false; + } + /// Performs a single stack operation, transforming the source layout closer to the target layout. + template + static bool shuffleStep(Args&&... args) + { + ShuffleOperations ops{std::forward(args)...}; + + // All source slots are final. + if (ranges::all_of( + ranges::views::iota(0u, ops.sourceSize()), + [&](size_t _index) { return ops.isCompatible(_index, _index); } + )) + { + // Bring up all remaining target slots, if any, or terminate otherwise. + if (ops.sourceSize() < ops.targetSize()) + { + if (!dupDeepSlotIfRequired(ops)) + yulAssert(bringUpTargetSlot(ops, ops.sourceSize()), ""); + return true; + } + return false; + } + + size_t sourceTop = ops.sourceSize() - 1; + // If we no longer need the current stack top, we pop it, unless we need an arbitrary slot at this position + // in the target. + if ( + ops.sourceMultiplicity(sourceTop) < 0 && + !ops.targetIsArbitrary(sourceTop) + ) + { + ops.pop(); + return true; + } + + yulAssert(ops.targetSize() > 0, ""); + + // If the top is not supposed to be exactly what is on top right now, try to find a lower position to swap it to. + if (!ops.isCompatible(sourceTop, sourceTop) || ops.targetIsArbitrary(sourceTop)) + for (size_t offset: ranges::views::iota(0u, std::min(ops.sourceSize(), ops.targetSize()))) + // It makes sense to swap to a lower position, if + if ( + !ops.isCompatible(offset, offset) && // The lower slot is not already in position. + !ops.sourceIsSame(offset, sourceTop) && // We would not just swap identical slots. + ops.isCompatible(sourceTop, offset) // The lower position wants to have this slot. + ) + { + // We cannot swap that deep. + if (ops.sourceSize() - offset - 1 > 16) + { + // If there is a reachable slot to be removed, park the current top there. + for (size_t swapDepth: ranges::views::iota(1u, 17u) | ranges::views::reverse) + if (ops.sourceMultiplicity(ops.sourceSize() - 1 - swapDepth) < 0) + { + ops.swap(swapDepth); + return true; + } + // Otherwise we rely on stack compression or stack-to-memory. + } + ops.swap(ops.sourceSize() - offset - 1); + return true; + } + + // ops.sourceSize() > ops.targetSize() cannot be true anymore, since if the source top is no longer required, + // we already popped it, and if it is required, we already swapped it down to a suitable target position. + yulAssert(ops.sourceSize() <= ops.targetSize(), ""); + + // If a lower slot should be removed, try to bring up the slot that should end up there and bring it up. + // Note that after the cases above, there will always be a target slot to duplicate in this case. + for (size_t offset: ranges::views::iota(0u, ops.sourceSize())) + if ( + !ops.isCompatible(offset, offset) && // The lower slot is not already in position. + ops.sourceMultiplicity(offset) < 0 && // We have too many copies of this slot. + offset <= ops.targetSize() && // There is a target slot at this position. + !ops.targetIsArbitrary(offset) // And that target slot is not arbitrary. + ) + { + if (!dupDeepSlotIfRequired(ops)) + yulAssert(bringUpTargetSlot(ops, offset), ""); + return true; + } + + // At this point we want to keep all slots. + for (size_t i = 0; i < ops.sourceSize(); ++i) + yulAssert(ops.sourceMultiplicity(i) >= 0, ""); + yulAssert(ops.sourceSize() <= ops.targetSize(), ""); + + // If the top is not in position, try to find a slot that wants to be at the top and swap it up. + if (!ops.isCompatible(sourceTop, sourceTop)) + for (size_t sourceOffset: ranges::views::iota(0u, ops.sourceSize())) + if ( + !ops.isCompatible(sourceOffset, sourceOffset) && + ops.isCompatible(sourceOffset, sourceTop) + ) + { + ops.swap(ops.sourceSize() - sourceOffset - 1); + return true; + } + + // If we still need more slots, produce a suitable one. + if (ops.sourceSize() < ops.targetSize()) + { + if (!dupDeepSlotIfRequired(ops)) + yulAssert(bringUpTargetSlot(ops, ops.sourceSize()), ""); + return true; + } + + // The stack has the correct size, each slot has the correct number of copies and the top is in position. + yulAssert(ops.sourceSize() == ops.targetSize(), ""); + size_t size = ops.sourceSize(); + for (size_t i = 0; i < ops.sourceSize(); ++i) + yulAssert(ops.sourceMultiplicity(i) == 0 && (ops.targetIsArbitrary(i) || ops.targetMultiplicity(i) == 0), ""); + yulAssert(ops.isCompatible(sourceTop, sourceTop), ""); + + // If we find a lower slot that is out of position, but also compatible with the top, swap that up. + for (size_t offset: ranges::views::iota(0u, size)) + if (!ops.isCompatible(offset, offset) && ops.isCompatible(sourceTop, offset)) + { + ops.swap(size - offset - 1); + return true; + } + // Swap up any slot that is still out of position. + for (size_t offset: ranges::views::iota(0u, size)) + if (!ops.isCompatible(offset, offset) && !ops.sourceIsSame(offset, sourceTop)) + { + ops.swap(size - offset - 1); + return true; + } + yulAssert(false, ""); + } +}; + + +/// Transforms @a _currentStack to @a _targetStack, invoking the provided shuffling operations. +/// Modifies @a _currentStack itself after each invocation of the shuffling operations. +template +void createStackLayout(Stack& _currentStack, Stack const& _targetStack, Swap _swap, PushOrDup _pushOrDup, Pop _pop) +{ + struct ShuffleOperations + { + Stack& currentStack; + Stack const& targetStack; + Swap swapCallback; + PushOrDup pushOrDupCallback; + Pop popCallback; + std::map multiplicity; + ShuffleOperations( + Stack& _currentStack, + Stack const& _targetStack, + Swap _swap, + PushOrDup _pushOrDup, + Pop _pop + ): + currentStack(_currentStack), + targetStack(_targetStack), + swapCallback(_swap), + pushOrDupCallback(_pushOrDup), + popCallback(_pop) + { + for (auto const& slot: currentStack) + --multiplicity[slot]; + for (auto&& [offset, slot]: targetStack | ranges::views::enumerate) + if (std::holds_alternative(slot) && offset < currentStack.size()) + ++multiplicity[currentStack.at(offset)]; + else + ++multiplicity[slot]; + } + bool isCompatible(size_t _source, size_t _target) + { + return + _source < currentStack.size() && + _target < targetStack.size() && + ( + std::holds_alternative(targetStack.at(_target)) || + currentStack.at(_source) == targetStack.at(_target) + ); + } + bool sourceIsSame(size_t _lhs, size_t _rhs) { return currentStack.at(_lhs) == currentStack.at(_rhs); } + int sourceMultiplicity(size_t _offset) { return multiplicity.at(currentStack.at(_offset)); } + int targetMultiplicity(size_t _offset) { return multiplicity.at(targetStack.at(_offset)); } + bool targetIsArbitrary(size_t offset) + { + return offset < targetStack.size() && std::holds_alternative(targetStack.at(offset)); + } + void swap(size_t _i) + { + swapCallback(static_cast(_i)); + std::swap(currentStack.at(currentStack.size() - _i - 1), currentStack.back()); + } + size_t sourceSize() { return currentStack.size(); } + size_t targetSize() { return targetStack.size(); } + void pop() + { + popCallback(); + currentStack.pop_back(); + } + void pushOrDupTarget(size_t _offset) + { + auto const& targetSlot = targetStack.at(_offset); + pushOrDupCallback(targetSlot); + currentStack.push_back(targetSlot); + } + }; + + Shuffler::shuffle(_currentStack, _targetStack, _swap, _pushOrDup, _pop); + + yulAssert(_currentStack.size() == _targetStack.size(), ""); + for (auto&& [current, target]: ranges::zip_view(_currentStack, _targetStack)) + if (std::holds_alternative(target)) + current = JunkSlot{}; + else + yulAssert(current == target, ""); +} + +} diff --git a/libyul/backends/evm/StackLayoutGenerator.cpp b/libyul/backends/evm/StackLayoutGenerator.cpp new file mode 100644 index 000000000..2b82c4b6c --- /dev/null +++ b/libyul/backends/evm/StackLayoutGenerator.cpp @@ -0,0 +1,578 @@ +/* + 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 +/** + * Stack layout generator for Yul to EVM code generation. + */ + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace solidity; +using namespace solidity::yul; +using namespace std; + +StackLayout StackLayoutGenerator::run(CFG const& _cfg) +{ + StackLayout stackLayout; + StackLayoutGenerator{stackLayout}.processEntryPoint(*_cfg.entry); + + for (auto& functionInfo: _cfg.functionInfo | ranges::views::values) + StackLayoutGenerator{stackLayout}.processEntryPoint(*functionInfo.entry); + + return stackLayout; +} + +StackLayoutGenerator::StackLayoutGenerator(StackLayout& _layout): m_layout(_layout) +{ +} + +namespace +{ + +/// @returns the ideal stack to have before executing an operation that outputs @a _operationOutput, s.t. +/// shuffling to @a _post is cheap (excluding the input of the operation itself). +/// If @a _generateSlotOnTheFly returns true for a slot, this slot should not occur in the ideal stack, but +/// rather be generated on the fly during shuffling. +template +Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Callable _generateSlotOnTheFly) +{ + struct PreviousSlot { size_t slot; }; + + // Determine the number of slots that have to be on stack before executing the operation (excluding + // the inputs of the operation itself). + // That is slots that should not be generated on the fly and are not outputs of the operation. + size_t preOperationLayoutSize = _post.size(); + for (auto const& slot: _post) + if (util::contains(_operationOutput, slot) || _generateSlotOnTheFly(slot)) + --preOperationLayoutSize; + + // The symbolic layout directly after the operation has the form + // PreviousSlot{0}, ..., PreviousSlot{n}, [output<0>], ..., [output] + auto layout = ranges::views::iota(0u, preOperationLayoutSize) | + ranges::views::transform([](size_t _index) { return PreviousSlot{_index}; }) | + ranges::to>>; + layout += _operationOutput; + + // Shortcut for trivial case. + if (layout.empty()) + return Stack{}; + + // Next we will shuffle the layout to the post stack using ShuffleOperations + // that are aware of PreviousSlot's. + struct ShuffleOperations + { + vector>& layout; + Stack const& post; + std::set outputs; + std::map multiplicity; + Callable generateSlotOnTheFly; + ShuffleOperations( + vector>& _layout, + Stack const& _post, + Callable _generateSlotOnTheFly + ): layout(_layout), post(_post), generateSlotOnTheFly(_generateSlotOnTheFly) + { + for (auto const& layoutSlot: layout) + if (StackSlot const* slot = get_if(&layoutSlot)) + outputs.insert(*slot); + + for (auto const& layoutSlot: layout) + if (StackSlot const* slot = get_if(&layoutSlot)) + --multiplicity[*slot]; + for (auto&& slot: post) + if (outputs.count(slot) || generateSlotOnTheFly(slot)) + ++multiplicity[slot]; + } + bool isCompatible(size_t _source, size_t _target) + { + return + _source < layout.size() && + _target < post.size() && + ( + std::holds_alternative(post.at(_target)) || + std::visit(util::GenericVisitor{ + [&](PreviousSlot const&) { + return !outputs.count(post.at(_target)) && !generateSlotOnTheFly(post.at(_target)); + }, + [&](StackSlot const& _s) { return _s == post.at(_target); } + }, layout.at(_source)) + ); + } + bool sourceIsSame(size_t _lhs, size_t _rhs) + { + return std::visit(util::GenericVisitor{ + [&](PreviousSlot const&, PreviousSlot const&) { return true; }, + [&](StackSlot const& _lhs, StackSlot const& _rhs) { return _lhs == _rhs; }, + [&](auto const&, auto const&) { return false; } + }, layout.at(_lhs), layout.at(_rhs)); + } + int sourceMultiplicity(size_t _offset) + { + return std::visit(util::GenericVisitor{ + [&](PreviousSlot const&) { return 0; }, + [&](StackSlot const& _s) { return multiplicity.at(_s); } + }, layout.at(_offset)); + } + int targetMultiplicity(size_t _offset) + { + if (!outputs.count(post.at(_offset)) && !generateSlotOnTheFly(post.at(_offset))) + return 0; + return multiplicity.at(post.at(_offset)); + } + bool targetIsArbitrary(size_t _offset) + { + return _offset < post.size() && std::holds_alternative(post.at(_offset)); + } + void swap(size_t _i) + { + yulAssert(!holds_alternative(layout.at(layout.size() - _i - 1)) || !holds_alternative(layout.back()), ""); + std::swap(layout.at(layout.size() - _i - 1), layout.back()); + } + size_t sourceSize() { return layout.size(); } + size_t targetSize() { return post.size(); } + void pop() { layout.pop_back(); } + void pushOrDupTarget(size_t _offset) { layout.push_back(post.at(_offset)); } + }; + Shuffler::shuffle(layout, _post, _generateSlotOnTheFly); + + // Now we can construct the ideal layout before the operation. + // "layout" has shuffled the PreviousSlot{x} to new places using minimal operations to move the operation + // output in place. The resulting permutation of the PreviousSlot yields the ideal positions of slots + // before the operation, i.e. if PreviousSlot{2} is at a position at which _post contains VariableSlot{"tmp"}, + // then we want the variable tmp in the slot at offset 2 in the layout before the operation. + vector> idealLayout(_post.size(), nullopt); + for (auto const& [slot, idealPosition]: ranges::zip_view(_post, layout)) + if (PreviousSlot* previousSlot = std::get_if(&idealPosition)) + idealLayout.at(previousSlot->slot) = slot; + + // The tail of layout must have contained the operation outputs and will not have been assigned slots in the last loop. + while (!idealLayout.empty() && !idealLayout.back()) + idealLayout.pop_back(); + + yulAssert(idealLayout.size() == preOperationLayoutSize, ""); + + return idealLayout | ranges::views::transform([](optional s) { + yulAssert(s, ""); + return *s; + }) | ranges::to; +} +} + +Stack StackLayoutGenerator::propagateStackThroughOperation(Stack _exitStack, CFG::Operation const& _operation) +{ + // This is a huge tradeoff between code size, gas cost and stack size. + auto generateSlotOnTheFly = [&](StackSlot const&) { + //return stack.size() > 12 && canBeFreelyGenerated(_slot); + // return canBeFreelyGenerated(_slot); + return false; + }; + + // Determine the ideal permutation of the slots in _exitLayout that are not operation outputs (and not to be + // generated on the fly), s.t. shuffling the `stack + _operation.output` to _exitLayout is cheap. + Stack stack = createIdealLayout(_operation.output, _exitStack, generateSlotOnTheFly); + + // Make sure the resulting previous slots do not overlap with any assignmed variables. + if (auto const* assignment = get_if(&_operation.operation)) + for (auto& stackSlot: stack) + if (auto const* varSlot = get_if(&stackSlot)) + yulAssert(!util::contains(assignment->variables, *varSlot), ""); + + // Since stack+_operation.output can be easily shuffled to _exitLayout, the desired layout before the operation + // is stack+_operation.input; + stack += _operation.input; + + // Store the exact desired operation entry layout. The stored layout will be recreated by the code transform + // before executing the operation. However, this recreation can produce slots that can be freely generated or + // are duplicated, i.e. we can compress the stack afterwards without causing problems for code generation later. + m_layout.operationEntryLayout[&_operation] = stack; + + // Remove anything from the stack top that can be freely generated or dupped from deeper on the stack. + while (!stack.empty()) + { + if (canBeFreelyGenerated(stack.back())) + stack.pop_back(); + else if (auto offset = util::findOffset(stack | ranges::views::reverse | ranges::views::drop(1), stack.back())) + { + if (*offset + 2 < 16) + stack.pop_back(); + else + break; + } + else + break; + } + + // TODO: there may be a better criterion than overall stack size. + if (stack.size() > 12) + // Deduplicate and remove slots that can be freely generated. + stack = compressStack(move(stack)); + return stack; +} + +Stack StackLayoutGenerator::propagateStackThroughBlock(Stack _exitStack, CFG::BasicBlock const& _block) +{ + Stack stack = std::move(_exitStack); + for (auto& operation: _block.operations | ranges::views::reverse) + stack = propagateStackThroughOperation(stack, operation); + return stack; +} + +void StackLayoutGenerator::processEntryPoint(CFG::BasicBlock const& _entry) +{ + list toVisit{&_entry}; + set visited; + + // TODO: check whether visiting only a subset of these in the outer iteration below is enough. + list> backwardsJumps = collectBackwardsJumps(_entry); + + while (!toVisit.empty()) + { + // First calculate stack layouts without walking backwards jumps, i.e. assuming the current preliminary + // entry layout of the backwards jump target as the initial exit layout of the backwards-jumping block. + while (!toVisit.empty()) + { + CFG::BasicBlock const *block = *toVisit.begin(); + toVisit.pop_front(); + + if (visited.count(block)) + continue; + + if (std::optional exitLayout = getExitLayoutOrStageDependencies(*block, visited, toVisit)) + { + visited.emplace(block); + auto& info = m_layout.blockInfos[block]; + info.exitLayout = *exitLayout; + info.entryLayout = propagateStackThroughBlock(info.exitLayout, *block); + + for (auto entry: block->entries) + toVisit.emplace_back(entry); + } + else + continue; + } + + // Determine which backwards jumps still require fixing and stage revisits of appropriate nodes. + for (auto [jumpingBlock, target]: backwardsJumps) + // This block jumps backwards, but does not provide all slots required by the jump target on exit. + // Therefore we need to visit the subgraph between ``target`` and ``jumpingBlock`` again. + if (ranges::any_of( + m_layout.blockInfos[target].entryLayout, + [exitLayout = m_layout.blockInfos[jumpingBlock].exitLayout](StackSlot const& _slot) { + return !util::contains(exitLayout, _slot); + } + )) + { + // In particular we can visit backwards starting from ``jumpingBlock`` and mark all entries to-be-visited- + // again until we hit ``target``. + toVisit.emplace_front(jumpingBlock); + // Since we are likely to permute the entry layout of ``target``, we also visit its entries again. + // This is not required for correctness, since the set of stack slots will match, but it may move some + // required stack shuffling from the loop condition to outside the loop. + for (CFG::BasicBlock const* entry: target->entries) + visited.erase(entry); + util::BreadthFirstSearch{{jumpingBlock}}.run( + [&visited, target = target](CFG::BasicBlock const* _block, auto _addChild) { + visited.erase(_block); + if (_block == target) + return; + for (auto const* entry: _block->entries) + _addChild(entry); + } + ); + // While the shuffled layout for ``target`` will be compatible, it can be worthwhile propagating + // it further up once more. + // This would mean not stopping at _block == target above, resp. even doing visited.clear() here, revisiting the entire graph. + // This is a tradeoff between the runtime of this process and the optimality of the result. + // Also note that while visiting the entire graph again *can* be helpful, it can also be detrimental. + } + } + + stitchConditionalJumps(_entry); +} + +optional StackLayoutGenerator::getExitLayoutOrStageDependencies( + CFG::BasicBlock const& _block, + set const& _visited, + list& _toVisit +) const +{ + return std::visit(util::GenericVisitor{ + [&](CFG::BasicBlock::MainExit const&) -> std::optional + { + // On the exit of the outermost block the stack can be empty. + return Stack{}; + }, + [&](CFG::BasicBlock::Jump const& _jump) -> std::optional + { + if (_jump.backwards) + { + // Choose the best currently known entry layout of the jump target as initial exit. + // Note that this may not yet be the final layout. + if (auto* info = util::valueOrNullptr(m_layout.blockInfos, _jump.target)) + return info->entryLayout; + return Stack{}; + } + // If the current iteration has already visited the jump target, start from its entry layout. + if (_visited.count(_jump.target)) + return m_layout.blockInfos.at(_jump.target).entryLayout; + // Otherwise stage the jump target for visit and defer the current block. + _toVisit.emplace_front(_jump.target); + return nullopt; + }, + [&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) -> std::optional + { + bool zeroVisited = _visited.count(_conditionalJump.zero); + bool nonZeroVisited = _visited.count(_conditionalJump.nonZero); + if (zeroVisited && nonZeroVisited) + { + // If the current iteration has already visited both jump targets, start from its entry layout. + Stack stack = combineStack( + m_layout.blockInfos.at(_conditionalJump.zero).entryLayout, + m_layout.blockInfos.at(_conditionalJump.nonZero).entryLayout + ); + // Additionally, the jump condition has to be at the stack top at exit. + stack.emplace_back(_conditionalJump.condition); + return stack; + } + // If one of the jump targets has not been visited, stage it for visit and defer the current block. + if (!zeroVisited) + _toVisit.emplace_front(_conditionalJump.zero); + if (!nonZeroVisited) + _toVisit.emplace_front(_conditionalJump.nonZero); + return nullopt; + }, + [&](CFG::BasicBlock::FunctionReturn const& _functionReturn) -> std::optional + { + // A function return needs the return variables and the function return label slot on stack. + yulAssert(_functionReturn.info, ""); + Stack stack = _functionReturn.info->returnVariables | ranges::views::transform([](auto const& _varSlot){ + return StackSlot{_varSlot}; + }) | ranges::to; + stack.emplace_back(FunctionReturnLabelSlot{_functionReturn.info->function}); + return stack; + }, + [&](CFG::BasicBlock::Terminated const&) -> std::optional + { + // A terminating block can have an empty stack on exit. + return Stack{}; + }, + }, _block.exit); +} + +list> StackLayoutGenerator::collectBackwardsJumps(CFG::BasicBlock const& _entry) const +{ + list> backwardsJumps; + util::BreadthFirstSearch{{&_entry}}.run([&](CFG::BasicBlock const* _block, auto _addChild) { + std::visit(util::GenericVisitor{ + [&](CFG::BasicBlock::MainExit const&) {}, + [&](CFG::BasicBlock::Jump const& _jump) + { + if (_jump.backwards) + backwardsJumps.emplace_back(_block, _jump.target); + _addChild(_jump.target); + }, + [&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) + { + _addChild(_conditionalJump.zero); + _addChild(_conditionalJump.nonZero); + }, + [&](CFG::BasicBlock::FunctionReturn const&) {}, + [&](CFG::BasicBlock::Terminated const&) {}, + }, _block->exit); + }); + return backwardsJumps; +} + +void StackLayoutGenerator::stitchConditionalJumps(CFG::BasicBlock const& _block) +{ + util::BreadthFirstSearch breadthFirstSearch{{&_block}}; + breadthFirstSearch.run([&](CFG::BasicBlock const* _block, auto _addChild) { + auto& info = m_layout.blockInfos.at(_block); + std::visit(util::GenericVisitor{ + [&](CFG::BasicBlock::MainExit const&) {}, + [&](CFG::BasicBlock::Jump const& _jump) + { + if (!_jump.backwards) + _addChild(_jump.target); + }, + [&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) + { + auto& zeroTargetInfo = m_layout.blockInfos.at(_conditionalJump.zero); + auto& nonZeroTargetInfo = m_layout.blockInfos.at(_conditionalJump.nonZero); + Stack exitLayout = info.exitLayout; + + // The last block must have produced the condition at the stack top. + yulAssert(!exitLayout.empty(), ""); + yulAssert(exitLayout.back() == _conditionalJump.condition, ""); + // The condition is consumed by the jump. + exitLayout.pop_back(); + + auto fixJumpTargetEntry = [&](Stack const& _originalEntryLayout) -> Stack { + Stack newEntryLayout = exitLayout; + // Whatever the block being jumped to does not actually require, can be marked as junk. + for (auto& slot: newEntryLayout) + if (!util::contains(_originalEntryLayout, slot)) + slot = JunkSlot{}; + // Make sure everything the block being jumped to requires is actually present or can be generated. + for (auto const& slot: _originalEntryLayout) + yulAssert(canBeFreelyGenerated(slot) || util::contains(newEntryLayout, slot), ""); + return newEntryLayout; + }; + zeroTargetInfo.entryLayout = fixJumpTargetEntry(zeroTargetInfo.entryLayout); + nonZeroTargetInfo.entryLayout = fixJumpTargetEntry(nonZeroTargetInfo.entryLayout); + _addChild(_conditionalJump.zero); + _addChild(_conditionalJump.nonZero); + }, + [&](CFG::BasicBlock::FunctionReturn const&) {}, + [&](CFG::BasicBlock::Terminated const&) { }, + }, _block->exit); + }); +} + +Stack StackLayoutGenerator::combineStack(Stack const& _stack1, Stack const& _stack2) +{ + // TODO: it would be nicer to replace this by a constructive algorithm. + // Currently it uses a reduced version of the Heap Algorithm to partly brute-force, which seems + // to work decently well. + + Stack commonPrefix; + for (auto&& [slot1, slot2]: ranges::zip_view(_stack1, _stack2)) + { + if (!(slot1 == slot2)) + break; + commonPrefix.emplace_back(slot1); + } + + Stack stack1Tail = _stack1 | ranges::views::drop(commonPrefix.size()) | ranges::to; + Stack stack2Tail = _stack2 | ranges::views::drop(commonPrefix.size()) | ranges::to; + + if (stack1Tail.empty()) + return commonPrefix + compressStack(stack2Tail); + if (stack2Tail.empty()) + return commonPrefix + compressStack(stack1Tail); + + Stack candidate; + for (auto slot: stack1Tail) + if (!util::contains(candidate, slot)) + candidate.emplace_back(slot); + for (auto slot: stack2Tail) + if (!util::contains(candidate, slot)) + candidate.emplace_back(slot); + cxx20::erase_if(candidate, [](StackSlot const& slot) { + return holds_alternative(slot) || holds_alternative(slot); + }); + + auto evaluate = [&](Stack const& _candidate) -> size_t { + size_t numOps = 0; + Stack testStack = _candidate; + auto swap = [&](unsigned _swapDepth) { ++numOps; if (_swapDepth > 16) numOps += 1000; }; + auto dupOrPush = [&](StackSlot const& _slot) + { + if (canBeFreelyGenerated(_slot)) + return; + auto depth = util::findOffset(ranges::concat_view(commonPrefix, testStack) | ranges::views::reverse, _slot); + if (depth && *depth >= 16) + numOps += 1000; + }; + createStackLayout(testStack, stack1Tail, swap, dupOrPush, [&](){} ); + testStack = _candidate; + createStackLayout(testStack, stack2Tail, swap, dupOrPush, [&](){}); + return numOps; + }; + + // See https://en.wikipedia.org/wiki/Heap's_algorithm + size_t n = candidate.size(); + Stack bestCandidate = candidate; + size_t bestCost = evaluate(candidate); + std::vector c(n, 0); + size_t i = 1; + while (i < n) + { + if (c[i] < i) + { + if (i & 1) + std::swap(candidate.front(), candidate[i]); + else + std::swap(candidate[c[i]], candidate[i]); + size_t cost = evaluate(candidate); + if (cost < bestCost) + { + bestCost = cost; + bestCandidate = candidate; + } + ++c[i]; + // Note that for a proper implementation of the Heap algorithm this would need to revert back to ``i = 1.`` + // However, the incorrect implementation produces decent result and the proper version would have n! + // complexity and is thereby not feasible. + ++i; + } + else + { + c[i] = 0; + ++i; + } + } + + return commonPrefix + bestCandidate; +} + +Stack StackLayoutGenerator::compressStack(Stack _stack) +{ + optional firstDupOffset; + do + { + if (firstDupOffset) + { + std::swap(_stack.at(*firstDupOffset), _stack.back()); + _stack.pop_back(); + firstDupOffset.reset(); + } + for (auto&& [depth, slot]: _stack | ranges::views::reverse | ranges::views::enumerate) + if (canBeFreelyGenerated(slot)) + { + firstDupOffset = _stack.size() - depth - 1; + break; + } + else if (auto dupDepth = util::findOffset(_stack | ranges::views::reverse | ranges::views::drop(depth + 1), slot)) + if (depth + *dupDepth <= 16) + { + firstDupOffset = _stack.size() - depth - 1; + break; + } + } + while (firstDupOffset); + return _stack; +} diff --git a/libyul/backends/evm/StackLayoutGenerator.h b/libyul/backends/evm/StackLayoutGenerator.h new file mode 100644 index 000000000..a5b05654b --- /dev/null +++ b/libyul/backends/evm/StackLayoutGenerator.h @@ -0,0 +1,97 @@ +/* + 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 +/** + * Stack layout generator for Yul to EVM code generation. + */ + +#pragma once + +#include + +#include + +namespace solidity::yul +{ + +struct StackLayout +{ + struct BlockInfo + { + /// Complete stack layout that is required for entering a block. + Stack entryLayout; + /// The resulting stack layout after executing the block. + Stack exitLayout; + }; + std::map blockInfos; + /// For each operation the complete stack layout that: + /// - has the slots required for the operation at the stack top. + /// - will have the operation result in a layout that makes it easy to achieve the next desired layout. + std::map operationEntryLayout; +}; + +class StackLayoutGenerator +{ +public: + static StackLayout run(CFG const& _cfg); + +private: + StackLayoutGenerator(StackLayout& _context); + + /// @returns the optimal entry stack layout, s.t. @a _operation can be applied to it and + /// the result can be transformed to @a _exitStack with minimal stack shuffling. + /// Simultaneously stores the entry layout required for executing the operation in m_layout. + Stack propagateStackThroughOperation(Stack _exitStack, CFG::Operation const& _operation); + + /// @returns the desired stack layout at the entry of @a _block, assuming the layout after + /// executing the block should be @a _exitStack. + Stack propagateStackThroughBlock(Stack _exitStack, CFG::BasicBlock const& _block); + + /// Main algorithm walking the graph from entry to exit and propagating back the stack layouts to the entries. + /// Iteratively reruns itself along backwards jumps until the layout is stabilized. + void processEntryPoint(CFG::BasicBlock const& _entry); + + /// @returns the best known exit layout of @a _block, if all dependencies are already @a _visited. + /// If not, adds the dependencies to @a _dependencyList and @returns std::nullopt. + std::optional getExitLayoutOrStageDependencies( + CFG::BasicBlock const& _block, + std::set const& _visited, + std::list& _dependencyList + ) const; + + /// @returns a pair of ``{jumpingBlock, targetBlock}`` for each backwards jump in the graph starting at @a _entry. + std::list> collectBackwardsJumps(CFG::BasicBlock const& _entry) const; + + /// After the main algorithms, layouts at conditional jumps are merely compatible, i.e. the exit layout of the + /// jumping block is a superset of the entry layout of the target block. This function modifies the entry layouts + /// of conditional jump targets, s.t. the entry layout of target blocks match the exit layout of the jumping block + /// exactly, except that slots not required after the jump are marked as `JunkSlot`s. + void stitchConditionalJumps(CFG::BasicBlock const& _block); + + /// Calculates the ideal stack layout, s.t. both @a _stack1 and @a _stack2 can be achieved with minimal + /// stack shuffling when starting from the returned layout. + static Stack combineStack(Stack const& _stack1, Stack const& _stack2); + + /// @returns a copy of @a _stack stripped of all duplicates and slots that can be freely generated. + /// Attempts to create a layout that requires a minimal amount of operations to reconstruct the original + /// stack @a _stack. + static Stack compressStack(Stack _stack); + + StackLayout& m_layout; +}; + +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index fa55d76a2..f35660741 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -143,6 +143,8 @@ set(libyul_sources libyul/ObjectCompilerTest.h libyul/ObjectParser.cpp libyul/Parser.cpp + libyul/StackLayoutGeneratorTest.cpp + libyul/StackLayoutGeneratorTest.h libyul/SyntaxTest.h libyul/SyntaxTest.cpp libyul/YulInterpreterTest.cpp diff --git a/test/InteractiveTests.h b/test/InteractiveTests.h index 4ffdf5a74..e27c00b84 100644 --- a/test/InteractiveTests.h +++ b/test/InteractiveTests.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -61,6 +62,7 @@ Testsuite const g_interactiveTestsuites[] = { {"Yul Interpreter", "libyul", "yulInterpreterTests", false, false, &yul::test::YulInterpreterTest::create}, {"Yul Object Compiler", "libyul", "objectCompiler", false, false, &yul::test::ObjectCompilerTest::create}, {"Yul Control Flow Graph", "libyul", "yulControlFlowGraph", false, false, &yul::test::ControlFlowGraphTest::create}, + {"Yul Stack Layout", "libyul", "yulStackLayout", false, false, &yul::test::StackLayoutGeneratorTest::create}, {"Function Side Effects", "libyul", "functionSideEffects", false, false, &yul::test::FunctionSideEffects::create}, {"Yul Syntax", "libyul", "yulSyntaxTests", false, false, &yul::test::SyntaxTest::create}, {"EVM Code Transform", "libyul", "evmCodeTransform", false, false, &yul::test::EVMCodeTransformTest::create, {"nooptions"}}, diff --git a/test/libyul/ControlFlowGraphTest.cpp b/test/libyul/ControlFlowGraphTest.cpp index 1107f4ca2..c77c190d3 100644 --- a/test/libyul/ControlFlowGraphTest.cpp +++ b/test/libyul/ControlFlowGraphTest.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -52,26 +53,6 @@ ControlFlowGraphTest::ControlFlowGraphTest(string const& _filename): namespace { -static std::string stackSlotToString(StackSlot const& _slot) -{ - return std::visit(util::GenericVisitor{ - [](FunctionCallReturnLabelSlot const& _ret) -> std::string { return "RET[" + _ret.call.get().functionName.name.str() + "]"; }, - [](FunctionReturnLabelSlot const&) -> std::string { return "RET"; }, - [](VariableSlot const& _var) { return _var.variable.get().name.str(); }, - [](LiteralSlot const& _lit) { return util::toCompactHexWithPrefix(_lit.value); }, - [](TemporarySlot const& _tmp) -> std::string { return "TMP[" + _tmp.call.get().functionName.name.str() + ", " + std::to_string(_tmp.index) + "]"; }, - [](JunkSlot const&) -> std::string { return "JUNK"; } - }, _slot); -} - -static std::string stackToString(Stack const& _stack) -{ - std::string result("[ "); - for (auto const& slot: _stack) - result += stackSlotToString(slot) + ' '; - result += ']'; - return result; -} static std::string variableSlotToString(VariableSlot const& _slot) { return _slot.variable.get().name.str(); diff --git a/test/libyul/StackLayoutGeneratorTest.cpp b/test/libyul/StackLayoutGeneratorTest.cpp new file mode 100644 index 000000000..35d4c07ee --- /dev/null +++ b/test/libyul/StackLayoutGeneratorTest.cpp @@ -0,0 +1,267 @@ +/* + 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 + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#ifdef ISOLTEST +#include +#endif + +using namespace solidity; +using namespace solidity::util; +using namespace solidity::langutil; +using namespace solidity::yul; +using namespace solidity::yul::test; +using namespace solidity::frontend; +using namespace solidity::frontend::test; +using namespace std; + +StackLayoutGeneratorTest::StackLayoutGeneratorTest(string const& _filename): + TestCase(_filename) +{ + m_source = m_reader.source(); + auto dialectName = m_reader.stringSetting("dialect", "evm"); + m_dialect = &dialect(dialectName, solidity::test::CommonOptions::get().evmVersion()); + m_expectation = m_reader.simpleExpectations(); +} + +namespace +{ +static std::string variableSlotToString(VariableSlot const& _slot) +{ + return _slot.variable.get().name.str(); +} +} + +class StackLayoutPrinter +{ +public: + StackLayoutPrinter(std::ostream& _stream, StackLayout const& _stackLayout): + m_stream(_stream), m_stackLayout(_stackLayout) + { + } + void operator()(CFG::BasicBlock const& _block, bool _isMainEntry = true) + { + if (_isMainEntry) + { + m_stream << "Entry [label=\"Entry\"];\n"; + m_stream << "Entry -> Block" << getBlockId(_block) << ";\n"; + } + while (!m_blocksToPrint.empty()) + { + CFG::BasicBlock const* block = *m_blocksToPrint.begin(); + m_blocksToPrint.erase(m_blocksToPrint.begin()); + printBlock(*block); + } + + } + void operator()( + CFG::FunctionInfo const& _info + ) + { + m_stream << "FunctionEntry_" << _info.function.name.str() << " [label=\""; + m_stream << "function " << _info.function.name.str() << "("; + m_stream << joinHumanReadable(_info.parameters | ranges::views::transform(variableSlotToString)); + m_stream << ")"; + if (!_info.returnVariables.empty()) + { + m_stream << " -> "; + m_stream << joinHumanReadable(_info.returnVariables | ranges::views::transform(variableSlotToString)); + } + m_stream << "\\l\\\n"; + Stack functionEntryStack = {FunctionReturnLabelSlot{_info.function}}; + functionEntryStack += _info.parameters | ranges::views::reverse; + m_stream << stackToString(functionEntryStack) << "\"];\n"; + m_stream << "FunctionEntry_" << _info.function.name.str() << " -> Block" << getBlockId(*_info.entry) << ";\n"; + (*this)(*_info.entry, false); + } + +private: + void printBlock(CFG::BasicBlock const& _block) + { + m_stream << "Block" << getBlockId(_block) << " [label=\"\\\n"; + + // Verify that the entries of this block exit into this block. + for (auto const& entry: _block.entries) + std::visit(util::GenericVisitor{ + [&](CFG::BasicBlock::Jump const& _jump) + { + soltestAssert(_jump.target == &_block, "Invalid control flow graph."); + }, + [&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) + { + soltestAssert( + _conditionalJump.zero == &_block || _conditionalJump.nonZero == &_block, + "Invalid control flow graph." + ); + }, + [&](auto const&) + { + soltestAssert(false, "Invalid control flow graph."); + } + }, entry->exit); + + auto const& blockInfo = m_stackLayout.blockInfos.at(&_block); + m_stream << stackToString(blockInfo.entryLayout) << "\\l\\\n"; + for (auto const& operation: _block.operations) + { + auto entryLayout = m_stackLayout.operationEntryLayout.at(&operation); + m_stream << stackToString(m_stackLayout.operationEntryLayout.at(&operation)) << "\\l\\\n"; + std::visit(util::GenericVisitor{ + [&](CFG::FunctionCall const& _call) { + m_stream << _call.function.get().name.str(); + }, + [&](CFG::BuiltinCall const& _call) { + m_stream << _call.functionCall.get().functionName.name.str(); + + }, + [&](CFG::Assignment const& _assignment) { + m_stream << "Assignment("; + m_stream << joinHumanReadable(_assignment.variables | ranges::views::transform(variableSlotToString)); + m_stream << ")"; + } + }, operation.operation); + m_stream << "\\l\\\n"; + soltestAssert(operation.input.size() <= entryLayout.size(), "Invalid Stack Layout."); + for (size_t i = 0; i < operation.input.size(); ++i) + entryLayout.pop_back(); + entryLayout += operation.output; + m_stream << stackToString(entryLayout) << "\\l\\\n"; + } + m_stream << stackToString(blockInfo.exitLayout) << "\\l\\\n"; + m_stream << "\"];\n"; + std::visit(util::GenericVisitor{ + [&](CFG::BasicBlock::MainExit const&) + { + m_stream << "Block" << getBlockId(_block) << "Exit [label=\"MainExit\"];\n"; + m_stream << "Block" << getBlockId(_block) << " -> Block" << getBlockId(_block) << "Exit;\n"; + }, + [&](CFG::BasicBlock::Jump const& _jump) + { + m_stream << "Block" << getBlockId(_block) << " -> Block" << getBlockId(_block) << "Exit [arrowhead=none];\n"; + m_stream << "Block" << getBlockId(_block) << "Exit [label=\""; + if (_jump.backwards) + m_stream << "Backwards"; + m_stream << "Jump\" shape=oval];\n"; + m_stream << "Block" << getBlockId(_block) << "Exit -> Block" << getBlockId(*_jump.target) << ";\n"; + }, + [&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) + { + m_stream << "Block" << getBlockId(_block) << " -> Block" << getBlockId(_block) << "Exit;\n"; + m_stream << "Block" << getBlockId(_block) << "Exit [label=\"{ "; + m_stream << stackSlotToString(_conditionalJump.condition); + m_stream << "| { <0> Zero | <1> NonZero }}\" shape=Mrecord];\n"; + m_stream << "Block" << getBlockId(_block); + m_stream << "Exit:0 -> Block" << getBlockId(*_conditionalJump.zero) << ";\n"; + m_stream << "Block" << getBlockId(_block); + m_stream << "Exit:1 -> Block" << getBlockId(*_conditionalJump.nonZero) << ";\n"; + }, + [&](CFG::BasicBlock::FunctionReturn const& _return) + { + m_stream << "Block" << getBlockId(_block) << "Exit [label=\"FunctionReturn[" << _return.info->function.name.str() << "]\"];\n"; + m_stream << "Block" << getBlockId(_block) << " -> Block" << getBlockId(_block) << "Exit;\n"; + }, + [&](CFG::BasicBlock::Terminated const&) + { + m_stream << "Block" << getBlockId(_block) << "Exit [label=\"Terminated\"];\n"; + m_stream << "Block" << getBlockId(_block) << " -> Block" << getBlockId(_block) << "Exit;\n"; + } + }, _block.exit); + m_stream << "\n"; + } + size_t getBlockId(CFG::BasicBlock const& _block) + { + if (size_t* id = util::valueOrNullptr(m_blockIds, &_block)) + return *id; + size_t id = m_blockIds[&_block] = m_blockCount++; + m_blocksToPrint.emplace_back(&_block); + return id; + } + std::ostream& m_stream; + StackLayout const& m_stackLayout; + std::map m_blockIds; + size_t m_blockCount = 0; + std::list m_blocksToPrint; +}; + +TestCase::TestResult StackLayoutGeneratorTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) +{ + ErrorList errors; + auto [object, analysisInfo] = parse(m_source, *m_dialect, errors); + if (!object || !analysisInfo || !Error::containsOnlyWarnings(errors)) + { + AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl; + return TestResult::FatalError; + } + + std::ostringstream output; + + std::unique_ptr cfg = ControlFlowGraphBuilder::build(*analysisInfo, *m_dialect, *object->code); + StackLayout stackLayout = StackLayoutGenerator::run(*cfg); + + output << "digraph CFG {\nnodesep=0.7;\nnode[shape=box];\n\n"; + StackLayoutPrinter printer{output, stackLayout}; + printer(*cfg->entry); + for (auto function: cfg->functions) + printer(cfg->functionInfo.at(function)); + output << "}\n"; + + m_obtainedResult = output.str(); + + auto result = checkResult(_stream, _linePrefix, _formatted); + +#ifdef ISOLTEST + char* graphDisplayer = nullptr; + if (result == TestResult::Failure) + graphDisplayer = getenv("ISOLTEST_DISPLAY_GRAPHS_FAILURE"); + else if (result == TestResult::Success) + graphDisplayer = getenv("ISOLTEST_DISPLAY_GRAPHS_SUCCESS"); + + if (graphDisplayer) + { + if (result == TestResult::Success) + std::cout << std::endl << m_source << std::endl; + boost::process::opstream pipe; + boost::process::child child(graphDisplayer, boost::process::std_in < pipe); + + pipe << output.str(); + pipe.flush(); + pipe.pipe().close(); + if (result == TestResult::Success) + child.wait(); + else + child.detach(); + } +#endif + + return result; +} diff --git a/test/libyul/StackLayoutGeneratorTest.h b/test/libyul/StackLayoutGeneratorTest.h new file mode 100644 index 000000000..9f570045f --- /dev/null +++ b/test/libyul/StackLayoutGeneratorTest.h @@ -0,0 +1,43 @@ +/* + 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 + +#pragma once + +#include + +namespace solidity::yul +{ +struct Dialect; + +namespace test +{ + +class StackLayoutGeneratorTest: public solidity::frontend::test::TestCase +{ +public: + static std::unique_ptr create(Config const& _config) + { + return std::make_unique(_config.filename); + } + explicit StackLayoutGeneratorTest(std::string const& _filename); + TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; +private: + Dialect const* m_dialect = nullptr; +}; +} +} diff --git a/test/libyul/yulStackLayout/complex.yul b/test/libyul/yulStackLayout/complex.yul new file mode 100644 index 000000000..e521e6faa --- /dev/null +++ b/test/libyul/yulStackLayout/complex.yul @@ -0,0 +1,318 @@ +{ + function f(a, b) -> c { + for { let x := 42 } lt(x, a) { + x := add(x, 1) + if calldataload(x) + { + sstore(0, x) + c := 0x21 + leave + sstore(0x01, 0x0101) + } + sstore(0xFF, 0xFFFF) + } + { + switch mload(x) + case 0 { + sstore(a, b) + break + sstore(a, b) + } + case 1 { + sstore(0x04, x) + leave + sstore(a, 0x0505) + } + case 2 { + sstore(x, 0x06) + c := 42 + revert(0, 0) + sstore(0x07, 0x0707) + } + case 3 { + sstore(0x08, 0x0808) + } + default { + if mload(b) { + return(0, 0) + sstore(0x09, 0x0909) + } + sstore(0x0A, 0x0A0A) + } + sstore(0x0B, 0x0B0B) + } + sstore(0x0C, 0x0C0C) + if sload(0x0D) { + c := 0x424242 + } + } + pop(f(1,2)) +} +// ---- +// digraph CFG { +// nodesep=0.7; +// node[shape=box]; +// +// Entry [label="Entry"]; +// Entry -> Block0; +// Block0 [label="\ +// [ ]\l\ +// [ RET[f] 0x02 0x01 ]\l\ +// f\l\ +// [ TMP[f, 0] ]\l\ +// [ TMP[f, 0] ]\l\ +// pop\l\ +// [ ]\l\ +// [ ]\l\ +// "]; +// Block0Exit [label="MainExit"]; +// Block0 -> Block0Exit; +// +// FunctionEntry_f [label="function f(a, b) -> c\l\ +// [ RET b a ]"]; +// FunctionEntry_f -> Block1; +// Block1 [label="\ +// [ c RET a b ]\l\ +// [ c RET a b 0x2a ]\l\ +// Assignment(x)\l\ +// [ c RET a b x ]\l\ +// [ c RET a b x ]\l\ +// "]; +// Block1 -> Block1Exit [arrowhead=none]; +// Block1Exit [label="Jump" shape=oval]; +// Block1Exit -> Block2; +// +// Block2 [label="\ +// [ c RET a b x ]\l\ +// [ c RET a b x a x ]\l\ +// lt\l\ +// [ c RET a b x TMP[lt, 0] ]\l\ +// [ c RET a b x TMP[lt, 0] ]\l\ +// "]; +// Block2 -> Block2Exit; +// Block2Exit [label="{ TMP[lt, 0]| { <0> Zero | <1> NonZero }}" shape=Mrecord]; +// Block2Exit:0 -> Block3; +// Block2Exit:1 -> Block4; +// +// Block3 [label="\ +// [ c RET JUNK JUNK JUNK ]\l\ +// [ c RET 0x0c0c 0x0c ]\l\ +// sstore\l\ +// [ c RET ]\l\ +// [ c RET 0x0d ]\l\ +// sload\l\ +// [ c RET TMP[sload, 0] ]\l\ +// [ c RET TMP[sload, 0] ]\l\ +// "]; +// Block3 -> Block3Exit; +// Block3Exit [label="{ TMP[sload, 0]| { <0> Zero | <1> NonZero }}" shape=Mrecord]; +// Block3Exit:0 -> Block5; +// Block3Exit:1 -> Block6; +// +// Block4 [label="\ +// [ c RET a b x ]\l\ +// [ c RET a b x x ]\l\ +// mload\l\ +// [ c RET a b x TMP[mload, 0] ]\l\ +// [ c RET a b x TMP[mload, 0] ]\l\ +// Assignment(GHOST[0])\l\ +// [ c RET a b x GHOST[0] ]\l\ +// [ c RET a b x GHOST[0] GHOST[0] 0x00 ]\l\ +// eq\l\ +// [ c RET a b x GHOST[0] TMP[eq, 0] ]\l\ +// [ c RET a b x GHOST[0] TMP[eq, 0] ]\l\ +// "]; +// Block4 -> Block4Exit; +// Block4Exit [label="{ TMP[eq, 0]| { <0> Zero | <1> NonZero }}" shape=Mrecord]; +// Block4Exit:0 -> Block7; +// Block4Exit:1 -> Block8; +// +// Block5 [label="\ +// [ c RET ]\l\ +// [ c RET ]\l\ +// "]; +// Block5Exit [label="FunctionReturn[f]"]; +// Block5 -> Block5Exit; +// +// Block6 [label="\ +// [ JUNK RET ]\l\ +// [ RET 0x424242 ]\l\ +// Assignment(c)\l\ +// [ RET c ]\l\ +// [ c RET ]\l\ +// "]; +// Block6 -> Block6Exit [arrowhead=none]; +// Block6Exit [label="Jump" shape=oval]; +// Block6Exit -> Block5; +// +// Block7 [label="\ +// [ c RET a b x GHOST[0] ]\l\ +// [ c RET a b x GHOST[0] GHOST[0] 0x01 ]\l\ +// eq\l\ +// [ c RET a b x GHOST[0] TMP[eq, 0] ]\l\ +// [ c RET a b x GHOST[0] TMP[eq, 0] ]\l\ +// "]; +// Block7 -> Block7Exit; +// Block7Exit [label="{ TMP[eq, 0]| { <0> Zero | <1> NonZero }}" shape=Mrecord]; +// Block7Exit:0 -> Block9; +// Block7Exit:1 -> Block10; +// +// Block8 [label="\ +// [ c RET a b JUNK JUNK ]\l\ +// [ c RET b a ]\l\ +// sstore\l\ +// [ c RET ]\l\ +// [ c RET ]\l\ +// "]; +// Block8 -> Block8Exit [arrowhead=none]; +// Block8Exit [label="Jump" shape=oval]; +// Block8Exit -> Block3; +// +// Block9 [label="\ +// [ c RET a b x GHOST[0] ]\l\ +// [ c RET a b x GHOST[0] GHOST[0] 0x02 ]\l\ +// eq\l\ +// [ c RET a b x GHOST[0] TMP[eq, 0] ]\l\ +// [ c RET a b x GHOST[0] TMP[eq, 0] ]\l\ +// "]; +// Block9 -> Block9Exit; +// Block9Exit [label="{ TMP[eq, 0]| { <0> Zero | <1> NonZero }}" shape=Mrecord]; +// Block9Exit:0 -> Block11; +// Block9Exit:1 -> Block12; +// +// Block10 [label="\ +// [ c RET JUNK JUNK x JUNK ]\l\ +// [ c RET x 0x04 ]\l\ +// sstore\l\ +// [ c RET ]\l\ +// [ c RET ]\l\ +// "]; +// Block10Exit [label="FunctionReturn[f]"]; +// Block10 -> Block10Exit; +// +// Block11 [label="\ +// [ c RET a b x GHOST[0] ]\l\ +// [ c RET a b x GHOST[0] 0x03 ]\l\ +// eq\l\ +// [ c RET a b x TMP[eq, 0] ]\l\ +// [ c RET a b x TMP[eq, 0] ]\l\ +// "]; +// Block11 -> Block11Exit; +// Block11Exit [label="{ TMP[eq, 0]| { <0> Zero | <1> NonZero }}" shape=Mrecord]; +// Block11Exit:0 -> Block13; +// Block11Exit:1 -> Block14; +// +// Block12 [label="\ +// [ JUNK JUNK JUNK JUNK x JUNK ]\l\ +// [ 0x06 x ]\l\ +// sstore\l\ +// [ ]\l\ +// [ 0x2a ]\l\ +// Assignment(c)\l\ +// [ c ]\l\ +// [ 0x00 0x00 ]\l\ +// revert\l\ +// [ ]\l\ +// [ ]\l\ +// "]; +// Block12Exit [label="Terminated"]; +// Block12 -> Block12Exit; +// +// Block13 [label="\ +// [ c RET a b x ]\l\ +// [ c RET a b x b ]\l\ +// mload\l\ +// [ c RET a b x TMP[mload, 0] ]\l\ +// [ c RET a b x TMP[mload, 0] ]\l\ +// "]; +// Block13 -> Block13Exit; +// Block13Exit [label="{ TMP[mload, 0]| { <0> Zero | <1> NonZero }}" shape=Mrecord]; +// Block13Exit:0 -> Block15; +// Block13Exit:1 -> Block16; +// +// Block14 [label="\ +// [ c RET a b x ]\l\ +// [ c RET a b 0x01 x 0x0808 0x08 ]\l\ +// sstore\l\ +// [ c RET a b 0x01 x ]\l\ +// [ c RET a b 0x01 x ]\l\ +// "]; +// Block14 -> Block14Exit [arrowhead=none]; +// Block14Exit [label="Jump" shape=oval]; +// Block14Exit -> Block17; +// +// Block15 [label="\ +// [ c RET a b x ]\l\ +// [ c RET a b 0x01 x 0x0a0a 0x0a ]\l\ +// sstore\l\ +// [ c RET a b 0x01 x ]\l\ +// [ c RET a b 0x01 x ]\l\ +// "]; +// Block15 -> Block15Exit [arrowhead=none]; +// Block15Exit [label="Jump" shape=oval]; +// Block15Exit -> Block17; +// +// Block16 [label="\ +// [ JUNK JUNK JUNK JUNK JUNK ]\l\ +// [ 0x00 0x00 ]\l\ +// return\l\ +// [ ]\l\ +// [ ]\l\ +// "]; +// Block16Exit [label="Terminated"]; +// Block16 -> Block16Exit; +// +// Block17 [label="\ +// [ c RET a b 0x01 x ]\l\ +// [ c RET a b 0x01 x 0x0b0b 0x0b ]\l\ +// sstore\l\ +// [ c RET a b 0x01 x ]\l\ +// [ c RET a b 0x01 x ]\l\ +// "]; +// Block17 -> Block17Exit [arrowhead=none]; +// Block17Exit [label="Jump" shape=oval]; +// Block17Exit -> Block18; +// +// Block18 [label="\ +// [ c RET a b 0x01 x ]\l\ +// [ c RET a b 0x01 x ]\l\ +// add\l\ +// [ c RET a b TMP[add, 0] ]\l\ +// [ c RET a b TMP[add, 0] ]\l\ +// Assignment(x)\l\ +// [ c RET a b x ]\l\ +// [ c RET x b a x ]\l\ +// calldataload\l\ +// [ c RET x b a TMP[calldataload, 0] ]\l\ +// [ c RET x b a TMP[calldataload, 0] ]\l\ +// "]; +// Block18 -> Block18Exit; +// Block18Exit [label="{ TMP[calldataload, 0]| { <0> Zero | <1> NonZero }}" shape=Mrecord]; +// Block18Exit:0 -> Block19; +// Block18Exit:1 -> Block20; +// +// Block19 [label="\ +// [ c RET x b a ]\l\ +// [ c RET x b a 0xffff 0xff ]\l\ +// sstore\l\ +// [ c RET x b a ]\l\ +// [ c RET x b a ]\l\ +// "]; +// Block19 -> Block19Exit [arrowhead=none]; +// Block19Exit [label="BackwardsJump" shape=oval]; +// Block19Exit -> Block2; +// +// Block20 [label="\ +// [ JUNK RET x JUNK JUNK ]\l\ +// [ RET x 0x00 ]\l\ +// sstore\l\ +// [ RET ]\l\ +// [ RET 0x21 ]\l\ +// Assignment(c)\l\ +// [ RET c ]\l\ +// [ c RET ]\l\ +// "]; +// Block20Exit [label="FunctionReturn[f]"]; +// Block20 -> Block20Exit; +// +// } diff --git a/test/libyul/yulStackLayout/for.yul b/test/libyul/yulStackLayout/for.yul new file mode 100644 index 000000000..fc0fbcdb7 --- /dev/null +++ b/test/libyul/yulStackLayout/for.yul @@ -0,0 +1,91 @@ +{ + let x := 0x01 + let y := 0x02 + sstore(0x01, x) + for { sstore(0x02, 0x0202) } lt(x, 0x0303) { x := add(x,0x0404) } { + sstore(0x05, 0x0505) + y := sload(x) + } + sstore(0x06, 0x0506) +} +// ---- +// digraph CFG { +// nodesep=0.7; +// node[shape=box]; +// +// Entry [label="Entry"]; +// Entry -> Block0; +// Block0 [label="\ +// [ ]\l\ +// [ 0x01 ]\l\ +// Assignment(x)\l\ +// [ x ]\l\ +// [ x 0x02 ]\l\ +// Assignment(y)\l\ +// [ x y ]\l\ +// [ x x 0x01 ]\l\ +// sstore\l\ +// [ x ]\l\ +// [ x 0x0202 0x02 ]\l\ +// sstore\l\ +// [ x ]\l\ +// [ x ]\l\ +// "]; +// Block0 -> Block0Exit [arrowhead=none]; +// Block0Exit [label="Jump" shape=oval]; +// Block0Exit -> Block1; +// +// Block1 [label="\ +// [ x ]\l\ +// [ x 0x0303 x ]\l\ +// lt\l\ +// [ x TMP[lt, 0] ]\l\ +// [ x TMP[lt, 0] ]\l\ +// "]; +// Block1 -> Block1Exit; +// Block1Exit [label="{ TMP[lt, 0]| { <0> Zero | <1> NonZero }}" shape=Mrecord]; +// Block1Exit:0 -> Block2; +// Block1Exit:1 -> Block3; +// +// Block2 [label="\ +// [ JUNK ]\l\ +// [ 0x0506 0x06 ]\l\ +// sstore\l\ +// [ ]\l\ +// [ ]\l\ +// "]; +// Block2Exit [label="MainExit"]; +// Block2 -> Block2Exit; +// +// Block3 [label="\ +// [ x ]\l\ +// [ 0x0404 x 0x0505 0x05 ]\l\ +// sstore\l\ +// [ 0x0404 x ]\l\ +// [ 0x0404 x x ]\l\ +// sload\l\ +// [ 0x0404 x TMP[sload, 0] ]\l\ +// [ 0x0404 x TMP[sload, 0] ]\l\ +// Assignment(y)\l\ +// [ 0x0404 x y ]\l\ +// [ 0x0404 x ]\l\ +// "]; +// Block3 -> Block3Exit [arrowhead=none]; +// Block3Exit [label="Jump" shape=oval]; +// Block3Exit -> Block4; +// +// Block4 [label="\ +// [ 0x0404 x ]\l\ +// [ 0x0404 x ]\l\ +// add\l\ +// [ TMP[add, 0] ]\l\ +// [ TMP[add, 0] ]\l\ +// Assignment(x)\l\ +// [ x ]\l\ +// [ x ]\l\ +// "]; +// Block4 -> Block4Exit [arrowhead=none]; +// Block4Exit [label="BackwardsJump" shape=oval]; +// Block4Exit -> Block1; +// +// } diff --git a/test/libyul/yulStackLayout/function.yul b/test/libyul/yulStackLayout/function.yul new file mode 100644 index 000000000..343555123 --- /dev/null +++ b/test/libyul/yulStackLayout/function.yul @@ -0,0 +1,117 @@ +{ + function f(a, b) -> r { + let x := add(a,b) + r := sub(x,a) + } + function g() { + sstore(0x01, 0x0101) + } + function h(x) { + h(f(x, 0)) + g() + } + function i() -> v, w { + v := 0x0202 + w := 0x0303 + } + let x, y := i() + h(x) + h(y) +} +// ---- +// digraph CFG { +// nodesep=0.7; +// node[shape=box]; +// +// Entry [label="Entry"]; +// Entry -> Block0; +// Block0 [label="\ +// [ ]\l\ +// [ RET[h] RET[h] RET[i] ]\l\ +// i\l\ +// [ RET[h] RET[h] TMP[i, 0] TMP[i, 1] ]\l\ +// [ RET[h] RET[h] TMP[i, 0] TMP[i, 1] ]\l\ +// Assignment(x, y)\l\ +// [ RET[h] RET[h] x y ]\l\ +// [ RET[h] y RET[h] x ]\l\ +// h\l\ +// [ RET[h] y ]\l\ +// [ RET[h] y ]\l\ +// h\l\ +// [ ]\l\ +// [ ]\l\ +// "]; +// Block0Exit [label="MainExit"]; +// Block0 -> Block0Exit; +// +// FunctionEntry_f [label="function f(a, b) -> r\l\ +// [ RET b a ]"]; +// FunctionEntry_f -> Block1; +// Block1 [label="\ +// [ RET a b ]\l\ +// [ RET a b a ]\l\ +// add\l\ +// [ RET a TMP[add, 0] ]\l\ +// [ RET a TMP[add, 0] ]\l\ +// Assignment(x)\l\ +// [ RET a x ]\l\ +// [ RET a x ]\l\ +// sub\l\ +// [ RET TMP[sub, 0] ]\l\ +// [ RET TMP[sub, 0] ]\l\ +// Assignment(r)\l\ +// [ RET r ]\l\ +// [ r RET ]\l\ +// "]; +// Block1Exit [label="FunctionReturn[f]"]; +// Block1 -> Block1Exit; +// +// FunctionEntry_g [label="function g()\l\ +// [ RET ]"]; +// FunctionEntry_g -> Block2; +// Block2 [label="\ +// [ RET ]\l\ +// [ RET 0x0101 0x01 ]\l\ +// sstore\l\ +// [ RET ]\l\ +// [ RET ]\l\ +// "]; +// Block2Exit [label="FunctionReturn[g]"]; +// Block2 -> Block2Exit; +// +// FunctionEntry_h [label="function h(x)\l\ +// [ RET x ]"]; +// FunctionEntry_h -> Block3; +// Block3 [label="\ +// [ RET RET[h] RET[f] 0x00 x ]\l\ +// [ RET RET[h] RET[f] 0x00 x ]\l\ +// f\l\ +// [ RET RET[h] TMP[f, 0] ]\l\ +// [ RET RET[h] TMP[f, 0] ]\l\ +// h\l\ +// [ RET ]\l\ +// [ RET RET[g] ]\l\ +// g\l\ +// [ RET ]\l\ +// [ RET ]\l\ +// "]; +// Block3Exit [label="FunctionReturn[h]"]; +// Block3 -> Block3Exit; +// +// FunctionEntry_i [label="function i() -> v, w\l\ +// [ RET ]"]; +// FunctionEntry_i -> Block4; +// Block4 [label="\ +// [ RET ]\l\ +// [ RET 0x0202 ]\l\ +// Assignment(v)\l\ +// [ RET v ]\l\ +// [ v RET 0x0303 ]\l\ +// Assignment(w)\l\ +// [ v RET w ]\l\ +// [ v w RET ]\l\ +// "]; +// Block4Exit [label="FunctionReturn[i]"]; +// Block4 -> Block4Exit; +// +// } diff --git a/test/libyul/yulStackLayout/if.yul b/test/libyul/yulStackLayout/if.yul new file mode 100644 index 000000000..a019788b3 --- /dev/null +++ b/test/libyul/yulStackLayout/if.yul @@ -0,0 +1,51 @@ +{ + sstore(0x01, 0x0101) + if calldataload(0) { + sstore(0x02, 0x0202) + } + sstore(0x03, 0x003) +} +// ---- +// digraph CFG { +// nodesep=0.7; +// node[shape=box]; +// +// Entry [label="Entry"]; +// Entry -> Block0; +// Block0 [label="\ +// [ ]\l\ +// [ 0x0101 0x01 ]\l\ +// sstore\l\ +// [ ]\l\ +// [ 0x00 ]\l\ +// calldataload\l\ +// [ TMP[calldataload, 0] ]\l\ +// [ TMP[calldataload, 0] ]\l\ +// "]; +// Block0 -> Block0Exit; +// Block0Exit [label="{ TMP[calldataload, 0]| { <0> Zero | <1> NonZero }}" shape=Mrecord]; +// Block0Exit:0 -> Block1; +// Block0Exit:1 -> Block2; +// +// Block1 [label="\ +// [ ]\l\ +// [ 0x03 0x03 ]\l\ +// sstore\l\ +// [ ]\l\ +// [ ]\l\ +// "]; +// Block1Exit [label="MainExit"]; +// Block1 -> Block1Exit; +// +// Block2 [label="\ +// [ ]\l\ +// [ 0x0202 0x02 ]\l\ +// sstore\l\ +// [ ]\l\ +// [ ]\l\ +// "]; +// Block2 -> Block2Exit [arrowhead=none]; +// Block2Exit [label="Jump" shape=oval]; +// Block2Exit -> Block1; +// +// } diff --git a/test/libyul/yulStackLayout/stub.yul b/test/libyul/yulStackLayout/stub.yul new file mode 100644 index 000000000..5a16304aa --- /dev/null +++ b/test/libyul/yulStackLayout/stub.yul @@ -0,0 +1,17 @@ +{ +} +// ---- +// digraph CFG { +// nodesep=0.7; +// node[shape=box]; +// +// Entry [label="Entry"]; +// Entry -> Block0; +// Block0 [label="\ +// [ ]\l\ +// [ ]\l\ +// "]; +// Block0Exit [label="MainExit"]; +// Block0 -> Block0Exit; +// +// } diff --git a/test/libyul/yulStackLayout/switch.yul b/test/libyul/yulStackLayout/switch.yul new file mode 100644 index 000000000..5f655731b --- /dev/null +++ b/test/libyul/yulStackLayout/switch.yul @@ -0,0 +1,107 @@ +{ + let x := 0x0101 + let y := 0x0202 + let z := 0x0303 + switch sload(x) + case 0 { + x := 0x42 + } + case 1 { + y := 0x42 + } + default { + sstore(z, z) + } + + sstore(0x0404, y) +} +// ---- +// digraph CFG { +// nodesep=0.7; +// node[shape=box]; +// +// Entry [label="Entry"]; +// Entry -> Block0; +// Block0 [label="\ +// [ ]\l\ +// [ 0x0101 ]\l\ +// Assignment(x)\l\ +// [ x ]\l\ +// [ x 0x0202 ]\l\ +// Assignment(y)\l\ +// [ x y ]\l\ +// [ y x 0x0303 ]\l\ +// Assignment(z)\l\ +// [ y x z ]\l\ +// [ y z x ]\l\ +// sload\l\ +// [ y z TMP[sload, 0] ]\l\ +// [ y z TMP[sload, 0] ]\l\ +// Assignment(GHOST[0])\l\ +// [ y z GHOST[0] ]\l\ +// [ y z GHOST[0] GHOST[0] 0x00 ]\l\ +// eq\l\ +// [ y z GHOST[0] TMP[eq, 0] ]\l\ +// [ y z GHOST[0] TMP[eq, 0] ]\l\ +// "]; +// Block0 -> Block0Exit; +// Block0Exit [label="{ TMP[eq, 0]| { <0> Zero | <1> NonZero }}" shape=Mrecord]; +// Block0Exit:0 -> Block1; +// Block0Exit:1 -> Block2; +// +// Block1 [label="\ +// [ y z GHOST[0] ]\l\ +// [ y z GHOST[0] 0x01 ]\l\ +// eq\l\ +// [ y z TMP[eq, 0] ]\l\ +// [ y z TMP[eq, 0] ]\l\ +// "]; +// Block1 -> Block1Exit; +// Block1Exit [label="{ TMP[eq, 0]| { <0> Zero | <1> NonZero }}" shape=Mrecord]; +// Block1Exit:0 -> Block3; +// Block1Exit:1 -> Block4; +// +// Block2 [label="\ +// [ y JUNK JUNK ]\l\ +// [ y 0x42 ]\l\ +// Assignment(x)\l\ +// [ y x ]\l\ +// [ y ]\l\ +// "]; +// Block2 -> Block2Exit [arrowhead=none]; +// Block2Exit [label="Jump" shape=oval]; +// Block2Exit -> Block5; +// +// Block3 [label="\ +// [ y z ]\l\ +// [ y z z ]\l\ +// sstore\l\ +// [ y ]\l\ +// [ y ]\l\ +// "]; +// Block3 -> Block3Exit [arrowhead=none]; +// Block3Exit [label="Jump" shape=oval]; +// Block3Exit -> Block5; +// +// Block4 [label="\ +// [ JUNK JUNK ]\l\ +// [ 0x42 ]\l\ +// Assignment(y)\l\ +// [ y ]\l\ +// [ y ]\l\ +// "]; +// Block4 -> Block4Exit [arrowhead=none]; +// Block4Exit [label="Jump" shape=oval]; +// Block4Exit -> Block5; +// +// Block5 [label="\ +// [ y ]\l\ +// [ y 0x0404 ]\l\ +// sstore\l\ +// [ ]\l\ +// [ ]\l\ +// "]; +// Block5Exit [label="MainExit"]; +// Block5 -> Block5Exit; +// +// } diff --git a/test/libyul/yulStackLayout/variables.yul b/test/libyul/yulStackLayout/variables.yul new file mode 100644 index 000000000..3e66d5686 --- /dev/null +++ b/test/libyul/yulStackLayout/variables.yul @@ -0,0 +1,51 @@ +{ + let x := calldataload(0) + let y := calldataload(2) + + x := calldataload(3) + y := calldataload(4) + + sstore(x,y) +} +// ---- +// digraph CFG { +// nodesep=0.7; +// node[shape=box]; +// +// Entry [label="Entry"]; +// Entry -> Block0; +// Block0 [label="\ +// [ ]\l\ +// [ 0x00 ]\l\ +// calldataload\l\ +// [ TMP[calldataload, 0] ]\l\ +// [ TMP[calldataload, 0] ]\l\ +// Assignment(x)\l\ +// [ x ]\l\ +// [ 0x02 ]\l\ +// calldataload\l\ +// [ TMP[calldataload, 0] ]\l\ +// [ TMP[calldataload, 0] ]\l\ +// Assignment(y)\l\ +// [ y ]\l\ +// [ 0x03 ]\l\ +// calldataload\l\ +// [ TMP[calldataload, 0] ]\l\ +// [ TMP[calldataload, 0] ]\l\ +// Assignment(x)\l\ +// [ x ]\l\ +// [ x 0x04 ]\l\ +// calldataload\l\ +// [ x TMP[calldataload, 0] ]\l\ +// [ x TMP[calldataload, 0] ]\l\ +// Assignment(y)\l\ +// [ x y ]\l\ +// [ y x ]\l\ +// sstore\l\ +// [ ]\l\ +// [ ]\l\ +// "]; +// Block0Exit [label="MainExit"]; +// Block0 -> Block0Exit; +// +// } diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 1f62b57fc..18b04afe8 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -38,6 +38,7 @@ add_executable(isoltest ../libyul/FunctionSideEffects.cpp ../libyul/ObjectCompilerTest.cpp ../libyul/SyntaxTest.cpp + ../libyul/StackLayoutGeneratorTest.cpp ../libyul/YulOptimizerTest.cpp ../libyul/YulOptimizerTestCommon.cpp ../libyul/YulInterpreterTest.cpp From 646421fee1b9b70fac47865fa67f1ea2a7c973c4 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Fri, 3 Sep 2021 15:29:51 +0200 Subject: [PATCH 016/232] Allow the Rematerializer to be restricted to an exact set of variables. --- libyul/optimiser/Rematerialiser.cpp | 32 ++++++++++++++++++----------- libyul/optimiser/Rematerialiser.h | 13 ++++++++---- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/libyul/optimiser/Rematerialiser.cpp b/libyul/optimiser/Rematerialiser.cpp index e5fec6b62..f1597a7f2 100644 --- a/libyul/optimiser/Rematerialiser.cpp +++ b/libyul/optimiser/Rematerialiser.cpp @@ -32,39 +32,44 @@ using namespace std; using namespace solidity; using namespace solidity::yul; -void Rematerialiser::run(Dialect const& _dialect, Block& _ast, set _varsToAlwaysRematerialize) +void Rematerialiser::run(Dialect const& _dialect, Block& _ast, set _varsToAlwaysRematerialize, bool _onlySelectedVariables) { - Rematerialiser{_dialect, _ast, std::move(_varsToAlwaysRematerialize)}(_ast); + Rematerialiser{_dialect, _ast, std::move(_varsToAlwaysRematerialize), _onlySelectedVariables}(_ast); } void Rematerialiser::run( Dialect const& _dialect, FunctionDefinition& _function, - set _varsToAlwaysRematerialize + set _varsToAlwaysRematerialize, + bool _onlySelectedVariables ) { - Rematerialiser{_dialect, _function, std::move(_varsToAlwaysRematerialize)}(_function); + Rematerialiser{_dialect, _function, std::move(_varsToAlwaysRematerialize), _onlySelectedVariables}(_function); } Rematerialiser::Rematerialiser( Dialect const& _dialect, Block& _ast, - set _varsToAlwaysRematerialize + set _varsToAlwaysRematerialize, + bool _onlySelectedVariables ): DataFlowAnalyzer(_dialect), m_referenceCounts(ReferencesCounter::countReferences(_ast)), - m_varsToAlwaysRematerialize(std::move(_varsToAlwaysRematerialize)) + m_varsToAlwaysRematerialize(std::move(_varsToAlwaysRematerialize)), + m_onlySelectedVariables(_onlySelectedVariables) { } Rematerialiser::Rematerialiser( Dialect const& _dialect, FunctionDefinition& _function, - set _varsToAlwaysRematerialize + set _varsToAlwaysRematerialize, + bool _onlySelectedVariables ): DataFlowAnalyzer(_dialect), m_referenceCounts(ReferencesCounter::countReferences(_function)), - m_varsToAlwaysRematerialize(std::move(_varsToAlwaysRematerialize)) + m_varsToAlwaysRematerialize(std::move(_varsToAlwaysRematerialize)), + m_onlySelectedVariables(_onlySelectedVariables) { } @@ -81,10 +86,13 @@ void Rematerialiser::visit(Expression& _e) size_t refs = m_referenceCounts[name]; size_t cost = CodeCost::codeCost(m_dialect, *value.value); if ( - (refs <= 1 && value.loopDepth == m_loopDepth) || - cost == 0 || - (refs <= 5 && cost <= 1 && m_loopDepth == 0) || - m_varsToAlwaysRematerialize.count(name) + ( + !m_onlySelectedVariables && ( + (refs <= 1 && value.loopDepth == m_loopDepth) || + cost == 0 || + (refs <= 5 && cost <= 1 && m_loopDepth == 0) + ) + ) || m_varsToAlwaysRematerialize.count(name) ) { assertThrow(m_referenceCounts[name] > 0, OptimizerException, ""); diff --git a/libyul/optimiser/Rematerialiser.h b/libyul/optimiser/Rematerialiser.h index b7e98a6b8..d1ebb1595 100644 --- a/libyul/optimiser/Rematerialiser.h +++ b/libyul/optimiser/Rematerialiser.h @@ -50,24 +50,28 @@ public: static void run( Dialect const& _dialect, Block& _ast, - std::set _varsToAlwaysRematerialize = {} + std::set _varsToAlwaysRematerialize = {}, + bool _onlySelectedVariables = false ); static void run( Dialect const& _dialect, FunctionDefinition& _function, - std::set _varsToAlwaysRematerialize = {} + std::set _varsToAlwaysRematerialize = {}, + bool _onlySelectedVariables = false ); protected: Rematerialiser( Dialect const& _dialect, Block& _ast, - std::set _varsToAlwaysRematerialize = {} + std::set _varsToAlwaysRematerialize = {}, + bool _onlySelectedVariables = false ); Rematerialiser( Dialect const& _dialect, FunctionDefinition& _function, - std::set _varsToAlwaysRematerialize = {} + std::set _varsToAlwaysRematerialize = {}, + bool _onlySelectedVariables = false ); using DataFlowAnalyzer::operator(); @@ -77,6 +81,7 @@ protected: std::map m_referenceCounts; std::set m_varsToAlwaysRematerialize; + bool m_onlySelectedVariables = false; }; /** From 5a023842336584ca6c4f00533ccbfd7e534650ea Mon Sep 17 00:00:00 2001 From: yatharthagoenka Date: Tue, 31 Aug 2021 18:33:58 +0530 Subject: [PATCH 017/232] Cleanup/Deduplication in .circleci/config --- .circleci/config.yml | 146 +++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 81 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8a0e11d9a..4a9745481 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -53,6 +53,25 @@ defaults: name: Correctness proofs for optimization rules command: scripts/run_proofs.sh + - run_soltest: &run_soltest + name: soltest + no_output_timeout: 30m + command: ./.circleci/soltest.sh + + - run_soltest_all: &run_soltest_all + name: soltest_all + no_output_timeout: 30m + command: ./.circleci/soltest_all.sh + + - run_cmdline_tests: &run_cmdline_tests + name: command line tests + no_output_timeout: 30m + command: ./test/cmdlineTests.sh + + - run_docs_pragma_min_version: &run_docs_pragma_min_version + name: docs pragma version check + command: ./scripts/docs_version_pragma_check.sh + # -------------------------------------------------------------------------- # Artifacts Templates @@ -114,17 +133,7 @@ defaults: - store_test_results: &store_test_results path: test_results/ - - run_soltest: &run_soltest - name: soltest - no_output_timeout: 30m - command: ./.circleci/soltest.sh - - - run_soltest_all: &run_soltest_all - name: soltest_all - no_output_timeout: 30m - command: ./.circleci/soltest_all.sh - - - run_soltest_steps: &run_soltest_steps + - steps_soltest: &steps_soltest steps: - checkout - attach_workspace: @@ -133,7 +142,7 @@ defaults: - store_test_results: *store_test_results - store_artifacts: *artifacts_test_results - - run_soltest_all_steps: &run_soltest_all_steps + - steps_soltest_all: &steps_soltest_all steps: - checkout - attach_workspace: @@ -142,12 +151,7 @@ defaults: - store_test_results: *store_test_results - store_artifacts: *artifacts_test_results - - run_cmdline_tests: &run_cmdline_tests - name: command line tests - no_output_timeout: 30m - command: ./test/cmdlineTests.sh - - - run_cmdline_tests_steps: &run_cmdline_tests_steps + - steps_cmdline_tests: &steps_cmdline_tests steps: - checkout - attach_workspace: @@ -156,34 +160,30 @@ defaults: - store_test_results: *store_test_results - store_artifacts: *artifacts_test_results - - run_docs_pragma_min_version: &run_docs_pragma_min_version - name: docs pragma version check - command: ./scripts/docs_version_pragma_check.sh - - test_ubuntu1604_clang: &test_ubuntu1604_clang docker: - image: << pipeline.parameters.ubuntu-1604-clang-ossfuzz-docker-image >> - <<: *run_soltest_steps + <<: *steps_soltest - test_ubuntu2004_clang: &test_ubuntu2004_clang docker: - image: << pipeline.parameters.ubuntu-2004-clang-docker-image >> - <<: *run_soltest_steps + <<: *steps_soltest - test_ubuntu2004: &test_ubuntu2004 docker: - image: << pipeline.parameters.ubuntu-2004-docker-image >> parallelism: 6 - <<: *run_soltest_all_steps + <<: *steps_soltest_all - test_asan: &test_asan <<: *test_ubuntu2004 - <<: *run_soltest_steps + <<: *steps_soltest - test_ubuntu2004_clang_cli: &test_ubuntu2004_clang_cli docker: - image: << pipeline.parameters.ubuntu-2004-clang-docker-image >> - <<: *run_cmdline_tests_steps + <<: *steps_cmdline_tests # -------------------------------------------------------------------------- # Workflow Templates @@ -437,6 +437,32 @@ jobs: name: Python unit tests command: python.exe test/pyscriptTests.py + b_ubu: &b_ubu + resource_class: xlarge + docker: + - image: << pipeline.parameters.ubuntu-2004-docker-image >> + environment: + MAKEFLAGS: -j 10 + steps: + - checkout + - run: *run_build + - store_artifacts: *artifacts_solc + - store_artifacts: *artifacts_tools + - persist_to_workspace: *artifacts_executables + + # x64 ASAN build, for testing for memory related bugs + b_ubu_asan: &b_ubu_asan + <<: *b_ubu + environment: + CMAKE_OPTIONS: -DSANITIZE=address + MAKEFLAGS: -j 10 + CMAKE_BUILD_TYPE: Release + steps: + - checkout + - run: *run_build + - store_artifacts: *artifacts_solc + - persist_to_workspace: *artifacts_executables + b_ubu_clang: &b_ubu_clang resource_class: xlarge docker: @@ -480,19 +506,6 @@ jobs: - store_artifacts: *artifacts_solc - persist_to_workspace: *artifacts_executables - b_ubu: &b_ubu - resource_class: xlarge - docker: - - image: << pipeline.parameters.ubuntu-2004-docker-image >> - environment: - MAKEFLAGS: -j 10 - steps: - - checkout - - run: *run_build - - store_artifacts: *artifacts_solc - - store_artifacts: *artifacts_tools - - persist_to_workspace: *artifacts_executables - b_ubu_release: &b_ubu_release <<: *b_ubu environment: @@ -697,19 +710,6 @@ jobs: - soljson.js - version.txt - # x64 ASAN build, for testing for memory related bugs - b_ubu_asan: &b_ubu_asan - <<: *b_ubu - environment: - CMAKE_OPTIONS: -DSANITIZE=address - MAKEFLAGS: -j 10 - CMAKE_BUILD_TYPE: Release - steps: - - checkout - - run: *run_build - - store_artifacts: *artifacts_solc - - persist_to_workspace: *artifacts_executables - b_docs: docker: - image: << pipeline.parameters.ubuntu-2004-docker-image >> @@ -741,12 +741,9 @@ jobs: name: Install runtime dependencies command: | pacman --noconfirm -Syu --noprogressbar --needed base-devel boost cmake z3 cvc4 git openssh tar - - checkout - - attach_workspace: - at: build - - run: *run_soltest - - store_test_results: *store_test_results - - store_artifacts: *artifacts_test_results + - when: + condition: true + <<: *steps_soltest t_ubu_soltest_enforce_yul: &t_ubu_soltest_enforce_yul docker: @@ -756,13 +753,7 @@ jobs: SOLTEST_FLAGS: --enforce-via-yul OPTIMIZE: 0 TERM: xterm - steps: - - checkout - - attach_workspace: - at: build - - run: *run_soltest - - store_test_results: *store_test_results - - store_artifacts: *artifacts_test_results + <<: *steps_soltest t_ubu_clang_soltest: &t_ubu_clang_soltest @@ -779,7 +770,7 @@ jobs: - image: << pipeline.parameters.ubuntu-2004-docker-image >> environment: TERM: xterm - <<: *run_cmdline_tests_steps + <<: *steps_cmdline_tests t_ubu_release_cli: &t_ubu_release_cli <<: *t_ubu_cli @@ -789,7 +780,7 @@ jobs: environment: TERM: xterm ASAN_OPTIONS: check_initialization_order=true:detect_stack_use_after_return=true:strict_init_order=true:strict_string_checks=true:detect_invalid_pointer_pairs=2 - <<: *run_cmdline_tests_steps + <<: *steps_cmdline_tests t_ubu_asan: <<: *test_asan @@ -813,25 +804,19 @@ jobs: docker: - image: << pipeline.parameters.ubuntu-2004-clang-docker-image >> steps: - - checkout - - attach_workspace: - at: build - - run: *run_soltest + - when: + condition: true + <<: *steps_soltest - run: *gitter_notify_failure - - store_test_results: *store_test_results - - store_artifacts: *artifacts_test_results t_ubu_ubsan_clang_cli: docker: - image: << pipeline.parameters.ubuntu-2004-clang-docker-image >> steps: - - checkout - - attach_workspace: - at: build - - run: *run_cmdline_tests + - when: + condition: true + <<: *steps_cmdline_tests - run: *gitter_notify_failure - - store_test_results: *store_test_results - - store_artifacts: *artifacts_test_results t_ems_solcjs: docker: @@ -1214,7 +1199,6 @@ workflows: branches: only: - develop - - develop_060 jobs: # OSSFUZZ builds and (regression) tests From 8d1331a081bdb882ddb2ed3344acb5cf491e350e Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Sat, 4 Sep 2021 22:38:23 +0300 Subject: [PATCH 018/232] docs: delete stale note about reading code --- docs/assembly.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/assembly.rst b/docs/assembly.rst index 9da8ebb8b..7edffca81 100644 --- a/docs/assembly.rst +++ b/docs/assembly.rst @@ -35,9 +35,9 @@ Example ------- The following example provides library code to access the code of another contract and -load it into a ``bytes`` variable. This is not possible with "plain Solidity" and the -idea is that reusable assembly libraries can enhance the Solidity language -without a compiler change. +load it into a ``bytes`` variable. This is possible with "plain Solidity" too, by using +``
.code``. But the point here is that reusable assembly libraries can enhance the +Solidity language without a compiler change. .. code-block:: solidity From e022ba1bfbed177767e6decedbec02f24d000398 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Fri, 3 Sep 2021 15:05:14 +0200 Subject: [PATCH 019/232] Report stack too deep and conditionally aggressively compress stack in StackLayoutGenerator. --- libyul/backends/evm/StackHelpers.h | 5 + libyul/backends/evm/StackLayoutGenerator.cpp | 155 +++++++++++++++++-- libyul/backends/evm/StackLayoutGenerator.h | 24 ++- 3 files changed, 168 insertions(+), 16 deletions(-) diff --git a/libyul/backends/evm/StackHelpers.h b/libyul/backends/evm/StackHelpers.h index 80e7d3834..302c6c029 100644 --- a/libyul/backends/evm/StackHelpers.h +++ b/libyul/backends/evm/StackHelpers.h @@ -342,6 +342,11 @@ private: /// Transforms @a _currentStack to @a _targetStack, invoking the provided shuffling operations. /// Modifies @a _currentStack itself after each invocation of the shuffling operations. +/// @a _swap is a function with signature void(unsigned) that is called when the top most slot is swapped with +/// the slot `depth` slots below the top. In terms of EVM opcodes this is supposed to be a `SWAP`. +/// @a _pushOrDup is a function with signature void(StackSlot const&) that is called to push or dup the slot given as +/// its argument to the stack top. +/// @a _pop is a function with signature void() that is called when the top most slot is popped. template void createStackLayout(Stack& _currentStack, Stack const& _targetStack, Swap _swap, PushOrDup _pushOrDup, Pop _pop) { diff --git a/libyul/backends/evm/StackLayoutGenerator.cpp b/libyul/backends/evm/StackLayoutGenerator.cpp index 2b82c4b6c..43a1d032c 100644 --- a/libyul/backends/evm/StackLayoutGenerator.cpp +++ b/libyul/backends/evm/StackLayoutGenerator.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include #include +#include #include using namespace solidity; @@ -55,12 +57,83 @@ StackLayout StackLayoutGenerator::run(CFG const& _cfg) return stackLayout; } +map> StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg) +{ + map> stackTooDeepErrors; + stackTooDeepErrors[YulString{}] = reportStackTooDeep(_cfg, YulString{}); + for (auto const& function: _cfg.functions) + if (auto errors = reportStackTooDeep(_cfg, function->name); !errors.empty()) + stackTooDeepErrors[function->name] = move(errors); + return stackTooDeepErrors; +} + +vector StackLayoutGenerator::reportStackTooDeep(CFG const& _cfg, YulString _functionName) +{ + StackLayout stackLayout; + CFG::FunctionInfo const* functionInfo = nullptr; + if (!_functionName.empty()) + { + functionInfo = &ranges::find( + _cfg.functionInfo, + _functionName, + util::mapTuple([](auto&&, auto&& info) { return info.function.name; }) + )->second; + yulAssert(functionInfo, "Function not found."); + } + + StackLayoutGenerator generator{stackLayout}; + CFG::BasicBlock const* entry = functionInfo ? functionInfo->entry : _cfg.entry; + generator.processEntryPoint(*entry); + return generator.reportStackTooDeep(*entry); +} + StackLayoutGenerator::StackLayoutGenerator(StackLayout& _layout): m_layout(_layout) { } namespace { +/// @returns all stack too deep errors that would occur when shuffling @a _source to @a _target. +vector findStackTooDeep(Stack const& _source, Stack const& _target) +{ + Stack currentStack = _source; + vector stackTooDeepErrors; + auto getVariableChoices = [](auto&& _range) { + vector result; + for (auto const& slot: _range) + if (auto const* variableSlot = get_if(&slot)) + if (!util::contains(result, variableSlot->variable.get().name)) + result.push_back(variableSlot->variable.get().name); + return result; + }; + ::createStackLayout( + currentStack, + _target, + [&](unsigned _i) + { + if (_i > 16) + stackTooDeepErrors.emplace_back(StackLayoutGenerator::StackTooDeep{ + _i - 16, + getVariableChoices(currentStack | ranges::views::take_last(_i + 1)) + }); + }, + [&](StackSlot const& _slot) + { + if (canBeFreelyGenerated(_slot)) + return; + if ( + auto depth = util::findOffset(currentStack | ranges::views::reverse, _slot); + depth && *depth >= 16 + ) + stackTooDeepErrors.emplace_back(StackLayoutGenerator::StackTooDeep{ + *depth - 15, + getVariableChoices(currentStack | ranges::views::take_last(*depth + 1)) + }); + }, + [&]() {} + ); + return stackTooDeepErrors; +} /// @returns the ideal stack to have before executing an operation that outputs @a _operationOutput, s.t. /// shuffling to @a _post is cheap (excluding the input of the operation itself). @@ -191,13 +264,16 @@ Stack createIdealLayout(Stack const& _operationOutput, Stack const& _post, Calla } } -Stack StackLayoutGenerator::propagateStackThroughOperation(Stack _exitStack, CFG::Operation const& _operation) +Stack StackLayoutGenerator::propagateStackThroughOperation(Stack _exitStack, CFG::Operation const& _operation, bool _aggressiveStackCompression) { + // Enable aggressive stack compression for recursive calls. + if (auto const* functionCall = get_if(&_operation.operation)) + if (functionCall->recursive) + _aggressiveStackCompression = true; + // This is a huge tradeoff between code size, gas cost and stack size. - auto generateSlotOnTheFly = [&](StackSlot const&) { - //return stack.size() > 12 && canBeFreelyGenerated(_slot); - // return canBeFreelyGenerated(_slot); - return false; + auto generateSlotOnTheFly = [&](StackSlot const& _slot) { + return _aggressiveStackCompression && canBeFreelyGenerated(_slot); }; // Determine the ideal permutation of the slots in _exitLayout that are not operation outputs (and not to be @@ -235,18 +311,21 @@ Stack StackLayoutGenerator::propagateStackThroughOperation(Stack _exitStack, CFG break; } - // TODO: there may be a better criterion than overall stack size. - if (stack.size() > 12) - // Deduplicate and remove slots that can be freely generated. - stack = compressStack(move(stack)); return stack; } -Stack StackLayoutGenerator::propagateStackThroughBlock(Stack _exitStack, CFG::BasicBlock const& _block) +Stack StackLayoutGenerator::propagateStackThroughBlock(Stack _exitStack, CFG::BasicBlock const& _block, bool _aggressiveStackCompression) { - Stack stack = std::move(_exitStack); - for (auto& operation: _block.operations | ranges::views::reverse) - stack = propagateStackThroughOperation(stack, operation); + Stack stack = _exitStack; + for (auto&& [idx, operation]: _block.operations | ranges::views::enumerate | ranges::views::reverse) + { + Stack newStack = propagateStackThroughOperation(stack, operation, _aggressiveStackCompression); + if (!_aggressiveStackCompression && !findStackTooDeep(newStack, stack).empty()) + // If we had stack errors, run again with aggressive stack compression. + return propagateStackThroughBlock(move(_exitStack), _block, true); + stack = move(newStack); + } + return stack; } @@ -507,7 +586,7 @@ Stack StackLayoutGenerator::combineStack(Stack const& _stack1, Stack const& _sta if (depth && *depth >= 16) numOps += 1000; }; - createStackLayout(testStack, stack1Tail, swap, dupOrPush, [&](){} ); + createStackLayout(testStack, stack1Tail, swap, dupOrPush, [&](){}); testStack = _candidate; createStackLayout(testStack, stack2Tail, swap, dupOrPush, [&](){}); return numOps; @@ -549,6 +628,54 @@ Stack StackLayoutGenerator::combineStack(Stack const& _stack1, Stack const& _sta return commonPrefix + bestCandidate; } +vector StackLayoutGenerator::reportStackTooDeep(CFG::BasicBlock const& _entry) const +{ + vector stackTooDeepErrors; + util::BreadthFirstSearch breadthFirstSearch{{&_entry}}; + breadthFirstSearch.run([&](CFG::BasicBlock const* _block, auto _addChild) { + Stack currentStack = m_layout.blockInfos.at(_block).entryLayout; + + for (auto const& operation: _block->operations) + { + Stack& operationEntry = m_layout.operationEntryLayout.at(&operation); + + stackTooDeepErrors += findStackTooDeep(currentStack, operationEntry); + currentStack = operationEntry; + for (size_t i = 0; i < operation.input.size(); i++) + currentStack.pop_back(); + currentStack += operation.output; + } + // Do not attempt to create the exit layout m_layout.blockInfos.at(_block).exitLayout here, + // since the code generator will directly move to the target entry layout. + + std::visit(util::GenericVisitor{ + [&](CFG::BasicBlock::MainExit const&) {}, + [&](CFG::BasicBlock::Jump const& _jump) + { + Stack const& targetLayout = m_layout.blockInfos.at(_jump.target).entryLayout; + stackTooDeepErrors += findStackTooDeep(currentStack, targetLayout); + + if (!_jump.backwards) + _addChild(_jump.target); + }, + [&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) + { + for (Stack const& targetLayout: { + m_layout.blockInfos.at(_conditionalJump.zero).entryLayout, + m_layout.blockInfos.at(_conditionalJump.nonZero).entryLayout + }) + stackTooDeepErrors += findStackTooDeep(currentStack, targetLayout); + + _addChild(_conditionalJump.zero); + _addChild(_conditionalJump.nonZero); + }, + [&](CFG::BasicBlock::FunctionReturn const&) {}, + [&](CFG::BasicBlock::Terminated const&) {}, + }, _block->exit); + }); + return stackTooDeepErrors; +} + Stack StackLayoutGenerator::compressStack(Stack _stack) { optional firstDupOffset; diff --git a/libyul/backends/evm/StackLayoutGenerator.h b/libyul/backends/evm/StackLayoutGenerator.h index a5b05654b..803e49354 100644 --- a/libyul/backends/evm/StackLayoutGenerator.h +++ b/libyul/backends/evm/StackLayoutGenerator.h @@ -47,7 +47,23 @@ struct StackLayout class StackLayoutGenerator { public: + struct StackTooDeep + { + /// Number of slots that need to be saved. + size_t deficit = 0; + /// Set of variables, eliminating which would decrease the stack deficit. + std::vector variableChoices; + }; + static StackLayout run(CFG const& _cfg); + /// @returns a map from function names to the stack too deep errors occurring in that function. + /// Requires @a _cfg to be a control flow graph generated from disambiguated Yul. + /// The empty string is mapped to the stack too deep errors of the main entry point. + static std::map> reportStackTooDeep(CFG const& _cfg); + /// @returns all stack too deep errors in the function named @a _functionName. + /// Requires @a _cfg to be a control flow graph generated from disambiguated Yul. + /// If @a _functionName is empty, the stack too deep errors of the main entry point are reported instead. + static std::vector reportStackTooDeep(CFG const& _cfg, YulString _functionName); private: StackLayoutGenerator(StackLayout& _context); @@ -55,11 +71,11 @@ private: /// @returns the optimal entry stack layout, s.t. @a _operation can be applied to it and /// the result can be transformed to @a _exitStack with minimal stack shuffling. /// Simultaneously stores the entry layout required for executing the operation in m_layout. - Stack propagateStackThroughOperation(Stack _exitStack, CFG::Operation const& _operation); + Stack propagateStackThroughOperation(Stack _exitStack, CFG::Operation const& _operation, bool _aggressiveStackCompression = false); /// @returns the desired stack layout at the entry of @a _block, assuming the layout after /// executing the block should be @a _exitStack. - Stack propagateStackThroughBlock(Stack _exitStack, CFG::BasicBlock const& _block); + Stack propagateStackThroughBlock(Stack _exitStack, CFG::BasicBlock const& _block, bool _aggressiveStackCompression = false); /// Main algorithm walking the graph from entry to exit and propagating back the stack layouts to the entries. /// Iteratively reruns itself along backwards jumps until the layout is stabilized. @@ -86,6 +102,10 @@ private: /// stack shuffling when starting from the returned layout. static Stack combineStack(Stack const& _stack1, Stack const& _stack2); + /// Walks through the CFG and reports any stack too deep errors that would occur when generating code for it + /// without countermeasures. + std::vector reportStackTooDeep(CFG::BasicBlock const& _entry) const; + /// @returns a copy of @a _stack stripped of all duplicates and slots that can be freely generated. /// Attempts to create a layout that requires a minimal amount of operations to reconstruct the original /// stack @a _stack. From 2cdd3b20818a472bf94c66713acdf6674a8df652 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 6 Sep 2021 12:02:55 +0200 Subject: [PATCH 020/232] Resolving Keccak-256: check if arguments are identifiers early. Previously, the check on whether the optimization was useful gas wise was done before checking if the keccak256 opcode had identifier as arguments. Since the gas meter crashes when encountering certain Yul opcodes (create, dataoffset, etc.), this optimizer step crashed. --- Changelog.md | 1 + libyul/optimiser/LoadResolver.cpp | 14 +++++++------- .../loadResolver/keccak_crash.yul | 13 +++++++++++++ 3 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 test/libyul/yulOptimizerTests/loadResolver/keccak_crash.yul diff --git a/Changelog.md b/Changelog.md index b1a350350..f363d7164 100644 --- a/Changelog.md +++ b/Changelog.md @@ -12,6 +12,7 @@ Compiler Features: * SMTChecker: Add constraints to better correlate ``address(this).balance`` and ``msg.value``. * SMTChecker: Support the ``value`` option for external function calls. * Commandline Interface: Disallowed the ``--experimental-via-ir`` option to be used with Standard Json, Assembler and Linker modes. + * Yul Optimizer: Fix a crash in LoadResolver, when ``keccak256`` has particular non-identifier arguments. Bugfixes: diff --git a/libyul/optimiser/LoadResolver.cpp b/libyul/optimiser/LoadResolver.cpp index b968e1bef..550ca6fb3 100644 --- a/libyul/optimiser/LoadResolver.cpp +++ b/libyul/optimiser/LoadResolver.cpp @@ -97,6 +97,13 @@ void LoadResolver::tryEvaluateKeccak( std::vector const& _arguments ) { + yulAssert(_arguments.size() == 2, ""); + Identifier const* memoryKey = std::get_if(&_arguments.at(0)); + Identifier const* length = std::get_if(&_arguments.at(1)); + + if (!memoryKey || !length) + return; + // The costs are only correct for hashes of 32 bytes or 1 word (when rounded up). GasMeter gasMeter{ dynamic_cast(m_dialect), @@ -122,13 +129,6 @@ void LoadResolver::tryEvaluateKeccak( if (costOfLiteral > costOfKeccak) return; - yulAssert(_arguments.size() == 2, ""); - Identifier const* memoryKey = std::get_if(&_arguments.at(0)); - Identifier const* length = std::get_if(&_arguments.at(1)); - - if (!memoryKey || !length) - return; - auto memoryValue = util::valueOrNullptr(m_memory, memoryKey->name); if (memoryValue && inScope(*memoryValue)) { diff --git a/test/libyul/yulOptimizerTests/loadResolver/keccak_crash.yul b/test/libyul/yulOptimizerTests/loadResolver/keccak_crash.yul new file mode 100644 index 000000000..dd6a164eb --- /dev/null +++ b/test/libyul/yulOptimizerTests/loadResolver/keccak_crash.yul @@ -0,0 +1,13 @@ +// This test used to crash: https://github.com/ethereum/solidity/issues/11801 +{ + for {} addmod(keccak256(0x0,create(0x0, 0x0, 0x0)), 0x0, 0x0) {} {} +} +// ---- +// step: loadResolver +// +// { +// for { } +// addmod(keccak256(0x0, create(0x0, 0x0, 0x0)), 0x0, 0x0) +// { } +// { } +// } From a683ea764656b9c81fb7e5e33184d2a3f877d9e2 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Fri, 3 Sep 2021 15:55:17 +0200 Subject: [PATCH 021/232] Remove the expression callback from the code generator functions of Yul builtins. --- libyul/backends/evm/EVMCodeTransform.cpp | 10 ++- libyul/backends/evm/EVMDialect.cpp | 83 +++++++----------------- libyul/backends/evm/EVMDialect.h | 7 +- libyul/backends/evm/NoOutputAssembly.cpp | 17 ++--- 4 files changed, 38 insertions(+), 79 deletions(-) diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index c837c8b1a..947e8d091 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -239,9 +239,13 @@ void CodeTransform::operator()(FunctionCall const& _call) m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_call.debugData)); if (BuiltinFunctionForEVM const* builtin = m_dialect.builtin(_call.functionName.name)) - builtin->generateCode(_call, m_assembly, m_builtinContext, [&](Expression const& _expression) { - visitExpression(_expression); - }); + { + for (auto&& [i, arg]: _call.arguments | ranges::views::enumerate | ranges::views::reverse) + if (!builtin->literalArgument(i)) + visitExpression(arg); + m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_call.debugData)); + builtin->generateCode(_call, m_assembly, m_builtinContext); + } else { AbstractAssembly::LabelID returnLabel = m_assembly.newLabelId(); diff --git a/libyul/backends/evm/EVMDialect.cpp b/libyul/backends/evm/EVMDialect.cpp index 86202e378..c90784a03 100644 --- a/libyul/backends/evm/EVMDialect.cpp +++ b/libyul/backends/evm/EVMDialect.cpp @@ -26,8 +26,8 @@ #include #include #include +#include #include - #include #include @@ -46,19 +46,6 @@ using namespace solidity::util; namespace { -void visitArguments( - AbstractAssembly& _assembly, - FunctionCall const& _call, - function _visitExpression -) -{ - for (auto const& arg: _call.arguments | ranges::views::reverse) - _visitExpression(arg); - - _assembly.setSourceLocation(_call.debugData->location); -} - - pair createEVMFunction( string const& _name, evmasm::Instruction _instruction @@ -76,12 +63,10 @@ pair createEVMFunction( f.literalArguments.clear(); f.instruction = _instruction; f.generateCode = [_instruction]( - FunctionCall const& _call, + FunctionCall const&, AbstractAssembly& _assembly, - BuiltinContext&, - std::function _visitExpression + BuiltinContext& ) { - visitArguments(_assembly, _call, _visitExpression); _assembly.appendInstruction(_instruction); }; @@ -94,7 +79,7 @@ pair createFunction( size_t _returns, SideEffects _sideEffects, vector> _literalArguments, - std::function)> _generateCode + std::function _generateCode ) { yulAssert(_literalArguments.size() == _params || _literalArguments.empty(), ""); @@ -166,12 +151,10 @@ map createBuiltins(langutil::EVMVersion _evmVe builtins.emplace(createFunction("linkersymbol", 1, 1, SideEffects{}, {LiteralKind::String}, []( FunctionCall const& _call, AbstractAssembly& _assembly, - BuiltinContext&, - function + BuiltinContext& ) { yulAssert(_call.arguments.size() == 1, ""); Expression const& arg = _call.arguments.front(); - _assembly.setSourceLocation(_call.debugData->location); _assembly.appendLinkerSymbol(std::get(arg).value.str()); })); @@ -184,24 +167,24 @@ map createBuiltins(langutil::EVMVersion _evmVe []( FunctionCall const& _call, AbstractAssembly& _assembly, - BuiltinContext&, - function _visitExpression + BuiltinContext& ) { - visitArguments(_assembly, _call, _visitExpression); + yulAssert(_call.arguments.size() == 1, ""); + Literal const* literal = get_if(&_call.arguments.front()); + yulAssert(literal, ""); + _assembly.appendConstant(valueOfLiteral(*literal)); }) ); builtins.emplace(createFunction("datasize", 1, 1, SideEffects{}, {LiteralKind::String}, []( FunctionCall const& _call, AbstractAssembly& _assembly, - BuiltinContext& _context, - std::function const& + BuiltinContext& _context ) { yulAssert(_context.currentObject, "No object available."); yulAssert(_call.arguments.size() == 1, ""); Expression const& arg = _call.arguments.front(); YulString dataName = std::get(arg).value; - _assembly.setSourceLocation(_call.debugData->location); if (_context.currentObject->name == dataName) _assembly.appendAssemblySize(); else @@ -217,14 +200,12 @@ map createBuiltins(langutil::EVMVersion _evmVe builtins.emplace(createFunction("dataoffset", 1, 1, SideEffects{}, {LiteralKind::String}, []( FunctionCall const& _call, AbstractAssembly& _assembly, - BuiltinContext& _context, - std::function const& + BuiltinContext& _context ) { yulAssert(_context.currentObject, "No object available."); yulAssert(_call.arguments.size() == 1, ""); Expression const& arg = _call.arguments.front(); YulString dataName = std::get(arg).value; - _assembly.setSourceLocation(_call.debugData->location); if (_context.currentObject->name == dataName) _assembly.appendConstant(0); else @@ -244,12 +225,10 @@ map createBuiltins(langutil::EVMVersion _evmVe SideEffects{false, true, false, false, true, SideEffects::None, SideEffects::None, SideEffects::Write}, {}, []( - FunctionCall const& _call, + FunctionCall const&, AbstractAssembly& _assembly, - BuiltinContext&, - std::function _visitExpression + BuiltinContext& ) { - visitArguments(_assembly, _call, _visitExpression); _assembly.appendInstruction(evmasm::Instruction::CODECOPY); } )); @@ -262,15 +241,10 @@ map createBuiltins(langutil::EVMVersion _evmVe []( FunctionCall const& _call, AbstractAssembly& _assembly, - BuiltinContext&, - std::function _visitExpression + BuiltinContext& ) { yulAssert(_call.arguments.size() == 3, ""); - - _visitExpression(_call.arguments[2]); YulString identifier = std::get(_call.arguments[1]).value; - _visitExpression(_call.arguments[0]); - _assembly.setSourceLocation(_call.debugData->location); _assembly.appendImmutableAssignment(identifier.str()); } )); @@ -283,11 +257,9 @@ map createBuiltins(langutil::EVMVersion _evmVe []( FunctionCall const& _call, AbstractAssembly& _assembly, - BuiltinContext&, - std::function + BuiltinContext& ) { yulAssert(_call.arguments.size() == 1, ""); - _assembly.setSourceLocation(_call.debugData->location); _assembly.appendImmutable(std::get(_call.arguments.front()).value.str()); } )); @@ -387,15 +359,11 @@ BuiltinFunctionForEVM const* EVMDialect::verbatimFunction(size_t _arguments, siz [=]( FunctionCall const& _call, AbstractAssembly& _assembly, - BuiltinContext&, - std::function _visitExpression + BuiltinContext& ) { yulAssert(_call.arguments.size() == (1 + _arguments), ""); - for (Expression const& arg: _call.arguments | ranges::views::tail | ranges::views::reverse) - _visitExpression(arg); Expression const& bytecode = _call.arguments.front(); - _assembly.setSourceLocation(_call.debugData->location); _assembly.appendVerbatim( asBytes(std::get(bytecode).value.str()), _arguments, @@ -456,24 +424,19 @@ EVMDialectTyped::EVMDialectTyped(langutil::EVMVersion _evmVersion, bool _objectA m_functions["popbool"_yulstring].name = "popbool"_yulstring; m_functions["popbool"_yulstring].parameters = {"bool"_yulstring}; m_functions.insert(createFunction("bool_to_u256", 1, 1, {}, {}, []( - FunctionCall const& _call, - AbstractAssembly& _assembly, - BuiltinContext&, - std::function _visitExpression - ) { - visitArguments(_assembly, _call, _visitExpression); - })); + FunctionCall const&, + AbstractAssembly&, + BuiltinContext& + ) {})); m_functions["bool_to_u256"_yulstring].parameters = {"bool"_yulstring}; m_functions["bool_to_u256"_yulstring].returns = {"u256"_yulstring}; m_functions.insert(createFunction("u256_to_bool", 1, 1, {}, {}, []( - FunctionCall const& _call, + FunctionCall const&, AbstractAssembly& _assembly, - BuiltinContext&, - std::function _visitExpression + BuiltinContext& ) { // TODO this should use a Panic. // A value larger than 1 causes an invalid instruction. - visitArguments(_assembly, _call, _visitExpression); _assembly.appendConstant(2); _assembly.appendInstruction(evmasm::Instruction::DUP2); _assembly.appendInstruction(evmasm::Instruction::LT); diff --git a/libyul/backends/evm/EVMDialect.h b/libyul/backends/evm/EVMDialect.h index b79c558be..28649f3e5 100644 --- a/libyul/backends/evm/EVMDialect.h +++ b/libyul/backends/evm/EVMDialect.h @@ -52,9 +52,10 @@ struct BuiltinFunctionForEVM: public BuiltinFunction { std::optional instruction; /// Function to generate code for the given function call and append it to the abstract - /// assembly. The fourth parameter is called to visit (and generate code for) the given - /// argument. - std::function)> generateCode; + /// assembly. Expects all non-literal arguments of the call to be on stack in reverse order + /// (i.e. right-most argument pushed first). + /// Expects the caller to set the source location. + std::function generateCode; }; diff --git a/libyul/backends/evm/NoOutputAssembly.cpp b/libyul/backends/evm/NoOutputAssembly.cpp index c8016d4a5..62c0ad119 100644 --- a/libyul/backends/evm/NoOutputAssembly.cpp +++ b/libyul/backends/evm/NoOutputAssembly.cpp @@ -26,6 +26,7 @@ #include +#include using namespace std; using namespace solidity; @@ -135,21 +136,11 @@ NoOutputEVMDialect::NoOutputEVMDialect(EVMDialect const& _copyFrom): for (auto& fun: m_functions) { size_t returns = fun.second.returns.size(); - fun.second.generateCode = [=](FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext&, std::function _visitExpression) + fun.second.generateCode = [=](FunctionCall const& _call, AbstractAssembly& _assembly, BuiltinContext&) { - size_t visited = 0; - for (size_t j = 0; j < _call.arguments.size(); j++) - { - size_t const i = _call.arguments.size() - j - 1; + for (size_t i: ranges::views::iota(0u, _call.arguments.size())) if (!fun.second.literalArgument(i)) - { - _visitExpression(_call.arguments[i]); - visited++; - } - } - - for (size_t i = 0; i < visited; i++) - _assembly.appendInstruction(evmasm::Instruction::POP); + _assembly.appendInstruction(evmasm::Instruction::POP); for (size_t i = 0; i < returns; i++) _assembly.appendConstant(u256(0)); From 4d52e873e77ecaf31ffe667908790ec459da3faf Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 6 Sep 2021 17:44:45 +0200 Subject: [PATCH 022/232] Move changelog item to bugfix. --- Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index f363d7164..5bbd686a3 100644 --- a/Changelog.md +++ b/Changelog.md @@ -12,7 +12,6 @@ Compiler Features: * SMTChecker: Add constraints to better correlate ``address(this).balance`` and ``msg.value``. * SMTChecker: Support the ``value`` option for external function calls. * Commandline Interface: Disallowed the ``--experimental-via-ir`` option to be used with Standard Json, Assembler and Linker modes. - * Yul Optimizer: Fix a crash in LoadResolver, when ``keccak256`` has particular non-identifier arguments. Bugfixes: @@ -21,6 +20,7 @@ Bugfixes: * SMTChecker: Fix false positive in external calls from constructors. * SMTChecker: Fix internal error on some multi-source uses of ``abi.*``, cryptographic functions and constants. * Type Checker: Disallow modifier declarations and definitions in interfaces. + * Yul Optimizer: Fix a crash in LoadResolver, when ``keccak256`` has particular non-identifier arguments. From 5d2931cba337dad24eecf46dfd51ff598a4a954f Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 6 Sep 2021 18:18:33 +0200 Subject: [PATCH 023/232] Refactor: Add helper for context. --- libsolidity/codegen/ir/IRGenerator.cpp | 40 ++++++++++++++------------ libsolidity/codegen/ir/IRGenerator.h | 2 ++ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 47a57eb08..9730cb35b 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -179,7 +179,7 @@ string IRGenerator::generate( ); t("useSrcMapCreation", useSrcMap); - t("sourceLocationComment", sourceLocationComment(_contract, m_context)); + t("sourceLocationComment", sourceLocationComment(_contract)); t("CreationObject", IRNames::creationObject(_contract)); t("library", _contract.isLibrary()); @@ -294,7 +294,7 @@ InternalDispatchMap IRGenerator::generateInternalDispatchFunctions(ContractDefin } )"); - templ("sourceLocationComment", sourceLocationComment(_contract, m_context)); + templ("sourceLocationComment", sourceLocationComment(_contract)); templ("functionName", funName); templ("panic", m_utils.panicFunction(PanicCode::InvalidInternalFunction)); templ("in", suffixedVariableNameList("in_", 0, arity.in)); @@ -347,10 +347,10 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function) )"); - t("sourceLocationComment", sourceLocationComment(_function, m_context)); + t("sourceLocationComment", sourceLocationComment(_function)); t( "contractSourceLocationComment", - sourceLocationComment(m_context.mostDerivedContract(), m_context) + sourceLocationComment(m_context.mostDerivedContract()) ); t("functionName", functionName); @@ -436,10 +436,10 @@ string IRGenerator::generateModifier( _modifierInvocation.name().annotation().referencedDeclaration ); solAssert(modifier, ""); - t("sourceLocationComment", sourceLocationComment(*modifier, m_context)); + t("sourceLocationComment", sourceLocationComment(*modifier)); t( "contractSourceLocationComment", - sourceLocationComment(m_context.mostDerivedContract(), m_context) + sourceLocationComment(m_context.mostDerivedContract()) ); switch (*_modifierInvocation.name().annotation().requiredLookup) @@ -499,10 +499,10 @@ string IRGenerator::generateFunctionWithModifierInner(FunctionDefinition const& } )"); - t("sourceLocationComment", sourceLocationComment(_function, m_context)); + t("sourceLocationComment", sourceLocationComment(_function)); t( "contractSourceLocationComment", - sourceLocationComment(m_context.mostDerivedContract(), m_context) + sourceLocationComment(m_context.mostDerivedContract()) ); t("functionName", functionName); vector retParams; @@ -547,10 +547,10 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) } )") - ("sourceLocationComment", sourceLocationComment(_varDecl, m_context)) + ("sourceLocationComment", sourceLocationComment(_varDecl)) ( "contractSourceLocationComment", - sourceLocationComment(m_context.mostDerivedContract(), m_context) + sourceLocationComment(m_context.mostDerivedContract()) ) ("functionName", functionName) ("id", to_string(_varDecl.id())) @@ -566,10 +566,10 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) } )") - ("sourceLocationComment", sourceLocationComment(_varDecl, m_context)) + ("sourceLocationComment", sourceLocationComment(_varDecl)) ( "contractSourceLocationComment", - sourceLocationComment(m_context.mostDerivedContract(), m_context) + sourceLocationComment(m_context.mostDerivedContract()) ) ("functionName", functionName) ("constantValueFunction", IRGeneratorForStatements(m_context, m_utils).constantValueFunction(_varDecl)) @@ -692,10 +692,10 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) ("params", joinHumanReadable(parameters)) ("retVariables", joinHumanReadable(returnVariables)) ("code", std::move(code)) - ("sourceLocationComment", sourceLocationComment(_varDecl, m_context)) + ("sourceLocationComment", sourceLocationComment(_varDecl)) ( "contractSourceLocationComment", - sourceLocationComment(m_context.mostDerivedContract(), m_context) + sourceLocationComment(m_context.mostDerivedContract()) ) .render(); }); @@ -820,13 +820,12 @@ void IRGenerator::generateConstructors(ContractDefinition const& _contract) t("sourceLocationComment", sourceLocationComment( contract->constructor() ? - contract->constructor()->location() : - contract->location(), - m_context + dynamic_cast(*contract->constructor()) : + dynamic_cast(*contract) )); t( "contractSourceLocationComment", - sourceLocationComment(m_context.mostDerivedContract(), m_context) + sourceLocationComment(m_context.mostDerivedContract()) ); t("params", joinHumanReadable(params)); @@ -1073,3 +1072,8 @@ void IRGenerator::resetContext(ContractDefinition const& _contract, ExecutionCon for (auto const& var: ContractType(_contract).stateVariables()) m_context.addStateVariable(*get<0>(var), get<1>(var), get<2>(var)); } + +string IRGenerator::sourceLocationComment(ASTNode const& _node) const +{ + return ::sourceLocationComment(_node, m_context); +} diff --git a/libsolidity/codegen/ir/IRGenerator.h b/libsolidity/codegen/ir/IRGenerator.h index 85d611108..3fd58f239 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -119,6 +119,8 @@ private: void resetContext(ContractDefinition const& _contract, ExecutionContext _context); + std::string sourceLocationComment(ASTNode const& _node) const; + langutil::EVMVersion const m_evmVersion; OptimiserSettings const m_optimiserSettings; From f14b7598c7783291196a86506a87e83f82a20dea Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 31 Aug 2021 12:57:13 +0200 Subject: [PATCH 024/232] Only list used source names. --- libsolidity/codegen/ir/Common.cpp | 5 +-- libsolidity/codegen/ir/Common.h | 4 +-- libsolidity/codegen/ir/IRGenerationContext.h | 3 ++ libsolidity/codegen/ir/IRGenerator.cpp | 32 +++++++++---------- libsolidity/codegen/ir/IRGenerator.h | 2 +- .../constant_optimizer_yul/output | 4 +-- test/cmdlineTests/exp_base_literal/output | 4 +-- .../output | 8 ++--- .../ir_compiler_subobjects/output | 12 +++---- .../output | 4 +-- .../output | 4 +-- .../keccak_optimization_deploy_code/output | 4 +-- .../keccak_optimization_low_runs/output | 4 +-- test/cmdlineTests/name_simplifier/output | 4 +-- .../cmdlineTests/optimizer_array_sload/output | 4 +-- test/cmdlineTests/revert_strings/output | 4 +-- .../output.json | 4 +-- .../standard_ir_requested/output.json | 4 +-- .../standard_viair_requested/output.json | 12 +++---- test/cmdlineTests/viair_abicoder_v1/output | 4 +-- test/cmdlineTests/viair_subobjects/output | 12 +++---- test/cmdlineTests/yul_optimizer_steps/output | 4 +-- .../yul_source_locations/output.json | 8 ++--- .../yul_string_format_ascii/output.json | 4 +-- .../output.json | 4 +-- .../output.json | 4 +-- .../yul_string_format_ascii_long/output.json | 4 +-- .../yul_string_format_hex/output.json | 4 +-- 28 files changed, 87 insertions(+), 83 deletions(-) diff --git a/libsolidity/codegen/ir/Common.cpp b/libsolidity/codegen/ir/Common.cpp index e9bbaa4e0..6aaecad81 100644 --- a/libsolidity/codegen/ir/Common.cpp +++ b/libsolidity/codegen/ir/Common.cpp @@ -127,9 +127,10 @@ string IRNames::zeroValue(Type const& _type, string const& _variableName) return "zero_" + _type.identifier() + _variableName; } -string sourceLocationComment(langutil::SourceLocation const& _location, IRGenerationContext const& _context) +string sourceLocationComment(langutil::SourceLocation const& _location, IRGenerationContext& _context) { solAssert(_location.sourceName, ""); + _context.markSourceUsed(*_location.sourceName); return "/// @src " + to_string(_context.sourceIndices().at(*_location.sourceName)) + ":" @@ -138,7 +139,7 @@ string sourceLocationComment(langutil::SourceLocation const& _location, IRGenera + to_string(_location.end); } -string sourceLocationComment(ASTNode const& _node, IRGenerationContext const& _context) +string sourceLocationComment(ASTNode const& _node, IRGenerationContext& _context) { return sourceLocationComment(_node.location(), _context); } diff --git a/libsolidity/codegen/ir/Common.h b/libsolidity/codegen/ir/Common.h index 67b0cffdc..ab5372286 100644 --- a/libsolidity/codegen/ir/Common.h +++ b/libsolidity/codegen/ir/Common.h @@ -73,8 +73,8 @@ struct IRNames * @returns a source location comment in the form of * `/// @src ::`. */ -std::string sourceLocationComment(langutil::SourceLocation const& _location, IRGenerationContext const& _context); -std::string sourceLocationComment(ASTNode const& _node, IRGenerationContext const& _context); +std::string sourceLocationComment(langutil::SourceLocation const& _location, IRGenerationContext& _context); +std::string sourceLocationComment(ASTNode const& _node, IRGenerationContext& _context); } diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index b8affcbd8..ee3eaced6 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -166,6 +166,8 @@ public: void copyFunctionIDsFrom(IRGenerationContext const& _other); std::map const& sourceIndices() const { return m_sourceIndices; } + void markSourceUsed(std::string const& _name) { m_usedSourceNames.insert(_name); } + std::set const& usedSourceNames() const { return m_usedSourceNames; } bool immutableRegistered(VariableDeclaration const& _varDecl) const { return m_immutableVariables.count(&_varDecl); } @@ -175,6 +177,7 @@ private: RevertStrings m_revertStrings; OptimiserSettings m_optimiserSettings; std::map m_sourceIndices; + std::set m_usedSourceNames; ContractDefinition const* m_mostDerivedContract = nullptr; std::map m_localVariables; /// Memory offsets reserved for the values of immutable variables during contract creation. diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 9730cb35b..8acb6f599 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -131,12 +131,21 @@ string IRGenerator::generate( subObjectsSources += _otherYulSources.at(subObject); return subObjectsSources; }; + auto formatUseSrcMap = [](IRGenerationContext const& _context) -> string + { + return joinHumanReadable( + ranges::views::transform(_context.usedSourceNames(), [_context](string const& _sourceName) { + return to_string(_context.sourceIndices().at(_sourceName)) + ":" + escapeAndQuoteString(_sourceName); + }), + ", " + ); + }; Whiskers t(R"( /// @use-src object "" { code { - + @@ -150,7 +159,7 @@ string IRGenerator::generate( /// @use-src object "" { code { - + let called_via_delegatecall := iszero(eq(loadimmutable(""), address())) @@ -169,19 +178,8 @@ string IRGenerator::generate( for (VariableDeclaration const* var: ContractType(_contract).immutableVariables()) m_context.registerImmutableVariable(*var); - auto invertedSourceIndicies = invertMap(m_context.sourceIndices()); - - string useSrcMap = joinHumanReadable( - ranges::views::transform(invertedSourceIndicies, [](auto&& _pair) { - return to_string(_pair.first) + ":" + escapeAndQuoteString(_pair.second); - }), - ", " - ); - - t("useSrcMapCreation", useSrcMap); - t("sourceLocationComment", sourceLocationComment(_contract)); - t("CreationObject", IRNames::creationObject(_contract)); + t("sourceLocationCommentCreation", sourceLocationComment(_contract)); t("library", _contract.isLibrary()); FunctionDefinition const* constructor = _contract.constructor(); @@ -211,6 +209,7 @@ string IRGenerator::generate( // This has to be called only after all other code generation for the creation object is complete. bool creationInvolvesAssembly = m_context.inlineAssemblySeen(); t("memoryInitCreation", memoryInit(!creationInvolvesAssembly)); + t("useSrcMapCreation", formatUseSrcMap(m_context)); resetContext(_contract, ExecutionContext::Deployed); @@ -220,8 +219,8 @@ string IRGenerator::generate( m_context.initializeInternalDispatch(move(internalDispatchMap)); // Do not register immutables to avoid assignment. - t("useSrcMapDeployed", useSrcMap); t("DeployedObject", IRNames::deployedObject(_contract)); + t("sourceLocationCommentDeployed", sourceLocationComment(_contract)); t("library_address", IRNames::libraryAddressImmutable()); t("dispatch", dispatchRoutine(_contract)); set deployedFunctionList = generateQueuedFunctions(); @@ -231,6 +230,7 @@ string IRGenerator::generate( t("metadataName", yul::Object::metadataName()); t("cborMetadata", toHex(_cborMetadata)); + t("useSrcMapDeployed", formatUseSrcMap(m_context)); // This has to be called only after all other code generation for the deployed object is complete. bool deployedInvolvesAssembly = m_context.inlineAssemblySeen(); @@ -1073,7 +1073,7 @@ void IRGenerator::resetContext(ContractDefinition const& _contract, ExecutionCon m_context.addStateVariable(*get<0>(var), get<1>(var), get<2>(var)); } -string IRGenerator::sourceLocationComment(ASTNode const& _node) const +string IRGenerator::sourceLocationComment(ASTNode const& _node) { return ::sourceLocationComment(_node, m_context); } diff --git a/libsolidity/codegen/ir/IRGenerator.h b/libsolidity/codegen/ir/IRGenerator.h index 3fd58f239..9ec574752 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -119,7 +119,7 @@ private: void resetContext(ContractDefinition const& _contract, ExecutionContext _context); - std::string sourceLocationComment(ASTNode const& _node) const; + std::string sourceLocationComment(ASTNode const& _node); langutil::EVMVersion const m_evmVersion; OptimiserSettings const m_optimiserSettings; diff --git a/test/cmdlineTests/constant_optimizer_yul/output b/test/cmdlineTests/constant_optimizer_yul/output index 46df0ba95..15304fb3b 100644 --- a/test/cmdlineTests/constant_optimizer_yul/output +++ b/test/cmdlineTests/constant_optimizer_yul/output @@ -6,7 +6,7 @@ Optimized IR: * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:"constant_optimizer_yul/input.sol", 1:"#utility.yul" +/// @use-src 0:"constant_optimizer_yul/input.sol" object "C_12" { code { { @@ -21,7 +21,7 @@ object "C_12" { return(128, _1) } } - /// @use-src 0:"constant_optimizer_yul/input.sol", 1:"#utility.yul" + /// @use-src 0:"constant_optimizer_yul/input.sol" object "C_12_deployed" { code { { diff --git a/test/cmdlineTests/exp_base_literal/output b/test/cmdlineTests/exp_base_literal/output index 4b1484e3d..36d7800a0 100644 --- a/test/cmdlineTests/exp_base_literal/output +++ b/test/cmdlineTests/exp_base_literal/output @@ -7,7 +7,7 @@ IR: *=====================================================*/ -/// @use-src 0:"exp_base_literal/input.sol", 1:"#utility.yul" +/// @use-src 0:"exp_base_literal/input.sol" object "C_81" { code { /// @src 0:82:370 @@ -38,7 +38,7 @@ object "C_81" { } } - /// @use-src 0:"exp_base_literal/input.sol", 1:"#utility.yul" + /// @use-src 0:"exp_base_literal/input.sol" object "C_81_deployed" { code { /// @src 0:82:370 diff --git a/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output b/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output index 541dac88b..8f948ccb9 100644 --- a/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output +++ b/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output @@ -6,7 +6,7 @@ Optimized IR: * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:"ir_compiler_inheritance_nosubobjects/input.sol", 1:"#utility.yul" +/// @use-src 0:"ir_compiler_inheritance_nosubobjects/input.sol" object "C_7" { code { { @@ -18,7 +18,7 @@ object "C_7" { return(128, _1) } } - /// @use-src 0:"ir_compiler_inheritance_nosubobjects/input.sol", 1:"#utility.yul" + /// @use-src 0:"ir_compiler_inheritance_nosubobjects/input.sol" object "C_7_deployed" { code { { @@ -39,7 +39,7 @@ Optimized IR: * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:"ir_compiler_inheritance_nosubobjects/input.sol", 1:"#utility.yul" +/// @use-src 0:"ir_compiler_inheritance_nosubobjects/input.sol" object "D_10" { code { { @@ -51,7 +51,7 @@ object "D_10" { return(128, _1) } } - /// @use-src 0:"ir_compiler_inheritance_nosubobjects/input.sol", 1:"#utility.yul" + /// @use-src 0:"ir_compiler_inheritance_nosubobjects/input.sol" object "D_10_deployed" { code { { diff --git a/test/cmdlineTests/ir_compiler_subobjects/output b/test/cmdlineTests/ir_compiler_subobjects/output index 8de953f11..9da2e5e7f 100644 --- a/test/cmdlineTests/ir_compiler_subobjects/output +++ b/test/cmdlineTests/ir_compiler_subobjects/output @@ -6,7 +6,7 @@ Optimized IR: * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:"ir_compiler_subobjects/input.sol", 1:"#utility.yul" +/// @use-src 0:"ir_compiler_subobjects/input.sol" object "C_3" { code { { @@ -18,7 +18,7 @@ object "C_3" { return(128, _1) } } - /// @use-src 0:"ir_compiler_subobjects/input.sol", 1:"#utility.yul" + /// @use-src 0:"ir_compiler_subobjects/input.sol" object "C_3_deployed" { code { { @@ -39,7 +39,7 @@ Optimized IR: * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:"ir_compiler_subobjects/input.sol", 1:"#utility.yul" +/// @use-src 0:"ir_compiler_subobjects/input.sol" object "D_16" { code { { @@ -51,7 +51,7 @@ object "D_16" { return(128, _1) } } - /// @use-src 0:"ir_compiler_subobjects/input.sol", 1:"#utility.yul" + /// @use-src 0:"ir_compiler_subobjects/input.sol" object "D_16_deployed" { code { { @@ -90,7 +90,7 @@ object "D_16" { revert(0, 0) } } - /// @use-src 0:"ir_compiler_subobjects/input.sol", 1:"#utility.yul" + /// @use-src 0:"ir_compiler_subobjects/input.sol" object "C_3" { code { { @@ -102,7 +102,7 @@ object "D_16" { return(128, _1) } } - /// @use-src 0:"ir_compiler_subobjects/input.sol", 1:"#utility.yul" + /// @use-src 0:"ir_compiler_subobjects/input.sol" object "C_3_deployed" { code { { diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output index b7cdc74e9..dff1fb478 100644 --- a/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output @@ -6,7 +6,7 @@ Optimized IR: * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:"ir_with_assembly_no_memoryguard_creation/input.sol", 1:"#utility.yul" +/// @use-src 0:"ir_with_assembly_no_memoryguard_creation/input.sol" object "D_12" { code { { @@ -18,7 +18,7 @@ object "D_12" { return(128, _1) } } - /// @use-src 0:"ir_with_assembly_no_memoryguard_creation/input.sol", 1:"#utility.yul" + /// @use-src 0:"ir_with_assembly_no_memoryguard_creation/input.sol" object "D_12_deployed" { code { { diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output index 0dece56bd..2fbed1d26 100644 --- a/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output @@ -6,7 +6,7 @@ Optimized IR: * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:"ir_with_assembly_no_memoryguard_runtime/input.sol", 1:"#utility.yul" +/// @use-src 0:"ir_with_assembly_no_memoryguard_runtime/input.sol" object "D_8" { code { { @@ -18,7 +18,7 @@ object "D_8" { return(128, _1) } } - /// @use-src 0:"ir_with_assembly_no_memoryguard_runtime/input.sol", 1:"#utility.yul" + /// @use-src 0:"ir_with_assembly_no_memoryguard_runtime/input.sol" object "D_8_deployed" { code { { diff --git a/test/cmdlineTests/keccak_optimization_deploy_code/output b/test/cmdlineTests/keccak_optimization_deploy_code/output index 4e80153d4..09ea3d776 100644 --- a/test/cmdlineTests/keccak_optimization_deploy_code/output +++ b/test/cmdlineTests/keccak_optimization_deploy_code/output @@ -6,7 +6,7 @@ Optimized IR: * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:"keccak_optimization_deploy_code/input.sol", 1:"#utility.yul" +/// @use-src 0:"keccak_optimization_deploy_code/input.sol" object "C_12" { code { { @@ -22,7 +22,7 @@ object "C_12" { return(128, _1) } } - /// @use-src 0:"keccak_optimization_deploy_code/input.sol", 1:"#utility.yul" + /// @use-src 0:"keccak_optimization_deploy_code/input.sol" object "C_12_deployed" { code { { diff --git a/test/cmdlineTests/keccak_optimization_low_runs/output b/test/cmdlineTests/keccak_optimization_low_runs/output index 2632b38df..692bd4384 100644 --- a/test/cmdlineTests/keccak_optimization_low_runs/output +++ b/test/cmdlineTests/keccak_optimization_low_runs/output @@ -6,7 +6,7 @@ Optimized IR: * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:"keccak_optimization_low_runs/input.sol", 1:"#utility.yul" +/// @use-src 0:"keccak_optimization_low_runs/input.sol" object "C_7" { code { { @@ -18,7 +18,7 @@ object "C_7" { return(128, _1) } } - /// @use-src 0:"keccak_optimization_low_runs/input.sol", 1:"#utility.yul" + /// @use-src 0:"keccak_optimization_low_runs/input.sol" object "C_7_deployed" { code { { diff --git a/test/cmdlineTests/name_simplifier/output b/test/cmdlineTests/name_simplifier/output index b8c202c53..a774ead21 100644 --- a/test/cmdlineTests/name_simplifier/output +++ b/test/cmdlineTests/name_simplifier/output @@ -6,7 +6,7 @@ Optimized IR: * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:"name_simplifier/input.sol", 1:"#utility.yul" +/// @use-src 0:"name_simplifier/input.sol" object "C_59" { code { { @@ -18,7 +18,7 @@ object "C_59" { return(128, _1) } } - /// @use-src 0:"name_simplifier/input.sol", 1:"#utility.yul" + /// @use-src 0:"name_simplifier/input.sol" object "C_59_deployed" { code { { diff --git a/test/cmdlineTests/optimizer_array_sload/output b/test/cmdlineTests/optimizer_array_sload/output index 2355d5993..e7bf19abf 100644 --- a/test/cmdlineTests/optimizer_array_sload/output +++ b/test/cmdlineTests/optimizer_array_sload/output @@ -6,7 +6,7 @@ Optimized IR: * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:"optimizer_array_sload/input.sol", 1:"#utility.yul" +/// @use-src 0:"optimizer_array_sload/input.sol" object "Arraysum_34" { code { { @@ -18,7 +18,7 @@ object "Arraysum_34" { return(128, _1) } } - /// @use-src 0:"optimizer_array_sload/input.sol", 1:"#utility.yul" + /// @use-src 0:"optimizer_array_sload/input.sol" object "Arraysum_34_deployed" { code { { diff --git a/test/cmdlineTests/revert_strings/output b/test/cmdlineTests/revert_strings/output index 8a9bc748c..be43c5d0d 100644 --- a/test/cmdlineTests/revert_strings/output +++ b/test/cmdlineTests/revert_strings/output @@ -7,7 +7,7 @@ IR: *=====================================================*/ -/// @use-src 0:"revert_strings/input.sol", 1:"#utility.yul" +/// @use-src 0:"revert_strings/input.sol" object "C_15" { code { /// @src 0:59:147 @@ -53,7 +53,7 @@ object "C_15" { } } - /// @use-src 0:"revert_strings/input.sol", 1:"#utility.yul" + /// @use-src 0:"revert_strings/input.sol" object "C_15_deployed" { code { /// @src 0:59:147 diff --git a/test/cmdlineTests/standard_irOptimized_requested/output.json b/test/cmdlineTests/standard_irOptimized_requested/output.json index bb5b9de14..e94582898 100644 --- a/test/cmdlineTests/standard_irOptimized_requested/output.json +++ b/test/cmdlineTests/standard_irOptimized_requested/output.json @@ -5,7 +5,7 @@ * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:\"A\", 1:\"#utility.yul\" +/// @use-src 0:\"A\" object \"C_7\" { code { /// @src 0:79:121 @@ -25,7 +25,7 @@ object \"C_7\" { function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { revert(0, 0) } } - /// @use-src 0:\"A\", 1:\"#utility.yul\" + /// @use-src 0:\"A\" object \"C_7_deployed\" { code { /// @src 0:79:121 diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index 3d9bb9135..3cc5c0808 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -6,7 +6,7 @@ *=====================================================*/ -/// @use-src 0:\"A\", 1:\"#utility.yul\" +/// @use-src 0:\"A\" object \"C_7\" { code { /// @src 0:79:121 @@ -37,7 +37,7 @@ object \"C_7\" { } } - /// @use-src 0:\"A\", 1:\"#utility.yul\" + /// @use-src 0:\"A\" object \"C_7_deployed\" { code { /// @src 0:79:121 diff --git a/test/cmdlineTests/standard_viair_requested/output.json b/test/cmdlineTests/standard_viair_requested/output.json index aa3291a25..9fa0b02a9 100644 --- a/test/cmdlineTests/standard_viair_requested/output.json +++ b/test/cmdlineTests/standard_viair_requested/output.json @@ -6,7 +6,7 @@ *=====================================================*/ -/// @use-src 0:\"A\", 1:\"#utility.yul\" +/// @use-src 0:\"A\" object \"C_3\" { code { /// @src 0:79:92 @@ -37,7 +37,7 @@ object \"C_3\" { } } - /// @use-src 0:\"A\", 1:\"#utility.yul\" + /// @use-src 0:\"A\" object \"C_3_deployed\" { code { /// @src 0:79:92 @@ -83,7 +83,7 @@ object \"C_3\" { *=====================================================*/ -/// @use-src 0:\"A\", 1:\"#utility.yul\" +/// @use-src 0:\"A\" object \"D_16\" { code { /// @src 0:93:146 @@ -114,7 +114,7 @@ object \"D_16\" { } } - /// @use-src 0:\"A\", 1:\"#utility.yul\" + /// @use-src 0:\"A\" object \"D_16_deployed\" { code { /// @src 0:93:146 @@ -215,7 +215,7 @@ object \"D_16\" { * !USE AT YOUR OWN RISK! * *=====================================================*/ - /// @use-src 0:\"A\", 1:\"#utility.yul\" + /// @use-src 0:\"A\" object \"C_3\" { code { /// @src 0:79:92 @@ -246,7 +246,7 @@ object \"D_16\" { } } - /// @use-src 0:\"A\", 1:\"#utility.yul\" + /// @use-src 0:\"A\" object \"C_3_deployed\" { code { /// @src 0:79:92 diff --git a/test/cmdlineTests/viair_abicoder_v1/output b/test/cmdlineTests/viair_abicoder_v1/output index ca9bbdc5e..6a164cc43 100644 --- a/test/cmdlineTests/viair_abicoder_v1/output +++ b/test/cmdlineTests/viair_abicoder_v1/output @@ -7,7 +7,7 @@ IR: *=====================================================*/ -/// @use-src 0:"viair_abicoder_v1/input.sol", 1:"#utility.yul" +/// @use-src 0:"viair_abicoder_v1/input.sol" object "test_11" { code { /// @src 0:79:169 @@ -38,7 +38,7 @@ object "test_11" { } } - /// @use-src 0:"viair_abicoder_v1/input.sol", 1:"#utility.yul" + /// @use-src 0:"viair_abicoder_v1/input.sol" object "test_11_deployed" { code { /// @src 0:79:169 diff --git a/test/cmdlineTests/viair_subobjects/output b/test/cmdlineTests/viair_subobjects/output index bfdec9087..03e952c7e 100644 --- a/test/cmdlineTests/viair_subobjects/output +++ b/test/cmdlineTests/viair_subobjects/output @@ -12,7 +12,7 @@ Optimized IR: * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:"viair_subobjects/input.sol", 1:"#utility.yul" +/// @use-src 0:"viair_subobjects/input.sol" object "C_3" { code { { @@ -24,7 +24,7 @@ object "C_3" { return(128, _1) } } - /// @use-src 0:"viair_subobjects/input.sol", 1:"#utility.yul" + /// @use-src 0:"viair_subobjects/input.sol" object "C_3_deployed" { code { { @@ -51,7 +51,7 @@ Optimized IR: * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:"viair_subobjects/input.sol", 1:"#utility.yul" +/// @use-src 0:"viair_subobjects/input.sol" object "D_16" { code { { @@ -63,7 +63,7 @@ object "D_16" { return(128, _1) } } - /// @use-src 0:"viair_subobjects/input.sol", 1:"#utility.yul" + /// @use-src 0:"viair_subobjects/input.sol" object "D_16_deployed" { code { { @@ -102,7 +102,7 @@ object "D_16" { revert(0, 0) } } - /// @use-src 0:"viair_subobjects/input.sol", 1:"#utility.yul" + /// @use-src 0:"viair_subobjects/input.sol" object "C_3" { code { { @@ -114,7 +114,7 @@ object "D_16" { return(128, _1) } } - /// @use-src 0:"viair_subobjects/input.sol", 1:"#utility.yul" + /// @use-src 0:"viair_subobjects/input.sol" object "C_3_deployed" { code { { diff --git a/test/cmdlineTests/yul_optimizer_steps/output b/test/cmdlineTests/yul_optimizer_steps/output index bdd97296d..5db709e53 100644 --- a/test/cmdlineTests/yul_optimizer_steps/output +++ b/test/cmdlineTests/yul_optimizer_steps/output @@ -6,7 +6,7 @@ Optimized IR: * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:"yul_optimizer_steps/input.sol", 1:"#utility.yul" +/// @use-src 0:"yul_optimizer_steps/input.sol" object "C_7" { code { { @@ -25,7 +25,7 @@ object "C_7" { function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { revert(0, 0) } } - /// @use-src 0:"yul_optimizer_steps/input.sol", 1:"#utility.yul" + /// @use-src 0:"yul_optimizer_steps/input.sol" object "C_7_deployed" { code { { diff --git a/test/cmdlineTests/yul_source_locations/output.json b/test/cmdlineTests/yul_source_locations/output.json index c5d04aebb..4ce705261 100644 --- a/test/cmdlineTests/yul_source_locations/output.json +++ b/test/cmdlineTests/yul_source_locations/output.json @@ -6,7 +6,7 @@ *=====================================================*/ -/// @use-src 0:\"C\", 1:\"D\", 2:\"#utility.yul\" +/// @use-src 0:\"C\" object \"C_54\" { code { /// @src 0:79:428 @@ -156,7 +156,7 @@ object \"C_54\" { } } - /// @use-src 0:\"C\", 1:\"D\", 2:\"#utility.yul\" + /// @use-src 0:\"C\" object \"C_54_deployed\" { code { /// @src 0:79:428 @@ -564,7 +564,7 @@ object \"C_54\" { *=====================================================*/ -/// @use-src 0:\"C\", 1:\"D\", 2:\"#utility.yul\" +/// @use-src 0:\"C\", 1:\"D\" object \"D_72\" { code { /// @src 1:91:166 @@ -781,7 +781,7 @@ object \"D_72\" { } } - /// @use-src 0:\"C\", 1:\"D\", 2:\"#utility.yul\" + /// @use-src 0:\"C\", 1:\"D\" object \"D_72_deployed\" { code { /// @src 1:91:166 diff --git a/test/cmdlineTests/yul_string_format_ascii/output.json b/test/cmdlineTests/yul_string_format_ascii/output.json index d6bce8b6a..76a14d5cb 100644 --- a/test/cmdlineTests/yul_string_format_ascii/output.json +++ b/test/cmdlineTests/yul_string_format_ascii/output.json @@ -6,7 +6,7 @@ *=====================================================*/ -/// @use-src 0:\"A\", 1:\"#utility.yul\" +/// @use-src 0:\"A\" object \"C_11\" { code { /// @src 0:78:164 @@ -37,7 +37,7 @@ object \"C_11\" { } } - /// @use-src 0:\"A\", 1:\"#utility.yul\" + /// @use-src 0:\"A\" object \"C_11_deployed\" { code { /// @src 0:78:164 diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json index ccf999086..39046124f 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json @@ -6,7 +6,7 @@ *=====================================================*/ -/// @use-src 0:\"A\", 1:\"#utility.yul\" +/// @use-src 0:\"A\" object \"C_11\" { code { /// @src 0:78:158 @@ -37,7 +37,7 @@ object \"C_11\" { } } - /// @use-src 0:\"A\", 1:\"#utility.yul\" + /// @use-src 0:\"A\" object \"C_11_deployed\" { code { /// @src 0:78:158 diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json index f29e4347e..8ff41db27 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json @@ -6,7 +6,7 @@ *=====================================================*/ -/// @use-src 0:\"A\", 1:\"#utility.yul\" +/// @use-src 0:\"A\" object \"C_11\" { code { /// @src 0:78:159 @@ -37,7 +37,7 @@ object \"C_11\" { } } - /// @use-src 0:\"A\", 1:\"#utility.yul\" + /// @use-src 0:\"A\" object \"C_11_deployed\" { code { /// @src 0:78:159 diff --git a/test/cmdlineTests/yul_string_format_ascii_long/output.json b/test/cmdlineTests/yul_string_format_ascii_long/output.json index d701ce599..8c7c8b38a 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/output.json @@ -6,7 +6,7 @@ *=====================================================*/ -/// @use-src 0:\"A\", 1:\"#utility.yul\" +/// @use-src 0:\"A\" object \"C_11\" { code { /// @src 0:78:243 @@ -37,7 +37,7 @@ object \"C_11\" { } } - /// @use-src 0:\"A\", 1:\"#utility.yul\" + /// @use-src 0:\"A\" object \"C_11_deployed\" { code { /// @src 0:78:243 diff --git a/test/cmdlineTests/yul_string_format_hex/output.json b/test/cmdlineTests/yul_string_format_hex/output.json index ac437ccec..58f2d628a 100644 --- a/test/cmdlineTests/yul_string_format_hex/output.json +++ b/test/cmdlineTests/yul_string_format_hex/output.json @@ -6,7 +6,7 @@ *=====================================================*/ -/// @use-src 0:\"A\", 1:\"#utility.yul\" +/// @use-src 0:\"A\" object \"C_11\" { code { /// @src 0:78:159 @@ -37,7 +37,7 @@ object \"C_11\" { } } - /// @use-src 0:\"A\", 1:\"#utility.yul\" + /// @use-src 0:\"A\" object \"C_11_deployed\" { code { /// @src 0:78:159 From 5093cff7aea787021f8735242f2950d99d1fc62e Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 6 Sep 2021 18:26:30 +0200 Subject: [PATCH 025/232] Rename source location function. --- libsolidity/codegen/ir/Common.cpp | 6 +-- libsolidity/codegen/ir/Common.h | 7 ++-- libsolidity/codegen/ir/IRGenerator.cpp | 38 +++++++++---------- libsolidity/codegen/ir/IRGenerator.h | 2 +- .../codegen/ir/IRGeneratorForStatements.cpp | 4 +- 5 files changed, 29 insertions(+), 28 deletions(-) diff --git a/libsolidity/codegen/ir/Common.cpp b/libsolidity/codegen/ir/Common.cpp index 6aaecad81..772e9b53e 100644 --- a/libsolidity/codegen/ir/Common.cpp +++ b/libsolidity/codegen/ir/Common.cpp @@ -127,7 +127,7 @@ string IRNames::zeroValue(Type const& _type, string const& _variableName) return "zero_" + _type.identifier() + _variableName; } -string sourceLocationComment(langutil::SourceLocation const& _location, IRGenerationContext& _context) +string dispenseLocationComment(langutil::SourceLocation const& _location, IRGenerationContext& _context) { solAssert(_location.sourceName, ""); _context.markSourceUsed(*_location.sourceName); @@ -139,9 +139,9 @@ string sourceLocationComment(langutil::SourceLocation const& _location, IRGenera + to_string(_location.end); } -string sourceLocationComment(ASTNode const& _node, IRGenerationContext& _context) +string dispenseLocationComment(ASTNode const& _node, IRGenerationContext& _context) { - return sourceLocationComment(_node.location(), _context); + return dispenseLocationComment(_node.location(), _context); } } diff --git a/libsolidity/codegen/ir/Common.h b/libsolidity/codegen/ir/Common.h index ab5372286..3a860f8f1 100644 --- a/libsolidity/codegen/ir/Common.h +++ b/libsolidity/codegen/ir/Common.h @@ -71,10 +71,11 @@ struct IRNames /** * @returns a source location comment in the form of - * `/// @src ::`. + * `/// @src ::` + * and marks the source index as used. */ -std::string sourceLocationComment(langutil::SourceLocation const& _location, IRGenerationContext& _context); -std::string sourceLocationComment(ASTNode const& _node, IRGenerationContext& _context); +std::string dispenseLocationComment(langutil::SourceLocation const& _location, IRGenerationContext& _context); +std::string dispenseLocationComment(ASTNode const& _node, IRGenerationContext& _context); } diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 8acb6f599..5affb1c08 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -179,7 +179,7 @@ string IRGenerator::generate( m_context.registerImmutableVariable(*var); t("CreationObject", IRNames::creationObject(_contract)); - t("sourceLocationCommentCreation", sourceLocationComment(_contract)); + t("sourceLocationCommentCreation", dispenseLocationComment(_contract)); t("library", _contract.isLibrary()); FunctionDefinition const* constructor = _contract.constructor(); @@ -220,7 +220,7 @@ string IRGenerator::generate( // Do not register immutables to avoid assignment. t("DeployedObject", IRNames::deployedObject(_contract)); - t("sourceLocationCommentDeployed", sourceLocationComment(_contract)); + t("sourceLocationCommentDeployed", dispenseLocationComment(_contract)); t("library_address", IRNames::libraryAddressImmutable()); t("dispatch", dispatchRoutine(_contract)); set deployedFunctionList = generateQueuedFunctions(); @@ -294,7 +294,7 @@ InternalDispatchMap IRGenerator::generateInternalDispatchFunctions(ContractDefin } )"); - templ("sourceLocationComment", sourceLocationComment(_contract)); + templ("sourceLocationComment", dispenseLocationComment(_contract)); templ("functionName", funName); templ("panic", m_utils.panicFunction(PanicCode::InvalidInternalFunction)); templ("in", suffixedVariableNameList("in_", 0, arity.in)); @@ -347,10 +347,10 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function) )"); - t("sourceLocationComment", sourceLocationComment(_function)); + t("sourceLocationComment", dispenseLocationComment(_function)); t( "contractSourceLocationComment", - sourceLocationComment(m_context.mostDerivedContract()) + dispenseLocationComment(m_context.mostDerivedContract()) ); t("functionName", functionName); @@ -436,10 +436,10 @@ string IRGenerator::generateModifier( _modifierInvocation.name().annotation().referencedDeclaration ); solAssert(modifier, ""); - t("sourceLocationComment", sourceLocationComment(*modifier)); + t("sourceLocationComment", dispenseLocationComment(*modifier)); t( "contractSourceLocationComment", - sourceLocationComment(m_context.mostDerivedContract()) + dispenseLocationComment(m_context.mostDerivedContract()) ); switch (*_modifierInvocation.name().annotation().requiredLookup) @@ -499,10 +499,10 @@ string IRGenerator::generateFunctionWithModifierInner(FunctionDefinition const& } )"); - t("sourceLocationComment", sourceLocationComment(_function)); + t("sourceLocationComment", dispenseLocationComment(_function)); t( "contractSourceLocationComment", - sourceLocationComment(m_context.mostDerivedContract()) + dispenseLocationComment(m_context.mostDerivedContract()) ); t("functionName", functionName); vector retParams; @@ -547,10 +547,10 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) } )") - ("sourceLocationComment", sourceLocationComment(_varDecl)) + ("sourceLocationComment", dispenseLocationComment(_varDecl)) ( "contractSourceLocationComment", - sourceLocationComment(m_context.mostDerivedContract()) + dispenseLocationComment(m_context.mostDerivedContract()) ) ("functionName", functionName) ("id", to_string(_varDecl.id())) @@ -566,10 +566,10 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) } )") - ("sourceLocationComment", sourceLocationComment(_varDecl)) + ("sourceLocationComment", dispenseLocationComment(_varDecl)) ( "contractSourceLocationComment", - sourceLocationComment(m_context.mostDerivedContract()) + dispenseLocationComment(m_context.mostDerivedContract()) ) ("functionName", functionName) ("constantValueFunction", IRGeneratorForStatements(m_context, m_utils).constantValueFunction(_varDecl)) @@ -692,10 +692,10 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) ("params", joinHumanReadable(parameters)) ("retVariables", joinHumanReadable(returnVariables)) ("code", std::move(code)) - ("sourceLocationComment", sourceLocationComment(_varDecl)) + ("sourceLocationComment", dispenseLocationComment(_varDecl)) ( "contractSourceLocationComment", - sourceLocationComment(m_context.mostDerivedContract()) + dispenseLocationComment(m_context.mostDerivedContract()) ) .render(); }); @@ -818,14 +818,14 @@ void IRGenerator::generateConstructors(ContractDefinition const& _contract) for (ASTPointer const& varDecl: contract->constructor()->parameters()) params += m_context.addLocalVariable(*varDecl).stackSlots(); - t("sourceLocationComment", sourceLocationComment( + t("sourceLocationComment", dispenseLocationComment( contract->constructor() ? dynamic_cast(*contract->constructor()) : dynamic_cast(*contract) )); t( "contractSourceLocationComment", - sourceLocationComment(m_context.mostDerivedContract()) + dispenseLocationComment(m_context.mostDerivedContract()) ); t("params", joinHumanReadable(params)); @@ -1073,7 +1073,7 @@ void IRGenerator::resetContext(ContractDefinition const& _contract, ExecutionCon m_context.addStateVariable(*get<0>(var), get<1>(var), get<2>(var)); } -string IRGenerator::sourceLocationComment(ASTNode const& _node) +string IRGenerator::dispenseLocationComment(ASTNode const& _node) { - return ::sourceLocationComment(_node, m_context); + return ::dispenseLocationComment(_node, m_context); } diff --git a/libsolidity/codegen/ir/IRGenerator.h b/libsolidity/codegen/ir/IRGenerator.h index 9ec574752..d5c2cbaec 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -119,7 +119,7 @@ private: void resetContext(ContractDefinition const& _contract, ExecutionContext _context); - std::string sourceLocationComment(ASTNode const& _node); + std::string dispenseLocationComment(ASTNode const& _node); langutil::EVMVersion const m_evmVersion; OptimiserSettings const m_optimiserSettings; diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 66e54e893..8f281a10e 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -217,7 +217,7 @@ std::ostringstream& IRGeneratorForStatementsBase::appendCode(bool _addLocationCo m_currentLocation.isValid() && m_lastLocation != m_currentLocation ) - m_code << sourceLocationComment(m_currentLocation, m_context) << "\n"; + m_code << dispenseLocationComment(m_currentLocation, m_context) << "\n"; m_lastLocation = m_currentLocation; @@ -340,7 +340,7 @@ string IRGeneratorForStatements::constantValueFunction(VariableDeclaration const := } )"); - templ("sourceLocationComment", sourceLocationComment(_constant, m_context)); + templ("sourceLocationComment", dispenseLocationComment(_constant, m_context)); templ("functionName", functionName); IRGeneratorForStatements generator(m_context, m_utils); solAssert(_constant.value(), ""); From f4d1044331763bc46cc4bd91e335f29d60d403d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 6 Sep 2021 21:03:21 +0200 Subject: [PATCH 026/232] Don't try to remove `soljson.js` after running `npm install` in cloned solc-js repo --- scripts/solc-bin/bytecode_reports_for_modified_binaries.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/solc-bin/bytecode_reports_for_modified_binaries.sh b/scripts/solc-bin/bytecode_reports_for_modified_binaries.sh index 006ae475e..3401c127f 100755 --- a/scripts/solc-bin/bytecode_reports_for_modified_binaries.sh +++ b/scripts/solc-bin/bytecode_reports_for_modified_binaries.sh @@ -109,7 +109,6 @@ cd "$tmp_dir" git clone https://github.com/ethereum/solc-js.git "$solcjs_dir" cd "$solcjs_dir" npm install -rm soljson.js cd "${solc_bin_dir}/${platform}/" echo "Commit range: ${base_ref}..${top_ref}" From 3fe52d98694b1a27fd2736619fc5c1bce7d18156 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 7 Sep 2021 15:04:12 +0200 Subject: [PATCH 027/232] Run the optimizer only once. --- Changelog.md | 1 + libevmasm/Assembly.cpp | 10 +++++++--- libevmasm/Assembly.h | 6 +++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Changelog.md b/Changelog.md index 5bbd686a3..fc61a1b19 100644 --- a/Changelog.md +++ b/Changelog.md @@ -15,6 +15,7 @@ Compiler Features: Bugfixes: + * Opcode Optimizer: Prevent the optimizer from running multiple times to avoid potential bytecode differences for referenced code. * Name Resolver: Fix that when importing an aliased symbol using ``import {AliasedName} from "a.sol"`` it would use the original name of the symbol and not the aliased one. * SMTChecker: Fix false negative caused by ``push`` on storage array references returned by internal functions. * SMTChecker: Fix false positive in external calls from constructors. diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index dad9635d7..ef465cf35 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -409,18 +409,21 @@ Assembly& Assembly::optimise(OptimiserSettings const& _settings) return *this; } -map Assembly::optimiseInternal( +map const& Assembly::optimiseInternal( OptimiserSettings const& _settings, std::set _tagsReferencedFromOutside ) { + if (m_tagReplacements) + return *m_tagReplacements; + // Run optimisation for sub-assemblies. for (size_t subId = 0; subId < m_subs.size(); ++subId) { OptimiserSettings settings = _settings; // Disable creation mode for sub-assemblies. settings.isCreation = false; - map subTagReplacements = m_subs[subId]->optimiseInternal( + map const& subTagReplacements = m_subs[subId]->optimiseInternal( settings, JumpdestRemover::referencedTags(m_items, subId) ); @@ -546,7 +549,8 @@ map Assembly::optimiseInternal( *this ); - return tagReplacements; + m_tagReplacements = move(tagReplacements); + return *m_tagReplacements; } LinkerObject const& Assembly::assemble() const diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index 4a0779ef7..732aa14a1 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -165,7 +165,7 @@ protected: /// Does the same operations as @a optimise, but should only be applied to a sub and /// returns the replaced tags. Also takes an argument containing the tags of this assembly /// that are referenced in a super-assembly. - std::map optimiseInternal(OptimiserSettings const& _settings, std::set _tagsReferencedFromOutside); + std::map const& optimiseInternal(OptimiserSettings const& _settings, std::set _tagsReferencedFromOutside); unsigned bytesRequired(unsigned subTagSize) const; @@ -210,6 +210,10 @@ protected: /// This map is used only for sub-assemblies which are not direct sub-assemblies (where path is having more than one value). std::map, size_t> m_subPaths; + /// Contains the tag replacements relevant for super-assemblies. + /// If set, it means the optimizer has run and we will not run it again. + std::optional> m_tagReplacements; + mutable LinkerObject m_assembledObject; mutable std::vector m_tagPositionsInBytecode; From 6e2fe1e340efedb599005507eb0c7f822b1a82cd Mon Sep 17 00:00:00 2001 From: Leo Alt Date: Mon, 6 Sep 2021 23:54:14 +0200 Subject: [PATCH 028/232] [SMTChecker] Cleanup spurious messages about TypeTypes --- libsolidity/formal/SMTEncoder.cpp | 18 ++++++++++++++++++ libsolidity/formal/SMTEncoder.h | 1 + .../smtCheckerTests/abi/abi_decode_1_tuple.sol | 2 -- .../smtCheckerTests/abi/abi_decode_array.sol | 14 -------------- .../special/abi_decode_memory_v2.sol | 3 --- .../special/abi_decode_simple.sol | 2 -- .../smtCheckerTests/types/abi_type_type_1.sol | 10 ++++++++++ .../smtCheckerTests/types/abi_type_type_2.sol | 9 +++++++++ 8 files changed, 38 insertions(+), 21 deletions(-) create mode 100644 test/libsolidity/smtCheckerTests/types/abi_type_type_1.sol create mode 100644 test/libsolidity/smtCheckerTests/types/abi_type_type_2.sol diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index 411fa2757..fdf5db5ca 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -560,6 +560,24 @@ bool SMTEncoder::visit(Conditional const& _op) return false; } +bool SMTEncoder::visit(FunctionCall const& _funCall) +{ + auto functionCallKind = *_funCall.annotation().kind; + if (functionCallKind != FunctionCallKind::FunctionCall) + return true; + + FunctionType const& funType = dynamic_cast(*_funCall.expression().annotation().type); + // We do not want to visit the TypeTypes in the second argument of `abi.decode`. + // Those types are checked/used in SymbolicState::buildABIFunctions. + if (funType.kind() == FunctionType::Kind::ABIDecode) + { + if (auto arg = _funCall.arguments().front()) + arg->accept(*this); + return false; + } + return true; +} + void SMTEncoder::endVisit(FunctionCall const& _funCall) { auto functionCallKind = *_funCall.annotation().kind; diff --git a/libsolidity/formal/SMTEncoder.h b/libsolidity/formal/SMTEncoder.h index 28270acc0..a567a0fbf 100644 --- a/libsolidity/formal/SMTEncoder.h +++ b/libsolidity/formal/SMTEncoder.h @@ -152,6 +152,7 @@ protected: bool visit(BinaryOperation const& _node) override; void endVisit(BinaryOperation const& _node) override; bool visit(Conditional const& _node) override; + bool visit(FunctionCall const& _node) override; void endVisit(FunctionCall const& _node) override; bool visit(ModifierInvocation const& _node) override; void endVisit(Identifier const& _node) override; diff --git a/test/libsolidity/smtCheckerTests/abi/abi_decode_1_tuple.sol b/test/libsolidity/smtCheckerTests/abi/abi_decode_1_tuple.sol index e9c4e2043..d43f11b68 100644 --- a/test/libsolidity/smtCheckerTests/abi/abi_decode_1_tuple.sol +++ b/test/libsolidity/smtCheckerTests/abi/abi_decode_1_tuple.sol @@ -6,5 +6,3 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 8364: (116-125): Assertion checker does not yet implement type type(uint256[] memory) -// Warning 8364: (115-126): Assertion checker does not yet implement type type(uint256[] memory) diff --git a/test/libsolidity/smtCheckerTests/abi/abi_decode_array.sol b/test/libsolidity/smtCheckerTests/abi/abi_decode_array.sol index 998503eb8..3c88329a3 100644 --- a/test/libsolidity/smtCheckerTests/abi/abi_decode_array.sol +++ b/test/libsolidity/smtCheckerTests/abi/abi_decode_array.sol @@ -32,20 +32,6 @@ contract C { // SMTEngine: all // SMTIgnoreCex: yes // ---- -// Warning 8364: (162-168): Assertion checker does not yet implement type type(uint256[] memory) -// Warning 8364: (170-176): Assertion checker does not yet implement type type(uint256[] memory) -// Warning 8364: (283-289): Assertion checker does not yet implement type type(uint256[] memory) -// Warning 8364: (291-297): Assertion checker does not yet implement type type(uint256[] memory) -// Warning 8364: (532-538): Assertion checker does not yet implement type type(uint256[] memory) -// Warning 8364: (540-546): Assertion checker does not yet implement type type(uint256[] memory) -// Warning 8364: (548-554): Assertion checker does not yet implement type type(uint256[] memory) -// Warning 8364: (769-775): Assertion checker does not yet implement type type(uint256[] memory) -// Warning 8364: (769-777): Assertion checker does not yet implement type type(uint256[] memory[] memory) -// Warning 8364: (779-785): Assertion checker does not yet implement type type(uint256[] memory) -// Warning 8364: (779-787): Assertion checker does not yet implement type type(uint256[] memory[] memory) -// Warning 8364: (779-789): Assertion checker does not yet implement type type(uint256[] memory[] memory[] memory) -// Warning 8364: (989-995): Assertion checker does not yet implement type type(uint256[] memory) -// Warning 8364: (997-1003): Assertion checker does not yet implement type type(uint256[] memory) // Warning 1218: (1009-1037): CHC: Error trying to invoke SMT solver. // Warning 1218: (1056-1084): CHC: Error trying to invoke SMT solver. // Warning 1218: (1103-1131): CHC: Error trying to invoke SMT solver. diff --git a/test/libsolidity/smtCheckerTests/special/abi_decode_memory_v2.sol b/test/libsolidity/smtCheckerTests/special/abi_decode_memory_v2.sol index a2d864b52..b9613a58c 100644 --- a/test/libsolidity/smtCheckerTests/special/abi_decode_memory_v2.sol +++ b/test/libsolidity/smtCheckerTests/special/abi_decode_memory_v2.sol @@ -9,6 +9,3 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 8364: (183-189): Assertion checker does not yet implement type type(uint256[] memory) -// Warning 8364: (183-192): Assertion checker does not yet implement type type(uint256[] memory[2] memory) -// Warning 8364: (173-174): Assertion checker does not yet implement type type(struct C.S storage pointer) diff --git a/test/libsolidity/smtCheckerTests/special/abi_decode_simple.sol b/test/libsolidity/smtCheckerTests/special/abi_decode_simple.sol index 641b59440..bb82c659e 100644 --- a/test/libsolidity/smtCheckerTests/special/abi_decode_simple.sol +++ b/test/libsolidity/smtCheckerTests/special/abi_decode_simple.sol @@ -13,6 +13,4 @@ contract C { // Warning 2072: (82-86): Unused local variable. // Warning 2072: (140-150): Unused local variable. // Warning 2072: (152-156): Unused local variable. -// Warning 8364: (123-124): Assertion checker does not yet implement type type(contract C) -// Warning 8364: (193-194): Assertion checker does not yet implement type type(contract C) // Warning 6328: (220-236): CHC: Assertion violation happens here.\nCounterexample:\n\na1 = 2437\nb1 = 10\nc1 = 9\na2 = 2437\nb2 = 10\nc2 = 9\n\nTransaction trace:\nC.constructor()\nC.f(data) diff --git a/test/libsolidity/smtCheckerTests/types/abi_type_type_1.sol b/test/libsolidity/smtCheckerTests/types/abi_type_type_1.sol new file mode 100644 index 000000000..d4207bc86 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/abi_type_type_1.sol @@ -0,0 +1,10 @@ +contract C { + function f(bytes memory d) public pure { + (bool a, uint x) = abi.decode(d, (bool, uint)); + assert(a == (x == 2)); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (107-128): CHC: Assertion violation happens here.\nCounterexample:\n\na = true\nx = 1\n\nTransaction trace:\nC.constructor()\nC.f(d) diff --git a/test/libsolidity/smtCheckerTests/types/abi_type_type_2.sol b/test/libsolidity/smtCheckerTests/types/abi_type_type_2.sol new file mode 100644 index 000000000..e1730fedd --- /dev/null +++ b/test/libsolidity/smtCheckerTests/types/abi_type_type_2.sol @@ -0,0 +1,9 @@ +contract C { + function f(bytes memory d) public pure { + assert(abi.decode(d, (bool))); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (57-86): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f(d) From a7612ce8736b57ca3469e272ecc74eb016ca9462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 30 Aug 2021 20:06:39 +0200 Subject: [PATCH 029/232] Move the function for creating code snippets used next to source locations in assembly to liblangutil --- libevmasm/Assembly.cpp | 12 ++---------- liblangutil/CharStream.cpp | 16 ++++++++++++++++ liblangutil/CharStream.h | 9 +++++++++ 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index dad9635d7..c1e171221 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -82,16 +83,7 @@ string locationFromSources(StringMap const& _sourceCodes, SourceLocation const& if (it == _sourceCodes.end()) return {}; - string const& source = it->second; - if (static_cast(_location.start) >= source.size()) - return {}; - - string cut = source.substr(static_cast(_location.start), static_cast(_location.end - _location.start)); - auto newLinePos = cut.find_first_of("\n"); - if (newLinePos != string::npos) - cut = cut.substr(0, newLinePos) + "..."; - - return cut; + return CharStream::singleLineSnippet(it->second, _location); } class Functionalizer diff --git a/liblangutil/CharStream.cpp b/liblangutil/CharStream.cpp index 8ab99fca8..748a4a99c 100644 --- a/liblangutil/CharStream.cpp +++ b/liblangutil/CharStream.cpp @@ -128,3 +128,19 @@ string_view CharStream::text(SourceLocation const& _location) const static_cast(_location.end - _location.start) ); } + +string CharStream::singleLineSnippet(string const& _sourceCode, SourceLocation const& _location) +{ + if (!_location.hasText()) + return {}; + + if (static_cast(_location.start) >= _sourceCode.size()) + return {}; + + string cut = _sourceCode.substr(static_cast(_location.start), static_cast(_location.end - _location.start)); + auto newLinePos = cut.find_first_of("\n"); + if (newLinePos != string::npos) + cut = cut.substr(0, newLinePos) + "..."; + + return cut; +} diff --git a/liblangutil/CharStream.h b/liblangutil/CharStream.h index 4b729771f..761cece31 100644 --- a/liblangutil/CharStream.h +++ b/liblangutil/CharStream.h @@ -118,6 +118,15 @@ public: /// Returns an empty string view if the source location does not `hasText()`. std::string_view text(SourceLocation const& _location) const; + /// @returns the first line of the referenced source fragment. If the fragment is longer than + /// one line, appends an ellipsis to indicate that. + std::string singleLineSnippet(SourceLocation const& _location) const + { + return singleLineSnippet(m_source, _location); + } + + static std::string singleLineSnippet(std::string const& _sourceCode, SourceLocation const& _location); + private: std::string m_source; std::string m_name; From 98ab6d91ede089fa11772b184a7970b19b8ed889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 31 Aug 2021 16:01:52 +0200 Subject: [PATCH 030/232] SourceLocation::singleLineSnippet(): Handle \r\n line endings correctly --- liblangutil/CharStream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/liblangutil/CharStream.cpp b/liblangutil/CharStream.cpp index 748a4a99c..3b30bad77 100644 --- a/liblangutil/CharStream.cpp +++ b/liblangutil/CharStream.cpp @@ -138,7 +138,7 @@ string CharStream::singleLineSnippet(string const& _sourceCode, SourceLocation c return {}; string cut = _sourceCode.substr(static_cast(_location.start), static_cast(_location.end - _location.start)); - auto newLinePos = cut.find_first_of("\n"); + auto newLinePos = cut.find_first_of("\n\r"); if (newLinePos != string::npos) cut = cut.substr(0, newLinePos) + "..."; From d3ae9cf71b4944e2753c967da3492eb36e026da9 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Wed, 28 Jul 2021 10:32:59 +0200 Subject: [PATCH 031/232] Added AST node UserDefinedValueType --- libsolidity/ast/AST.cpp | 6 ++++++ libsolidity/ast/AST.h | 31 +++++++++++++++++++++++++++++++ libsolidity/ast/ASTForward.h | 1 + libsolidity/ast/ASTVisitor.h | 4 ++++ libsolidity/ast/AST_accept.h | 20 ++++++++++++++++++++ 5 files changed, 62 insertions(+) diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 6d5e89ce2..3201d60ff 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -335,6 +335,12 @@ TypeNameAnnotation& TypeName::annotation() const return initAnnotation(); } +Type const* UserDefinedValueTypeDefinition::type() const +{ + solAssert(m_underlyingType->annotation().type, ""); + return TypeProvider::typeType(TypeProvider::userDefinedValueType(*this)); +} + Type const* StructDefinition::type() const { solAssert(annotation().recursive.has_value(), "Requested struct type before DeclarationTypeChecker."); diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index f02e93599..e1e5fc596 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -726,6 +726,37 @@ public: Type const* type() const override; }; +/** + * User defined value types, i.e., custom types, for example, `type MyInt is int`. Allows creating a + * zero cost abstraction over value type with stricter type requirements. + */ +class UserDefinedValueTypeDefinition: public Declaration +{ +public: + UserDefinedValueTypeDefinition( + int64_t _id, + SourceLocation const& _location, + ASTPointer _name, + SourceLocation _nameLocation, + ASTPointer _underlyingType + ): + Declaration(_id, _location, _name, std::move(_nameLocation), Visibility::Default), + m_underlyingType(std::move(_underlyingType)) + { + } + + void accept(ASTVisitor& _visitor) override; + void accept(ASTConstVisitor& _visitor) const override; + + Type const* type() const override; + + TypeName const* underlyingType() const { return m_underlyingType.get(); } + +private: + /// The name of the underlying type + ASTPointer m_underlyingType; +}; + /** * Parameter list, used as function parameter list, return list and for try and catch. * None of the parameters is allowed to contain mappings (not even recursively diff --git a/libsolidity/ast/ASTForward.h b/libsolidity/ast/ASTForward.h index 5b73eb3a3..79e6a4ecf 100644 --- a/libsolidity/ast/ASTForward.h +++ b/libsolidity/ast/ASTForward.h @@ -51,6 +51,7 @@ class UsingForDirective; class StructDefinition; class EnumDefinition; class EnumValue; +class UserDefinedValueTypeDefinition; class ParameterList; class FunctionDefinition; class VariableDeclaration; diff --git a/libsolidity/ast/ASTVisitor.h b/libsolidity/ast/ASTVisitor.h index 398387b33..ef03e6339 100644 --- a/libsolidity/ast/ASTVisitor.h +++ b/libsolidity/ast/ASTVisitor.h @@ -61,6 +61,7 @@ public: virtual bool visit(IdentifierPath& _node) { return visitNode(_node); } virtual bool visit(InheritanceSpecifier& _node) { return visitNode(_node); } virtual bool visit(UsingForDirective& _node) { return visitNode(_node); } + virtual bool visit(UserDefinedValueTypeDefinition& _node) { return visitNode(_node); } virtual bool visit(StructDefinition& _node) { return visitNode(_node); } virtual bool visit(EnumDefinition& _node) { return visitNode(_node); } virtual bool visit(EnumValue& _node) { return visitNode(_node); } @@ -116,6 +117,7 @@ public: virtual void endVisit(IdentifierPath& _node) { endVisitNode(_node); } virtual void endVisit(InheritanceSpecifier& _node) { endVisitNode(_node); } virtual void endVisit(UsingForDirective& _node) { endVisitNode(_node); } + virtual void endVisit(UserDefinedValueTypeDefinition& _node) { endVisitNode(_node); } virtual void endVisit(StructDefinition& _node) { endVisitNode(_node); } virtual void endVisit(EnumDefinition& _node) { endVisitNode(_node); } virtual void endVisit(EnumValue& _node) { endVisitNode(_node); } @@ -194,6 +196,7 @@ public: virtual bool visit(InheritanceSpecifier const& _node) { return visitNode(_node); } virtual bool visit(StructDefinition const& _node) { return visitNode(_node); } virtual bool visit(UsingForDirective const& _node) { return visitNode(_node); } + virtual bool visit(UserDefinedValueTypeDefinition const& _node) { return visitNode(_node); } virtual bool visit(EnumDefinition const& _node) { return visitNode(_node); } virtual bool visit(EnumValue const& _node) { return visitNode(_node); } virtual bool visit(ParameterList const& _node) { return visitNode(_node); } @@ -248,6 +251,7 @@ public: virtual void endVisit(IdentifierPath const& _node) { endVisitNode(_node); } virtual void endVisit(InheritanceSpecifier const& _node) { endVisitNode(_node); } virtual void endVisit(UsingForDirective const& _node) { endVisitNode(_node); } + virtual void endVisit(UserDefinedValueTypeDefinition const& _node) { endVisitNode(_node); } virtual void endVisit(StructDefinition const& _node) { endVisitNode(_node); } virtual void endVisit(EnumDefinition const& _node) { endVisitNode(_node); } virtual void endVisit(EnumValue const& _node) { endVisitNode(_node); } diff --git a/libsolidity/ast/AST_accept.h b/libsolidity/ast/AST_accept.h index 075e6fe5c..14ebfe621 100644 --- a/libsolidity/ast/AST_accept.h +++ b/libsolidity/ast/AST_accept.h @@ -164,6 +164,26 @@ void EnumValue::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } +void UserDefinedValueTypeDefinition::accept(ASTConstVisitor& _visitor) const +{ + if (_visitor.visit(*this)) + { + if (m_underlyingType) + m_underlyingType->accept(_visitor); + } + _visitor.endVisit(*this); +} + +void UserDefinedValueTypeDefinition::accept(ASTVisitor& _visitor) +{ + if (_visitor.visit(*this)) + { + if (m_underlyingType) + m_underlyingType->accept(_visitor); + } + _visitor.endVisit(*this); +} + void UsingForDirective::accept(ASTVisitor& _visitor) { if (_visitor.visit(*this)) From 9f7426b4a96d29196a5bbc0be0b28458024f3da8 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Wed, 28 Jul 2021 10:33:19 +0200 Subject: [PATCH 032/232] Implemented parsing for UserDefinedValueType Also added parsing tests. --- libsolidity/parsing/Parser.cpp | 21 +++++++++++++++++++ libsolidity/parsing/Parser.h | 1 + .../parsing/user_defined_value_type.sol | 5 +++++ .../parsing/user_defined_value_type_err.sol | 3 +++ ...ser_defined_value_type_in_function_err.sol | 6 ++++++ 5 files changed, 36 insertions(+) create mode 100644 test/libsolidity/syntaxTests/parsing/user_defined_value_type.sol create mode 100644 test/libsolidity/syntaxTests/parsing/user_defined_value_type_err.sol create mode 100644 test/libsolidity/syntaxTests/parsing/user_defined_value_type_in_function_err.sol diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 3f30a07c9..3f5c975e3 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -113,6 +113,9 @@ ASTPointer Parser::parse(CharStream& _charStream) case Token::Enum: nodes.push_back(parseEnumDefinition()); break; + case Token::Type: + nodes.push_back(parseUserDefinedValueTypeDefinition()); + break; case Token::Function: nodes.push_back(parseFunctionDefinition(true)); break; @@ -364,6 +367,8 @@ ASTPointer Parser::parseContractDefinition() subNodes.push_back(parseStructDefinition()); else if (currentTokenValue == Token::Enum) subNodes.push_back(parseEnumDefinition()); + else if (currentTokenValue == Token::Type) + subNodes.push_back(parseUserDefinedValueTypeDefinition()); else if ( // Workaround because `error` is not a keyword. currentTokenValue == Token::Identifier && @@ -1010,6 +1015,22 @@ ASTPointer Parser::parseUserDefinedTypeName() return nodeFactory.createNode(identifierPath); } +ASTPointer Parser::parseUserDefinedValueTypeDefinition() +{ + ASTNodeFactory nodeFactory(*this); + expectToken(Token::Type); + auto&& [name, nameLocation] = expectIdentifierWithLocation(); + expectToken(Token::Is); + ASTPointer typeName = parseTypeName(); + nodeFactory.markEndPosition(); + expectToken(Token::Semicolon); + return nodeFactory.createNode( + name, + move(nameLocation), + typeName + ); +} + ASTPointer Parser::parseIdentifierPath() { RecursionGuard recursionGuard(*this); diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h index 5374966d7..e656c936d 100644 --- a/libsolidity/parsing/Parser.h +++ b/libsolidity/parsing/Parser.h @@ -95,6 +95,7 @@ private: ASTPointer parseFunctionDefinition(bool _freeFunction = false); ASTPointer parseStructDefinition(); ASTPointer parseEnumDefinition(); + ASTPointer parseUserDefinedValueTypeDefinition(); ASTPointer parseEnumValue(); ASTPointer parseVariableDeclaration( VarDeclParserOptions const& _options = {}, diff --git a/test/libsolidity/syntaxTests/parsing/user_defined_value_type.sol b/test/libsolidity/syntaxTests/parsing/user_defined_value_type.sol new file mode 100644 index 000000000..e4bd137a3 --- /dev/null +++ b/test/libsolidity/syntaxTests/parsing/user_defined_value_type.sol @@ -0,0 +1,5 @@ +type MyInt is uint; + +contract C { + type MyAddress is address; +} diff --git a/test/libsolidity/syntaxTests/parsing/user_defined_value_type_err.sol b/test/libsolidity/syntaxTests/parsing/user_defined_value_type_err.sol new file mode 100644 index 000000000..dc1208bfd --- /dev/null +++ b/test/libsolidity/syntaxTests/parsing/user_defined_value_type_err.sol @@ -0,0 +1,3 @@ +type(MyInt) is uint256; +// ---- +// ParserError 2314: (4-5): Expected identifier but got '(' diff --git a/test/libsolidity/syntaxTests/parsing/user_defined_value_type_in_function_err.sol b/test/libsolidity/syntaxTests/parsing/user_defined_value_type_in_function_err.sol new file mode 100644 index 000000000..6e31db226 --- /dev/null +++ b/test/libsolidity/syntaxTests/parsing/user_defined_value_type_in_function_err.sol @@ -0,0 +1,6 @@ +function f() { + type(uint).max; + type MyInt is int; +} +// ---- +// ParserError 2314: (44-49): Expected ';' but got identifier From 15452371d49f67920a5b260f50049d66545ab454 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Thu, 12 Aug 2021 17:06:38 +0200 Subject: [PATCH 033/232] Types for UserDefinedValueType --- libsolidity/ast/TypeProvider.cpp | 5 +++ libsolidity/ast/TypeProvider.h | 2 ++ libsolidity/ast/Types.cpp | 60 ++++++++++++++++++++++++++++++++ libsolidity/ast/Types.h | 51 ++++++++++++++++++++++++++- 4 files changed, 117 insertions(+), 1 deletion(-) diff --git a/libsolidity/ast/TypeProvider.cpp b/libsolidity/ast/TypeProvider.cpp index ee7a65004..6183493b4 100644 --- a/libsolidity/ast/TypeProvider.cpp +++ b/libsolidity/ast/TypeProvider.cpp @@ -578,3 +578,8 @@ MappingType const* TypeProvider::mapping(Type const* _keyType, Type const* _valu { return createAndGet(_keyType, _valueType); } + +UserDefinedValueType const* TypeProvider::userDefinedValueType(UserDefinedValueTypeDefinition const& _definition) +{ + return createAndGet(_definition); +} diff --git a/libsolidity/ast/TypeProvider.h b/libsolidity/ast/TypeProvider.h index 6cdfdadc6..78b8378ca 100644 --- a/libsolidity/ast/TypeProvider.h +++ b/libsolidity/ast/TypeProvider.h @@ -201,6 +201,8 @@ public: static MappingType const* mapping(Type const* _keyType, Type const* _valueType); + static UserDefinedValueType const* userDefinedValueType(UserDefinedValueTypeDefinition const& _definition); + private: /// Global TypeProvider instance. static TypeProvider& instance() diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 0fe9a728f..c1163156a 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2533,6 +2533,36 @@ unsigned EnumType::memberValue(ASTString const& _member) const solAssert(false, "Requested unknown enum value " + _member); } +Type const& UserDefinedValueType::underlyingType() const +{ + Type const* type = m_definition.underlyingType()->annotation().type; + solAssert(type, ""); + return *type; +} + +string UserDefinedValueType::richIdentifier() const +{ + return "t_userDefinedValueType" + parenthesizeIdentifier(m_definition.name()) + to_string(m_definition.id()); +} + +bool UserDefinedValueType::operator==(Type const& _other) const +{ + if (_other.category() != category()) + return false; + UserDefinedValueType const& other = dynamic_cast(_other); + return other.definition() == definition(); +} + +string UserDefinedValueType::toString(bool /* _short */) const +{ + return "user defined type " + definition().name(); +} + +vector> UserDefinedValueType::makeStackItems() const +{ + return underlyingType().stackItems(); +} + BoolResult TupleType::isImplicitlyConvertibleTo(Type const& _other) const { if (auto tupleType = dynamic_cast(&_other)) @@ -2884,6 +2914,8 @@ string FunctionType::richIdentifier() const case Kind::GasLeft: id += "gasleft"; break; case Kind::Event: id += "event"; break; case Kind::Error: id += "error"; break; + case Kind::Wrap: id += "wrap"; break; + case Kind::Unwrap: id += "unwrap"; break; case Kind::SetGas: id += "setgas"; break; case Kind::SetValue: id += "setvalue"; break; case Kind::BlockHash: id += "blockhash"; break; @@ -3754,6 +3786,34 @@ MemberList::MemberMap TypeType::nativeMembers(ASTNode const* _currentScope) cons for (ASTPointer const& enumValue: enumDef.members()) members.emplace_back(enumValue.get(), enumType); } + else if (m_actualType->category() == Category::UserDefinedValueType) + { + auto& userDefined = dynamic_cast(*m_actualType); + members.emplace_back( + "wrap", + TypeProvider::function( + TypePointers{&userDefined.underlyingType()}, + TypePointers{&userDefined}, + strings{string{}}, + strings{string{}}, + FunctionType::Kind::Wrap, + false, /*_arbitraryParameters */ + StateMutability::Pure + ) + ); + members.emplace_back( + "unwrap", + TypeProvider::function( + TypePointers{&userDefined}, + TypePointers{&userDefined.underlyingType()}, + strings{string{}}, + strings{string{}}, + FunctionType::Kind::Unwrap, + false, /* _arbitraryParameters */ + StateMutability::Pure + ) + ); + } else if ( auto const* arrayType = dynamic_cast(m_actualType); arrayType && arrayType->isByteArray() diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 57f5201f6..b092628fb 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -174,7 +174,7 @@ public: enum class Category { Address, Integer, RationalNumber, StringLiteral, Bool, FixedPoint, Array, ArraySlice, - FixedBytes, Contract, Struct, Function, Enum, Tuple, + FixedBytes, Contract, Struct, Function, Enum, UserDefinedValueType, Tuple, Mapping, TypeType, Modifier, Magic, Module, InaccessibleDynamic }; @@ -1082,6 +1082,53 @@ private: EnumDefinition const& m_enum; }; +/** + * The type of a UserDefinedValueType. + */ +class UserDefinedValueType: public Type +{ +public: + explicit UserDefinedValueType(UserDefinedValueTypeDefinition const& _definition): + m_definition(_definition) + {} + + Category category() const override { return Category::UserDefinedValueType; } + Type const& underlyingType() const; + UserDefinedValueTypeDefinition const& definition() const { return m_definition; } + + TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; } + Type const* encodingType() const override { return &underlyingType(); } + TypeResult interfaceType(bool /* _inLibrary */) const override {return &underlyingType(); } + std::string richIdentifier() const override; + bool operator==(Type const& _other) const override; + + unsigned calldataEncodedSize(bool _padded) const override { return underlyingType().calldataEncodedSize(_padded); } + + bool leftAligned() const override { return underlyingType().leftAligned(); } + bool canBeStored() const override { return underlyingType().canBeStored(); } + u256 storageSize() const override { return underlyingType().storageSize(); } + bool isValueType() const override + { + solAssert(underlyingType().isValueType(), ""); + return true; + } + bool nameable() const override + { + solAssert(underlyingType().nameable(), ""); + return true; + } + + std::string toString(bool _short) const override; + std::string canonicalName() const override { solAssert(false, ""); } + std::string signatureInExternalFunction(bool) const override { solAssert(false, ""); } + +protected: + std::vector> makeStackItems() const override; + +private: + UserDefinedValueTypeDefinition const& m_definition; +}; + /** * Type that can hold a finite sequence of values of different types. * In some cases, the components are empty pointers (when used as placeholders). @@ -1150,6 +1197,8 @@ public: RIPEMD160, ///< CALL to special contract for ripemd160 Event, ///< syntactic sugar for LOG* Error, ///< creating an error instance in revert or require + Wrap, ///< customType.wrap(...) for user defined value types + Unwrap, ///< customType.unwrap(...) for user defined value types SetGas, ///< modify the default gas value for the function call SetValue, ///< modify the default value transfer for the function call BlockHash, ///< BLOCKHASH From 0647039864120b6a267f072870770975c4dd24e1 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 16 Aug 2021 14:43:05 +0200 Subject: [PATCH 034/232] DeclarationTypeChecker for UserDefinedValueTypes - Checks for repetitions. - Assigns types. - Checks if the 'actual type' is an elementary type name. - Checks if the 'actual type' is a value type. Also added tests. --- .../analysis/DeclarationTypeChecker.cpp | 26 +++++++++++++++++++ libsolidity/analysis/DeclarationTypeChecker.h | 1 + .../userDefinedValueType/all_value_types.sol | 12 +++++++++ .../userDefinedValueType/conversion_err.sol | 6 +++++ .../name_conflict_contract_warning.sol | 6 +++++ .../name_conflict_err.sol | 9 +++++++ .../non_value_type_bytes.sol | 3 +++ .../non_value_type_contract_err.sol | 4 +++ .../non_value_type_function_err.sol | 3 +++ .../non_value_type_mapping_err.sol | 3 +++ .../non_value_type_string_err.sol | 3 +++ .../non_value_type_struct_err.sol | 7 +++++ .../userDefinedValueType/recursive_err.sol | 4 +++ .../recursive_function_paramter_err.sol | 3 +++ .../userDefinedValueType/reference.sol | 13 ++++++++++ .../userDefinedValueType/repetition_err.sol | 7 +++++ .../self_reference_err.sol | 3 +++ 17 files changed, 113 insertions(+) create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/all_value_types.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/conversion_err.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/name_conflict_contract_warning.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/name_conflict_err.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_bytes.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_contract_err.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_function_err.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_mapping_err.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_string_err.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_struct_err.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/recursive_err.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/recursive_function_paramter_err.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/reference.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/repetition_err.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/self_reference_err.sol diff --git a/libsolidity/analysis/DeclarationTypeChecker.cpp b/libsolidity/analysis/DeclarationTypeChecker.cpp index c184e11df..f67d7d501 100644 --- a/libsolidity/analysis/DeclarationTypeChecker.cpp +++ b/libsolidity/analysis/DeclarationTypeChecker.cpp @@ -140,6 +140,30 @@ bool DeclarationTypeChecker::visit(StructDefinition const& _struct) return false; } +void DeclarationTypeChecker::endVisit(UserDefinedValueTypeDefinition const& _userDefined) +{ + TypeName const* typeName = _userDefined.underlyingType(); + solAssert(typeName, ""); + if (!dynamic_cast(typeName)) + m_errorReporter.fatalTypeError( + 8657_error, + typeName->location(), + "The underlying type for a user defined value type has to be an elementary value type." + ); + + Type const* type = typeName->annotation().type; + solAssert(type, ""); + solAssert(!dynamic_cast(type), ""); + if (!type->isValueType()) + m_errorReporter.typeError( + 8129_error, + _userDefined.location(), + "The underlying type of the user defined value type \"" + + _userDefined.name() + + "\" is not a value type." + ); +} + void DeclarationTypeChecker::endVisit(UserDefinedTypeName const& _typeName) { if (_typeName.annotation().type) @@ -158,6 +182,8 @@ void DeclarationTypeChecker::endVisit(UserDefinedTypeName const& _typeName) _typeName.annotation().type = TypeProvider::enumType(*enumDef); else if (ContractDefinition const* contract = dynamic_cast(declaration)) _typeName.annotation().type = TypeProvider::contract(*contract); + else if (auto userDefinedValueType = dynamic_cast(declaration)) + _typeName.annotation().type = TypeProvider::userDefinedValueType(*userDefinedValueType); else { _typeName.annotation().type = TypeProvider::emptyTuple(); diff --git a/libsolidity/analysis/DeclarationTypeChecker.h b/libsolidity/analysis/DeclarationTypeChecker.h index d327d4296..cb887c845 100644 --- a/libsolidity/analysis/DeclarationTypeChecker.h +++ b/libsolidity/analysis/DeclarationTypeChecker.h @@ -60,6 +60,7 @@ private: void endVisit(VariableDeclaration const& _variable) override; bool visit(EnumDefinition const& _enum) override; bool visit(StructDefinition const& _struct) override; + void endVisit(UserDefinedValueTypeDefinition const& _userDefined) override; bool visit(UsingForDirective const& _usingForDirective) override; bool visit(InheritanceSpecifier const& _inheritanceSpecifier) override; diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/all_value_types.sol b/test/libsolidity/syntaxTests/userDefinedValueType/all_value_types.sol new file mode 100644 index 000000000..3388c1976 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/all_value_types.sol @@ -0,0 +1,12 @@ +type MyAddress is address; +type MyAddressPayable is address payable; +type MyInt is int; +type MyUInt is uint; +type MyInt128 is int128; +type MyUInt128 is uint128; +// TODO add fixed point type, when it's implemented +type MyFixedBytes32 is bytes32; +type MyFixedBytes1 is bytes1; +type MyBool is bool; +/// test to see if having NatSpec causes issues +type redundantNatSpec is bytes2; diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/conversion_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/conversion_err.sol new file mode 100644 index 000000000..33c81aee5 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/conversion_err.sol @@ -0,0 +1,6 @@ +type MyAddress is address; +function f() { + MyAddress a = MyAddress(5, 2); +} +// ---- +// TypeError 2558: (60-75): Exactly one argument expected for explicit type conversion. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/name_conflict_contract_warning.sol b/test/libsolidity/syntaxTests/userDefinedValueType/name_conflict_contract_warning.sol new file mode 100644 index 000000000..8c5306bc4 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/name_conflict_contract_warning.sol @@ -0,0 +1,6 @@ +type MyAddress is address; +contract C { + type MyAddress is address; +} +// ---- +// Warning 2519: (44-70): This declaration shadows an existing declaration. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/name_conflict_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/name_conflict_err.sol new file mode 100644 index 000000000..6573111ea --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/name_conflict_err.sol @@ -0,0 +1,9 @@ +type MyInt is int; +type MyInt is address; +contract C { + type MyAddress is address; + type MyAddress is address; +} +// ---- +// DeclarationError 2333: (19-41): Identifier already declared. +// DeclarationError 2333: (90-116): Identifier already declared. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_bytes.sol b/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_bytes.sol new file mode 100644 index 000000000..2bb6c5809 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_bytes.sol @@ -0,0 +1,3 @@ +type MyBytes is bytes; +// ---- +// TypeError 8129: (0-22): The underlying type of the user defined value type "MyBytes" is not a value type. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_contract_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_contract_err.sol new file mode 100644 index 000000000..5a86e92f9 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_contract_err.sol @@ -0,0 +1,4 @@ +contract C {} +type MyContract is C; +// ---- +// TypeError 8657: (33-34): The underlying type for a user defined value type has to be an elementary value type. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_function_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_function_err.sol new file mode 100644 index 000000000..78d9c7043 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_function_err.sol @@ -0,0 +1,3 @@ +type MyFunction is function(uint) returns (uint); +// ---- +// TypeError 8657: (19-49): The underlying type for a user defined value type has to be an elementary value type. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_mapping_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_mapping_err.sol new file mode 100644 index 000000000..9f894c521 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_mapping_err.sol @@ -0,0 +1,3 @@ +type MyInt is mapping(uint => uint); +// ---- +// TypeError 8657: (14-35): The underlying type for a user defined value type has to be an elementary value type. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_string_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_string_err.sol new file mode 100644 index 000000000..b44b23bdb --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_string_err.sol @@ -0,0 +1,3 @@ +type MyString is string; +// ---- +// TypeError 8129: (0-24): The underlying type of the user defined value type "MyString" is not a value type. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_struct_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_struct_err.sol new file mode 100644 index 000000000..3a713a887 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/non_value_type_struct_err.sol @@ -0,0 +1,7 @@ +struct S {uint x;} + +contract C { + type MyType is S; +} +// ---- +// TypeError 8657: (52-53): The underlying type for a user defined value type has to be an elementary value type. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/recursive_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/recursive_err.sol new file mode 100644 index 000000000..4130edde5 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/recursive_err.sol @@ -0,0 +1,4 @@ +type MyInt1 is MyInt2; +type MyInt2 is MyInt1; +// ---- +// TypeError 8657: (15-21): The underlying type for a user defined value type has to be an elementary value type. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/recursive_function_paramter_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/recursive_function_paramter_err.sol new file mode 100644 index 000000000..52e99311e --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/recursive_function_paramter_err.sol @@ -0,0 +1,3 @@ +type MyFunction is function(MyFunction) external returns(MyFunction); +// ---- +// TypeError 8657: (19-69): The underlying type for a user defined value type has to be an elementary value type. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/reference.sol b/test/libsolidity/syntaxTests/userDefinedValueType/reference.sol new file mode 100644 index 000000000..81a1ae8af --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/reference.sol @@ -0,0 +1,13 @@ +library L { + type MyInt is int; +} + +contract C { + L.MyInt a; + type MyInt is int8; +} + +contract D is C { + C.MyInt b; + L.MyInt c; +} diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/repetition_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/repetition_err.sol new file mode 100644 index 000000000..d9fc18d7f --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/repetition_err.sol @@ -0,0 +1,7 @@ +type MyInt is int; +type MyInt is int; +type MyAddress is address; +type MyAddress is uint; +// ---- +// DeclarationError 2333: (19-37): Identifier already declared. +// DeclarationError 2333: (65-88): Identifier already declared. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/self_reference_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/self_reference_err.sol new file mode 100644 index 000000000..20c657c73 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/self_reference_err.sol @@ -0,0 +1,3 @@ +type MyInt is MyInt; +// ---- +// TypeError 8657: (14-19): The underlying type for a user defined value type has to be an elementary value type. From ce75790e8de8c070b9dc1dc9ea0292003d8442ea Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Tue, 7 Sep 2021 18:23:53 +0200 Subject: [PATCH 035/232] TypeChecker: added checks for `wrap` and `unwrap` For user defined value types and also added a test case. --- libsolidity/analysis/TypeChecker.cpp | 7 +++++++ .../wrap_unwrap_calls_err.sol | 16 ++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_calls_err.sol diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 61c4208af..30159e9e5 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -2481,6 +2481,13 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) returnTypes = functionType->returnParameterTypes(); break; } + case FunctionType::Kind::Wrap: + case FunctionType::Kind::Unwrap: + { + typeCheckFunctionGeneralChecks(_functionCall, functionType); + returnTypes = functionType->returnParameterTypes(); + break; + } default: { typeCheckFunctionCall(_functionCall, functionType); diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_calls_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_calls_err.sol new file mode 100644 index 000000000..470a42b0a --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_calls_err.sol @@ -0,0 +1,16 @@ +type MyInt is int; +function f() { + MyInt.wrap(5, 6, 7); + MyInt.wrap({test: 5}); + MyInt.wrap(); + MyInt.unwrap(5); + MyInt.unwrap({test: 5}); + MyInt.unwrap(MyInt.wrap(1), MyInt.wrap(2)); +} +// ---- +// TypeError 6160: (38-57): Wrong argument count for function call: 3 arguments given but expected 1. +// TypeError 4974: (63-84): Named argument "test" does not match function declaration. +// TypeError 6160: (90-102): Wrong argument count for function call: 0 arguments given but expected 1. +// TypeError 9553: (121-122): Invalid type for argument in function call. Invalid implicit conversion from int_const 5 to user defined type MyInt requested. +// TypeError 4974: (129-152): Named argument "test" does not match function declaration. +// TypeError 6160: (158-200): Wrong argument count for function call: 2 arguments given but expected 1. From c63b768fff749bd4bbb7b01a9340f00abf32333f Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 7 Sep 2021 17:37:36 +0200 Subject: [PATCH 036/232] Sort yul functions by creation time. --- .../codegen/MultiUseYulFunctionCollector.cpp | 19 +++++++------------ .../codegen/MultiUseYulFunctionCollector.h | 10 +++++----- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/libsolidity/codegen/MultiUseYulFunctionCollector.cpp b/libsolidity/codegen/MultiUseYulFunctionCollector.cpp index 57d2a856c..69d30c6c8 100644 --- a/libsolidity/codegen/MultiUseYulFunctionCollector.cpp +++ b/libsolidity/codegen/MultiUseYulFunctionCollector.cpp @@ -33,13 +33,8 @@ using namespace solidity::util; string MultiUseYulFunctionCollector::requestedFunctions() { - string result; - for (auto const& [name, code]: m_requestedFunctions) - { - solAssert(code != "< arguments; vector returnParameters; string body = _creator(arguments, returnParameters); solAssert(!body.empty(), ""); - m_requestedFunctions[_name] = Whiskers(R"( + m_code += Whiskers(R"( function () -> { } @@ -80,7 +75,7 @@ string MultiUseYulFunctionCollector::createFunction( ("args", joinHumanReadable(arguments)) ("retParams", joinHumanReadable(returnParameters)) ("body", body) - .render();; + .render(); } return _name; } diff --git a/libsolidity/codegen/MultiUseYulFunctionCollector.h b/libsolidity/codegen/MultiUseYulFunctionCollector.h index 7883fa668..050b5858f 100644 --- a/libsolidity/codegen/MultiUseYulFunctionCollector.h +++ b/libsolidity/codegen/MultiUseYulFunctionCollector.h @@ -25,6 +25,7 @@ #include #include #include +#include namespace solidity::frontend { @@ -46,9 +47,8 @@ public: std::function&, std::vector&)> const& _creator ); - /// @returns concatenation of all generated functions. - /// Guarantees that the order of functions in the generated code is deterministic and - /// platform-independent. + /// @returns concatenation of all generated functions in the order in which they were + /// generated. /// Clears the internal list, i.e. calling it again will result in an /// empty return value. std::string requestedFunctions(); @@ -57,8 +57,8 @@ public: bool contains(std::string const& _name) const { return m_requestedFunctions.count(_name) > 0; } private: - /// Map from function name to code for a multi-use function. - std::map m_requestedFunctions; + std::set m_requestedFunctions; + std::string m_code; }; } From 1304080a77a4c7d15c5957f3484b5ba9b324e5e2 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 7 Sep 2021 18:00:20 +0200 Subject: [PATCH 037/232] Update commandline tests. --- .../combined_json_generated_sources/output | 764 +++++----- test/cmdlineTests/exp_base_literal/output | 224 +-- test/cmdlineTests/name_simplifier/output | 49 +- test/cmdlineTests/revert_strings/output | 464 +++--- .../standard_function_debug_info/output.json | 2 +- .../standard_generatedSources/output.json | 134 +- .../output.json | 25 +- .../standard_ir_requested/output.json | 48 +- .../output.json | 14 +- .../standard_viair_requested/output.json | 118 +- test/cmdlineTests/viair_abicoder_v1/output | 62 +- test/cmdlineTests/yul_optimizer_steps/output | 4 +- .../yul_source_locations/output.json | 1292 ++++++++--------- .../yul_source_locations_in_asm/output.json | 268 ++-- .../yul_string_format_ascii/output.json | 162 +-- .../output.json | 62 +- .../output.json | 76 +- .../yul_string_format_ascii_long/output.json | 170 +-- .../yul_string_format_hex/output.json | 76 +- 19 files changed, 2008 insertions(+), 2006 deletions(-) diff --git a/test/cmdlineTests/combined_json_generated_sources/output b/test/cmdlineTests/combined_json_generated_sources/output index 3cf5cfb68..0bd9395fe 100644 --- a/test/cmdlineTests/combined_json_generated_sources/output +++ b/test/cmdlineTests/combined_json_generated_sources/output @@ -17,14 +17,294 @@ "body": { "nodeType": "YulBlock", - "src": "114:478:1", + "src": "47:35:1", + "statements": + [ + { + "nodeType": "YulAssignment", + "src": "57:19:1", + "value": + { + "arguments": + [ + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "73:2:1", + "type": "", + "value": "64" + } + ], + "functionName": + { + "name": "mload", + "nodeType": "YulIdentifier", + "src": "67:5:1" + }, + "nodeType": "YulFunctionCall", + "src": "67:9:1" + }, + "variableNames": + [ + { + "name": "memPtr", + "nodeType": "YulIdentifier", + "src": "57:6:1" + } + ] + } + ] + }, + "name": "allocate_unbounded", + "nodeType": "YulFunctionDefinition", + "returnVariables": + [ + { + "name": "memPtr", + "nodeType": "YulTypedName", + "src": "40:6:1", + "type": "" + } + ], + "src": "7:75:1" + }, + { + "body": + { + "nodeType": "YulBlock", + "src": "177:28:1", + "statements": + [ + { + "expression": + { + "arguments": + [ + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "194:1:1", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "197:1:1", + "type": "", + "value": "0" + } + ], + "functionName": + { + "name": "revert", + "nodeType": "YulIdentifier", + "src": "187:6:1" + }, + "nodeType": "YulFunctionCall", + "src": "187:12:1" + }, + "nodeType": "YulExpressionStatement", + "src": "187:12:1" + } + ] + }, + "name": "revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b", + "nodeType": "YulFunctionDefinition", + "src": "88:117:1" + }, + { + "body": + { + "nodeType": "YulBlock", + "src": "300:28:1", + "statements": + [ + { + "expression": + { + "arguments": + [ + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "317:1:1", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "320:1:1", + "type": "", + "value": "0" + } + ], + "functionName": + { + "name": "revert", + "nodeType": "YulIdentifier", + "src": "310:6:1" + }, + "nodeType": "YulFunctionCall", + "src": "310:12:1" + }, + "nodeType": "YulExpressionStatement", + "src": "310:12:1" + } + ] + }, + "name": "revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db", + "nodeType": "YulFunctionDefinition", + "src": "211:117:1" + }, + { + "body": + { + "nodeType": "YulBlock", + "src": "423:28:1", + "statements": + [ + { + "expression": + { + "arguments": + [ + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "440:1:1", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "443:1:1", + "type": "", + "value": "0" + } + ], + "functionName": + { + "name": "revert", + "nodeType": "YulIdentifier", + "src": "433:6:1" + }, + "nodeType": "YulFunctionCall", + "src": "433:12:1" + }, + "nodeType": "YulExpressionStatement", + "src": "433:12:1" + } + ] + }, + "name": "revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d", + "nodeType": "YulFunctionDefinition", + "src": "334:117:1" + }, + { + "body": + { + "nodeType": "YulBlock", + "src": "546:28:1", + "statements": + [ + { + "expression": + { + "arguments": + [ + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "563:1:1", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "566:1:1", + "type": "", + "value": "0" + } + ], + "functionName": + { + "name": "revert", + "nodeType": "YulIdentifier", + "src": "556:6:1" + }, + "nodeType": "YulFunctionCall", + "src": "556:12:1" + }, + "nodeType": "YulExpressionStatement", + "src": "556:12:1" + } + ] + }, + "name": "revert_error_15abf5612cd996bc235ba1e55a4a30ac60e6bb601ff7ba4ad3f179b6be8d0490", + "nodeType": "YulFunctionDefinition", + "src": "457:117:1" + }, + { + "body": + { + "nodeType": "YulBlock", + "src": "669:28:1", + "statements": + [ + { + "expression": + { + "arguments": + [ + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "686:1:1", + "type": "", + "value": "0" + }, + { + "kind": "number", + "nodeType": "YulLiteral", + "src": "689:1:1", + "type": "", + "value": "0" + } + ], + "functionName": + { + "name": "revert", + "nodeType": "YulIdentifier", + "src": "679:6:1" + }, + "nodeType": "YulFunctionCall", + "src": "679:12:1" + }, + "nodeType": "YulExpressionStatement", + "src": "679:12:1" + } + ] + }, + "name": "revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef", + "nodeType": "YulFunctionDefinition", + "src": "580:117:1" + }, + { + "body": + { + "nodeType": "YulBlock", + "src": "810:478:1", "statements": [ { "body": { "nodeType": "YulBlock", - "src": "163:83:1", + "src": "859:83:1", "statements": [ { @@ -35,13 +315,13 @@ { "name": "revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d", "nodeType": "YulIdentifier", - "src": "165:77:1" + "src": "861:77:1" }, "nodeType": "YulFunctionCall", - "src": "165:79:1" + "src": "861:79:1" }, "nodeType": "YulExpressionStatement", - "src": "165:79:1" + "src": "861:79:1" } ] }, @@ -58,12 +338,12 @@ { "name": "offset", "nodeType": "YulIdentifier", - "src": "142:6:1" + "src": "838:6:1" }, { "kind": "number", "nodeType": "YulLiteral", - "src": "150:4:1", + "src": "846:4:1", "type": "", "value": "0x1f" } @@ -72,42 +352,42 @@ { "name": "add", "nodeType": "YulIdentifier", - "src": "138:3:1" + "src": "834:3:1" }, "nodeType": "YulFunctionCall", - "src": "138:17:1" + "src": "834:17:1" }, { "name": "end", "nodeType": "YulIdentifier", - "src": "157:3:1" + "src": "853:3:1" } ], "functionName": { "name": "slt", "nodeType": "YulIdentifier", - "src": "134:3:1" + "src": "830:3:1" }, "nodeType": "YulFunctionCall", - "src": "134:27:1" + "src": "830:27:1" } ], "functionName": { "name": "iszero", "nodeType": "YulIdentifier", - "src": "127:6:1" + "src": "823:6:1" }, "nodeType": "YulFunctionCall", - "src": "127:35:1" + "src": "823:35:1" }, "nodeType": "YulIf", - "src": "124:122:1" + "src": "820:122:1" }, { "nodeType": "YulAssignment", - "src": "255:30:1", + "src": "951:30:1", "value": { "arguments": @@ -115,24 +395,24 @@ { "name": "offset", "nodeType": "YulIdentifier", - "src": "278:6:1" + "src": "974:6:1" } ], "functionName": { "name": "calldataload", "nodeType": "YulIdentifier", - "src": "265:12:1" + "src": "961:12:1" }, "nodeType": "YulFunctionCall", - "src": "265:20:1" + "src": "961:20:1" }, "variableNames": [ { "name": "length", "nodeType": "YulIdentifier", - "src": "255:6:1" + "src": "951:6:1" } ] }, @@ -140,7 +420,7 @@ "body": { "nodeType": "YulBlock", - "src": "328:83:1", + "src": "1024:83:1", "statements": [ { @@ -151,13 +431,13 @@ { "name": "revert_error_15abf5612cd996bc235ba1e55a4a30ac60e6bb601ff7ba4ad3f179b6be8d0490", "nodeType": "YulIdentifier", - "src": "330:77:1" + "src": "1026:77:1" }, "nodeType": "YulFunctionCall", - "src": "330:79:1" + "src": "1026:79:1" }, "nodeType": "YulExpressionStatement", - "src": "330:79:1" + "src": "1026:79:1" } ] }, @@ -168,12 +448,12 @@ { "name": "length", "nodeType": "YulIdentifier", - "src": "300:6:1" + "src": "996:6:1" }, { "kind": "number", "nodeType": "YulLiteral", - "src": "308:18:1", + "src": "1004:18:1", "type": "", "value": "0xffffffffffffffff" } @@ -182,17 +462,17 @@ { "name": "gt", "nodeType": "YulIdentifier", - "src": "297:2:1" + "src": "993:2:1" }, "nodeType": "YulFunctionCall", - "src": "297:30:1" + "src": "993:30:1" }, "nodeType": "YulIf", - "src": "294:117:1" + "src": "990:117:1" }, { "nodeType": "YulAssignment", - "src": "420:29:1", + "src": "1116:29:1", "value": { "arguments": @@ -200,12 +480,12 @@ { "name": "offset", "nodeType": "YulIdentifier", - "src": "436:6:1" + "src": "1132:6:1" }, { "kind": "number", "nodeType": "YulLiteral", - "src": "444:4:1", + "src": "1140:4:1", "type": "", "value": "0x20" } @@ -214,17 +494,17 @@ { "name": "add", "nodeType": "YulIdentifier", - "src": "432:3:1" + "src": "1128:3:1" }, "nodeType": "YulFunctionCall", - "src": "432:17:1" + "src": "1128:17:1" }, "variableNames": [ { "name": "arrayPos", "nodeType": "YulIdentifier", - "src": "420:8:1" + "src": "1116:8:1" } ] }, @@ -232,7 +512,7 @@ "body": { "nodeType": "YulBlock", - "src": "503:83:1", + "src": "1199:83:1", "statements": [ { @@ -243,13 +523,13 @@ { "name": "revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef", "nodeType": "YulIdentifier", - "src": "505:77:1" + "src": "1201:77:1" }, "nodeType": "YulFunctionCall", - "src": "505:79:1" + "src": "1201:79:1" }, "nodeType": "YulExpressionStatement", - "src": "505:79:1" + "src": "1201:79:1" } ] }, @@ -263,7 +543,7 @@ { "name": "arrayPos", "nodeType": "YulIdentifier", - "src": "468:8:1" + "src": "1164:8:1" }, { "arguments": @@ -271,12 +551,12 @@ { "name": "length", "nodeType": "YulIdentifier", - "src": "482:6:1" + "src": "1178:6:1" }, { "kind": "number", "nodeType": "YulLiteral", - "src": "490:4:1", + "src": "1186:4:1", "type": "", "value": "0x20" } @@ -285,38 +565,38 @@ { "name": "mul", "nodeType": "YulIdentifier", - "src": "478:3:1" + "src": "1174:3:1" }, "nodeType": "YulFunctionCall", - "src": "478:17:1" + "src": "1174:17:1" } ], "functionName": { "name": "add", "nodeType": "YulIdentifier", - "src": "464:3:1" + "src": "1160:3:1" }, "nodeType": "YulFunctionCall", - "src": "464:32:1" + "src": "1160:32:1" }, { "name": "end", "nodeType": "YulIdentifier", - "src": "498:3:1" + "src": "1194:3:1" } ], "functionName": { "name": "gt", "nodeType": "YulIdentifier", - "src": "461:2:1" + "src": "1157:2:1" }, "nodeType": "YulFunctionCall", - "src": "461:41:1" + "src": "1157:41:1" }, "nodeType": "YulIf", - "src": "458:128:1" + "src": "1154:128:1" } ] }, @@ -327,13 +607,13 @@ { "name": "offset", "nodeType": "YulTypedName", - "src": "81:6:1", + "src": "777:6:1", "type": "" }, { "name": "end", "nodeType": "YulTypedName", - "src": "89:3:1", + "src": "785:3:1", "type": "" } ], @@ -342,30 +622,30 @@ { "name": "arrayPos", "nodeType": "YulTypedName", - "src": "97:8:1", + "src": "793:8:1", "type": "" }, { "name": "length", "nodeType": "YulTypedName", - "src": "107:6:1", + "src": "803:6:1", "type": "" } ], - "src": "24:568:1" + "src": "720:568:1" }, { "body": { "nodeType": "YulBlock", - "src": "699:458:1", + "src": "1395:458:1", "statements": [ { "body": { "nodeType": "YulBlock", - "src": "745:83:1", + "src": "1441:83:1", "statements": [ { @@ -376,13 +656,13 @@ { "name": "revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b", "nodeType": "YulIdentifier", - "src": "747:77:1" + "src": "1443:77:1" }, "nodeType": "YulFunctionCall", - "src": "747:79:1" + "src": "1443:79:1" }, "nodeType": "YulExpressionStatement", - "src": "747:79:1" + "src": "1443:79:1" } ] }, @@ -396,27 +676,27 @@ { "name": "dataEnd", "nodeType": "YulIdentifier", - "src": "720:7:1" + "src": "1416:7:1" }, { "name": "headStart", "nodeType": "YulIdentifier", - "src": "729:9:1" + "src": "1425:9:1" } ], "functionName": { "name": "sub", "nodeType": "YulIdentifier", - "src": "716:3:1" + "src": "1412:3:1" }, "nodeType": "YulFunctionCall", - "src": "716:23:1" + "src": "1412:23:1" }, { "kind": "number", "nodeType": "YulLiteral", - "src": "741:2:1", + "src": "1437:2:1", "type": "", "value": "32" } @@ -425,22 +705,22 @@ { "name": "slt", "nodeType": "YulIdentifier", - "src": "712:3:1" + "src": "1408:3:1" }, "nodeType": "YulFunctionCall", - "src": "712:32:1" + "src": "1408:32:1" }, "nodeType": "YulIf", - "src": "709:119:1" + "src": "1405:119:1" }, { "nodeType": "YulBlock", - "src": "838:312:1", + "src": "1534:312:1", "statements": [ { "nodeType": "YulVariableDeclaration", - "src": "853:45:1", + "src": "1549:45:1", "value": { "arguments": @@ -451,12 +731,12 @@ { "name": "headStart", "nodeType": "YulIdentifier", - "src": "884:9:1" + "src": "1580:9:1" }, { "kind": "number", "nodeType": "YulLiteral", - "src": "895:1:1", + "src": "1591:1:1", "type": "", "value": "0" } @@ -465,27 +745,27 @@ { "name": "add", "nodeType": "YulIdentifier", - "src": "880:3:1" + "src": "1576:3:1" }, "nodeType": "YulFunctionCall", - "src": "880:17:1" + "src": "1576:17:1" } ], "functionName": { "name": "calldataload", "nodeType": "YulIdentifier", - "src": "867:12:1" + "src": "1563:12:1" }, "nodeType": "YulFunctionCall", - "src": "867:31:1" + "src": "1563:31:1" }, "variables": [ { "name": "offset", "nodeType": "YulTypedName", - "src": "857:6:1", + "src": "1553:6:1", "type": "" } ] @@ -494,7 +774,7 @@ "body": { "nodeType": "YulBlock", - "src": "945:83:1", + "src": "1641:83:1", "statements": [ { @@ -505,13 +785,13 @@ { "name": "revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db", "nodeType": "YulIdentifier", - "src": "947:77:1" + "src": "1643:77:1" }, "nodeType": "YulFunctionCall", - "src": "947:79:1" + "src": "1643:79:1" }, "nodeType": "YulExpressionStatement", - "src": "947:79:1" + "src": "1643:79:1" } ] }, @@ -522,12 +802,12 @@ { "name": "offset", "nodeType": "YulIdentifier", - "src": "917:6:1" + "src": "1613:6:1" }, { "kind": "number", "nodeType": "YulLiteral", - "src": "925:18:1", + "src": "1621:18:1", "type": "", "value": "0xffffffffffffffff" } @@ -536,17 +816,17 @@ { "name": "gt", "nodeType": "YulIdentifier", - "src": "914:2:1" + "src": "1610:2:1" }, "nodeType": "YulFunctionCall", - "src": "914:30:1" + "src": "1610:30:1" }, "nodeType": "YulIf", - "src": "911:117:1" + "src": "1607:117:1" }, { "nodeType": "YulAssignment", - "src": "1042:98:1", + "src": "1738:98:1", "value": { "arguments": @@ -557,49 +837,49 @@ { "name": "headStart", "nodeType": "YulIdentifier", - "src": "1112:9:1" + "src": "1808:9:1" }, { "name": "offset", "nodeType": "YulIdentifier", - "src": "1123:6:1" + "src": "1819:6:1" } ], "functionName": { "name": "add", "nodeType": "YulIdentifier", - "src": "1108:3:1" + "src": "1804:3:1" }, "nodeType": "YulFunctionCall", - "src": "1108:22:1" + "src": "1804:22:1" }, { "name": "dataEnd", "nodeType": "YulIdentifier", - "src": "1132:7:1" + "src": "1828:7:1" } ], "functionName": { "name": "abi_decode_t_array$_t_uint256_$dyn_calldata_ptr", "nodeType": "YulIdentifier", - "src": "1060:47:1" + "src": "1756:47:1" }, "nodeType": "YulFunctionCall", - "src": "1060:80:1" + "src": "1756:80:1" }, "variableNames": [ { "name": "value0", "nodeType": "YulIdentifier", - "src": "1042:6:1" + "src": "1738:6:1" }, { "name": "value1", "nodeType": "YulIdentifier", - "src": "1050:6:1" + "src": "1746:6:1" } ] } @@ -614,13 +894,13 @@ { "name": "headStart", "nodeType": "YulTypedName", - "src": "661:9:1", + "src": "1357:9:1", "type": "" }, { "name": "dataEnd", "nodeType": "YulTypedName", - "src": "672:7:1", + "src": "1368:7:1", "type": "" } ], @@ -629,301 +909,21 @@ { "name": "value0", "nodeType": "YulTypedName", - "src": "684:6:1", + "src": "1380:6:1", "type": "" }, { "name": "value1", "nodeType": "YulTypedName", - "src": "692:6:1", + "src": "1388:6:1", "type": "" } ], - "src": "598:559:1" - }, - { - "body": - { - "nodeType": "YulBlock", - "src": "1203:35:1", - "statements": - [ - { - "nodeType": "YulAssignment", - "src": "1213:19:1", - "value": - { - "arguments": - [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1229:2:1", - "type": "", - "value": "64" - } - ], - "functionName": - { - "name": "mload", - "nodeType": "YulIdentifier", - "src": "1223:5:1" - }, - "nodeType": "YulFunctionCall", - "src": "1223:9:1" - }, - "variableNames": - [ - { - "name": "memPtr", - "nodeType": "YulIdentifier", - "src": "1213:6:1" - } - ] - } - ] - }, - "name": "allocate_unbounded", - "nodeType": "YulFunctionDefinition", - "returnVariables": - [ - { - "name": "memPtr", - "nodeType": "YulTypedName", - "src": "1196:6:1", - "type": "" - } - ], - "src": "1163:75:1" - }, - { - "body": - { - "nodeType": "YulBlock", - "src": "1333:28:1", - "statements": - [ - { - "expression": - { - "arguments": - [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1350:1:1", - "type": "", - "value": "0" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1353:1:1", - "type": "", - "value": "0" - } - ], - "functionName": - { - "name": "revert", - "nodeType": "YulIdentifier", - "src": "1343:6:1" - }, - "nodeType": "YulFunctionCall", - "src": "1343:12:1" - }, - "nodeType": "YulExpressionStatement", - "src": "1343:12:1" - } - ] - }, - "name": "revert_error_15abf5612cd996bc235ba1e55a4a30ac60e6bb601ff7ba4ad3f179b6be8d0490", - "nodeType": "YulFunctionDefinition", - "src": "1244:117:1" - }, - { - "body": - { - "nodeType": "YulBlock", - "src": "1456:28:1", - "statements": - [ - { - "expression": - { - "arguments": - [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1473:1:1", - "type": "", - "value": "0" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1476:1:1", - "type": "", - "value": "0" - } - ], - "functionName": - { - "name": "revert", - "nodeType": "YulIdentifier", - "src": "1466:6:1" - }, - "nodeType": "YulFunctionCall", - "src": "1466:12:1" - }, - "nodeType": "YulExpressionStatement", - "src": "1466:12:1" - } - ] - }, - "name": "revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d", - "nodeType": "YulFunctionDefinition", - "src": "1367:117:1" - }, - { - "body": - { - "nodeType": "YulBlock", - "src": "1579:28:1", - "statements": - [ - { - "expression": - { - "arguments": - [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1596:1:1", - "type": "", - "value": "0" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1599:1:1", - "type": "", - "value": "0" - } - ], - "functionName": - { - "name": "revert", - "nodeType": "YulIdentifier", - "src": "1589:6:1" - }, - "nodeType": "YulFunctionCall", - "src": "1589:12:1" - }, - "nodeType": "YulExpressionStatement", - "src": "1589:12:1" - } - ] - }, - "name": "revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef", - "nodeType": "YulFunctionDefinition", - "src": "1490:117:1" - }, - { - "body": - { - "nodeType": "YulBlock", - "src": "1702:28:1", - "statements": - [ - { - "expression": - { - "arguments": - [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1719:1:1", - "type": "", - "value": "0" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1722:1:1", - "type": "", - "value": "0" - } - ], - "functionName": - { - "name": "revert", - "nodeType": "YulIdentifier", - "src": "1712:6:1" - }, - "nodeType": "YulFunctionCall", - "src": "1712:12:1" - }, - "nodeType": "YulExpressionStatement", - "src": "1712:12:1" - } - ] - }, - "name": "revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db", - "nodeType": "YulFunctionDefinition", - "src": "1613:117:1" - }, - { - "body": - { - "nodeType": "YulBlock", - "src": "1825:28:1", - "statements": - [ - { - "expression": - { - "arguments": - [ - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1842:1:1", - "type": "", - "value": "0" - }, - { - "kind": "number", - "nodeType": "YulLiteral", - "src": "1845:1:1", - "type": "", - "value": "0" - } - ], - "functionName": - { - "name": "revert", - "nodeType": "YulIdentifier", - "src": "1835:6:1" - }, - "nodeType": "YulFunctionCall", - "src": "1835:12:1" - }, - "nodeType": "YulExpressionStatement", - "src": "1835:12:1" - } - ] - }, - "name": "revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b", - "nodeType": "YulFunctionDefinition", - "src": "1736:117:1" + "src": "1294:559:1" } ] }, - "contents": "{\n\n // uint256[]\n function abi_decode_t_array$_t_uint256_$dyn_calldata_ptr(offset, end) -> arrayPos, length {\n if iszero(slt(add(offset, 0x1f), end)) { revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d() }\n length := calldataload(offset)\n if gt(length, 0xffffffffffffffff) { revert_error_15abf5612cd996bc235ba1e55a4a30ac60e6bb601ff7ba4ad3f179b6be8d0490() }\n arrayPos := add(offset, 0x20)\n if gt(add(arrayPos, mul(length, 0x20)), end) { revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef() }\n }\n\n function abi_decode_tuple_t_array$_t_uint256_$dyn_calldata_ptr(headStart, dataEnd) -> value0, value1 {\n if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() }\n\n {\n\n let offset := calldataload(add(headStart, 0))\n if gt(offset, 0xffffffffffffffff) { revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() }\n\n value0, value1 := abi_decode_t_array$_t_uint256_$dyn_calldata_ptr(add(headStart, offset), dataEnd)\n }\n\n }\n\n function allocate_unbounded() -> memPtr {\n memPtr := mload(64)\n }\n\n function revert_error_15abf5612cd996bc235ba1e55a4a30ac60e6bb601ff7ba4ad3f179b6be8d0490() {\n revert(0, 0)\n }\n\n function revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d() {\n revert(0, 0)\n }\n\n function revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef() {\n revert(0, 0)\n }\n\n function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() {\n revert(0, 0)\n }\n\n function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() {\n revert(0, 0)\n }\n\n}\n", + "contents": "{\n\n function allocate_unbounded() -> memPtr {\n memPtr := mload(64)\n }\n\n function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() {\n revert(0, 0)\n }\n\n function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() {\n revert(0, 0)\n }\n\n function revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d() {\n revert(0, 0)\n }\n\n function revert_error_15abf5612cd996bc235ba1e55a4a30ac60e6bb601ff7ba4ad3f179b6be8d0490() {\n revert(0, 0)\n }\n\n function revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef() {\n revert(0, 0)\n }\n\n // uint256[]\n function abi_decode_t_array$_t_uint256_$dyn_calldata_ptr(offset, end) -> arrayPos, length {\n if iszero(slt(add(offset, 0x1f), end)) { revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d() }\n length := calldataload(offset)\n if gt(length, 0xffffffffffffffff) { revert_error_15abf5612cd996bc235ba1e55a4a30ac60e6bb601ff7ba4ad3f179b6be8d0490() }\n arrayPos := add(offset, 0x20)\n if gt(add(arrayPos, mul(length, 0x20)), end) { revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef() }\n }\n\n function abi_decode_tuple_t_array$_t_uint256_$dyn_calldata_ptr(headStart, dataEnd) -> value0, value1 {\n if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() }\n\n {\n\n let offset := calldataload(add(headStart, 0))\n if gt(offset, 0xffffffffffffffff) { revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() }\n\n value0, value1 := abi_decode_t_array$_t_uint256_$dyn_calldata_ptr(add(headStart, offset), dataEnd)\n }\n\n }\n\n}\n", "id": 1, "language": "Yul", "name": "#utility.yul" diff --git a/test/cmdlineTests/exp_base_literal/output b/test/cmdlineTests/exp_base_literal/output index 36d7800a0..f4f8042c2 100644 --- a/test/cmdlineTests/exp_base_literal/output +++ b/test/cmdlineTests/exp_base_literal/output @@ -25,6 +25,10 @@ object "C_81" { memPtr := mload(64) } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + /// @src 0:82:370 function constructor_C_81() { @@ -33,10 +37,6 @@ object "C_81" { } /// @src 0:82:370 - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - } /// @use-src 0:"exp_base_literal/input.sol" object "C_81_deployed" { @@ -66,6 +66,37 @@ object "C_81" { if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + function abi_decode_t_uint256(offset, end) -> value { value := calldataload(offset) validator_revert_t_uint256(value) @@ -104,14 +135,18 @@ object "C_81" { } - function abi_encode_t_int256_to_t_int256_fromStack(value, pos) { - mstore(pos, cleanup_t_int256(value)) - } - function abi_encode_t_uint256_to_t_uint256_fromStack(value, pos) { mstore(pos, cleanup_t_uint256(value)) } + function cleanup_t_int256(value) -> cleaned { + cleaned := value + } + + function abi_encode_t_int256_to_t_int256_fromStack(value, pos) { + mstore(pos, cleanup_t_int256(value)) + } + function abi_encode_tuple_t_uint256_t_int256_t_uint256_t_uint256__to_t_uint256_t_int256_t_uint256_t_uint256__fromStack(headStart , value0, value1, value2, value3) -> tail { tail := add(headStart, 128) @@ -125,36 +160,34 @@ object "C_81" { } - function allocate_unbounded() -> memPtr { - memPtr := mload(64) + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) } - function checked_exp_t_rational_0_by_1_t_uint256(exponent) -> power { - exponent := cleanup_t_uint256(exponent) - - power := exp(0, exponent) + function zero_value_for_split_t_uint256() -> ret { + ret := 0 } - function checked_exp_t_rational_10_by_1_t_uint256(exponent) -> power { - exponent := cleanup_t_uint256(exponent) - - if gt(exponent, 77) { panic_error_0x11() } - - power := exp(10, exponent) + function zero_value_for_split_t_int256() -> ret { + ret := 0 } - function checked_exp_t_rational_115792089237316195423570985008687907853269984665640564039457584007913129639935_by_1_t_uint256(exponent) -> power { - exponent := cleanup_t_uint256(exponent) - - if gt(exponent, 1) { panic_error_0x11() } - - power := exp(115792089237316195423570985008687907853269984665640564039457584007913129639935, exponent) + function cleanup_t_rational_2_by_1(value) -> cleaned { + cleaned := value } - function checked_exp_t_rational_1_by_1_t_uint256(exponent) -> power { - exponent := cleanup_t_uint256(exponent) + function identity(value) -> ret { + ret := value + } - power := exp(1, exponent) + function convert_t_rational_2_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_2_by_1(value))) + } + + function panic_error_0x11() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x11) + revert(0, 0x24) } function checked_exp_t_rational_2_by_1_t_uint256(exponent) -> power { @@ -165,10 +198,12 @@ object "C_81" { power := exp(2, exponent) } - function checked_exp_t_rational_minus_1_by_1_t_uint256(exponent) -> power { - exponent := cleanup_t_uint256(exponent) + function cleanup_t_rational_minus_2_by_1(value) -> cleaned { + cleaned := value + } - power := exp(115792089237316195423570985008687907853269984665640564039457584007913129639935, exponent) + function convert_t_rational_minus_2_by_1_to_t_int256(value) -> converted { + converted := cleanup_t_int256(identity(cleanup_t_rational_minus_2_by_1(value))) } function checked_exp_t_rational_minus_2_by_1_t_uint256(exponent) -> power { @@ -179,39 +214,39 @@ object "C_81" { power := exp(115792089237316195423570985008687907853269984665640564039457584007913129639934, exponent) } - function cleanup_t_int256(value) -> cleaned { - cleaned := value - } - - function cleanup_t_rational_0_by_1(value) -> cleaned { - cleaned := value - } - function cleanup_t_rational_10_by_1(value) -> cleaned { cleaned := value } + function convert_t_rational_10_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_10_by_1(value))) + } + + function checked_exp_t_rational_10_by_1_t_uint256(exponent) -> power { + exponent := cleanup_t_uint256(exponent) + + if gt(exponent, 77) { panic_error_0x11() } + + power := exp(10, exponent) + } + function cleanup_t_rational_115792089237316195423570985008687907853269984665640564039457584007913129639935_by_1(value) -> cleaned { cleaned := value } - function cleanup_t_rational_1_by_1(value) -> cleaned { - cleaned := value + function convert_t_rational_115792089237316195423570985008687907853269984665640564039457584007913129639935_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_115792089237316195423570985008687907853269984665640564039457584007913129639935_by_1(value))) } - function cleanup_t_rational_2_by_1(value) -> cleaned { - cleaned := value + function checked_exp_t_rational_115792089237316195423570985008687907853269984665640564039457584007913129639935_by_1_t_uint256(exponent) -> power { + exponent := cleanup_t_uint256(exponent) + + if gt(exponent, 1) { panic_error_0x11() } + + power := exp(115792089237316195423570985008687907853269984665640564039457584007913129639935, exponent) } - function cleanup_t_rational_minus_1_by_1(value) -> cleaned { - cleaned := value - } - - function cleanup_t_rational_minus_2_by_1(value) -> cleaned { - cleaned := value - } - - function cleanup_t_uint256(value) -> cleaned { + function cleanup_t_rational_0_by_1(value) -> cleaned { cleaned := value } @@ -219,28 +254,38 @@ object "C_81" { converted := cleanup_t_uint256(identity(cleanup_t_rational_0_by_1(value))) } - function convert_t_rational_10_by_1_to_t_uint256(value) -> converted { - converted := cleanup_t_uint256(identity(cleanup_t_rational_10_by_1(value))) + function checked_exp_t_rational_0_by_1_t_uint256(exponent) -> power { + exponent := cleanup_t_uint256(exponent) + + power := exp(0, exponent) } - function convert_t_rational_115792089237316195423570985008687907853269984665640564039457584007913129639935_by_1_to_t_uint256(value) -> converted { - converted := cleanup_t_uint256(identity(cleanup_t_rational_115792089237316195423570985008687907853269984665640564039457584007913129639935_by_1(value))) - } - - function convert_t_rational_1_by_1_to_t_uint256(value) -> converted { - converted := cleanup_t_uint256(identity(cleanup_t_rational_1_by_1(value))) - } - - function convert_t_rational_2_by_1_to_t_uint256(value) -> converted { - converted := cleanup_t_uint256(identity(cleanup_t_rational_2_by_1(value))) + function cleanup_t_rational_minus_1_by_1(value) -> cleaned { + cleaned := value } function convert_t_rational_minus_1_by_1_to_t_int256(value) -> converted { converted := cleanup_t_int256(identity(cleanup_t_rational_minus_1_by_1(value))) } - function convert_t_rational_minus_2_by_1_to_t_int256(value) -> converted { - converted := cleanup_t_int256(identity(cleanup_t_rational_minus_2_by_1(value))) + function checked_exp_t_rational_minus_1_by_1_t_uint256(exponent) -> power { + exponent := cleanup_t_uint256(exponent) + + power := exp(115792089237316195423570985008687907853269984665640564039457584007913129639935, exponent) + } + + function cleanup_t_rational_1_by_1(value) -> cleaned { + cleaned := value + } + + function convert_t_rational_1_by_1_to_t_uint256(value) -> converted { + converted := cleanup_t_uint256(identity(cleanup_t_rational_1_by_1(value))) + } + + function checked_exp_t_rational_1_by_1_t_uint256(exponent) -> power { + exponent := cleanup_t_uint256(exponent) + + power := exp(1, exponent) } /// @src 0:96:368 @@ -369,51 +414,6 @@ object "C_81" { } /// @src 0:82:370 - function identity(value) -> ret { - ret := value - } - - function panic_error_0x11() { - mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) - mstore(4, 0x11) - revert(0, 0x24) - } - - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { - revert(0, 0) - } - - function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { - revert(0, 0) - } - - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - - function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { - revert(0, 0) - } - - function shift_right_224_unsigned(value) -> newValue { - newValue := - - shr(224, value) - - } - - function validator_revert_t_uint256(value) { - if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } - } - - function zero_value_for_split_t_int256() -> ret { - ret := 0 - } - - function zero_value_for_split_t_uint256() -> ret { - ret := 0 - } - } data ".metadata" hex"" diff --git a/test/cmdlineTests/name_simplifier/output b/test/cmdlineTests/name_simplifier/output index a774ead21..fcd70e0b0 100644 --- a/test/cmdlineTests/name_simplifier/output +++ b/test/cmdlineTests/name_simplifier/output @@ -62,6 +62,26 @@ object "C_59" { } revert(0, 0) } + function panic_error_0x41() + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 0x41) + revert(0, 0x24) + } + function allocate_memory_1236() -> memPtr + { + memPtr := mload(64) + let newFreePtr := add(memPtr, 32) + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } + mstore(64, newFreePtr) + } + function allocate_memory(size) -> memPtr + { + memPtr := mload(64) + let newFreePtr := add(memPtr, and(add(size, 31), not(31))) + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } + mstore(64, newFreePtr) + } function abi_encode_uint256_string(headStart, value0, value1) -> tail { mstore(headStart, value0) @@ -80,19 +100,11 @@ object "C_59" { } tail := add(add(headStart, and(add(length, 31), not(31))), 96) } - function allocate_memory_1236() -> memPtr + function panic_error_0x32() { - memPtr := mload(64) - let newFreePtr := add(memPtr, 32) - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } - mstore(64, newFreePtr) - } - function allocate_memory(size) -> memPtr - { - memPtr := mload(64) - let newFreePtr := add(memPtr, and(add(size, 31), not(31))) - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } - mstore(64, newFreePtr) + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 0x32) + revert(0, 0x24) } /// @src 0:381:623 function fun_sumArray(var_s_mpos) -> var, var_mpos @@ -118,19 +130,6 @@ object "C_59" { /// @src 0:500:619 var_mpos := memPtr } - /// @src 0:346:625 - function panic_error_0x32() - { - mstore(0, shl(224, 0x4e487b71)) - mstore(4, 0x32) - revert(0, 0x24) - } - function panic_error_0x41() - { - mstore(0, shl(224, 0x4e487b71)) - mstore(4, 0x41) - revert(0, 0x24) - } } data ".metadata" hex"" } diff --git a/test/cmdlineTests/revert_strings/output b/test/cmdlineTests/revert_strings/output index be43c5d0d..fde886ed5 100644 --- a/test/cmdlineTests/revert_strings/output +++ b/test/cmdlineTests/revert_strings/output @@ -25,14 +25,6 @@ object "C_15" { memPtr := mload(64) } - /// @src 0:59:147 - function constructor_C_15() { - - /// @src 0:59:147 - - } - /// @src 0:59:147 - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { let start := allocate_unbounded() @@ -52,6 +44,14 @@ object "C_15" { } + /// @src 0:59:147 + function constructor_C_15() { + + /// @src 0:59:147 + + } + /// @src 0:59:147 + } /// @use-src 0:"revert_strings/input.sol" object "C_15_deployed" { @@ -81,233 +81,17 @@ object "C_15" { if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() - // uint256[][] - function abi_decode_available_length_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptr(offset, length, end) -> array { - array := allocate_memory(array_allocation_size_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptr(length)) - let dst := array + function shift_right_224_unsigned(value) -> newValue { + newValue := - mstore(array, length) - dst := add(array, 0x20) + shr(224, value) - let src := offset - if gt(add(src, mul(length, 0x20)), end) { - revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef() - } - for { let i := 0 } lt(i, length) { i := add(i, 1) } - { - - let innerOffset := calldataload(src) - if gt(innerOffset, 0xffffffffffffffff) { revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d() } - let elementPos := add(offset, innerOffset) - - mstore(dst, abi_decode_t_array$_t_uint256_$dyn_memory_ptr(elementPos, end)) - dst := add(dst, 0x20) - src := add(src, 0x20) - } - } - - // uint256[] - function abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr(offset, length, end) -> array { - array := allocate_memory(array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr(length)) - let dst := array - - mstore(array, length) - dst := add(array, 0x20) - - let src := offset - if gt(add(src, mul(length, 0x20)), end) { - revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef() - } - for { let i := 0 } lt(i, length) { i := add(i, 1) } - { - - let elementPos := src - - mstore(dst, abi_decode_t_uint256(elementPos, end)) - dst := add(dst, 0x20) - src := add(src, 0x20) - } - } - - // uint256[][] - function abi_decode_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptr(offset, end) -> array { - if iszero(slt(add(offset, 0x1f), end)) { revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d() } - let length := calldataload(offset) - array := abi_decode_available_length_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptr(add(offset, 0x20), length, end) - } - - // uint256[] - function abi_decode_t_array$_t_uint256_$dyn_memory_ptr(offset, end) -> array { - if iszero(slt(add(offset, 0x1f), end)) { revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d() } - let length := calldataload(offset) - array := abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr(add(offset, 0x20), length, end) - } - - function abi_decode_t_enum$_E_$3(offset, end) -> value { - value := calldataload(offset) - validator_revert_t_enum$_E_$3(value) - } - - function abi_decode_t_uint256(offset, end) -> value { - value := calldataload(offset) - validator_revert_t_uint256(value) - } - - function abi_decode_tuple_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptrt_enum$_E_$3(headStart, dataEnd) -> value0, value1 { - if slt(sub(dataEnd, headStart), 64) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } - - { - - let offset := calldataload(add(headStart, 0)) - if gt(offset, 0xffffffffffffffff) { revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() } - - value0 := abi_decode_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptr(add(headStart, offset), dataEnd) - } - - { - - let offset := 32 - - value1 := abi_decode_t_enum$_E_$3(add(headStart, offset), dataEnd) - } - - } - - function abi_encode_tuple__to__fromStack(headStart ) -> tail { - tail := add(headStart, 0) - - } - - function allocate_memory(size) -> memPtr { - memPtr := allocate_unbounded() - finalize_allocation(memPtr, size) } function allocate_unbounded() -> memPtr { memPtr := mload(64) } - function array_allocation_size_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptr(length) -> size { - // Make sure we can allocate memory without overflow - if gt(length, 0xffffffffffffffff) { panic_error_0x41() } - - size := mul(length, 0x20) - - // add length slot - size := add(size, 0x20) - - } - - function array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr(length) -> size { - // Make sure we can allocate memory without overflow - if gt(length, 0xffffffffffffffff) { panic_error_0x41() } - - size := mul(length, 0x20) - - // add length slot - size := add(size, 0x20) - - } - - function cleanup_t_uint256(value) -> cleaned { - cleaned := value - } - - function finalize_allocation(memPtr, size) { - let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) - // protect against overflow - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } - mstore(64, newFreePtr) - } - - /// @src 0:93:145 - function fun_f_14(var__7_mpos, var_e_10) { - - } - /// @src 0:59:147 - - function panic_error_0x41() { - mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) - mstore(4, 0x41) - revert(0, 0x24) - } - - function revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d() { - - let start := allocate_unbounded() - let pos := start - mstore(pos, 3963877391197344453575983046348115674221700746820753546331534351508065746944) - pos := add(pos, 4) - mstore(pos, 0x20) - pos := add(pos, 0x20) - mstore(pos, 43) - pos := add(pos, 0x20) - - mstore(add(pos, 0), "ABI decoding: invalid calldata a") - - mstore(add(pos, 32), "rray offset") - - revert(start, 132) - - } - - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { - - let start := allocate_unbounded() - let pos := start - mstore(pos, 3963877391197344453575983046348115674221700746820753546331534351508065746944) - pos := add(pos, 4) - mstore(pos, 0x20) - pos := add(pos, 0x20) - mstore(pos, 53) - pos := add(pos, 0x20) - - mstore(add(pos, 0), "Contract does not have fallback ") - - mstore(add(pos, 32), "nor receive functions") - - revert(start, 132) - - } - - function revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef() { - - let start := allocate_unbounded() - let pos := start - mstore(pos, 3963877391197344453575983046348115674221700746820753546331534351508065746944) - pos := add(pos, 4) - mstore(pos, 0x20) - pos := add(pos, 0x20) - mstore(pos, 43) - pos := add(pos, 0x20) - - mstore(add(pos, 0), "ABI decoding: invalid calldata a") - - mstore(add(pos, 32), "rray stride") - - revert(start, 132) - - } - - function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { - - let start := allocate_unbounded() - let pos := start - mstore(pos, 3963877391197344453575983046348115674221700746820753546331534351508065746944) - pos := add(pos, 4) - mstore(pos, 0x20) - pos := add(pos, 0x20) - mstore(pos, 34) - pos := add(pos, 0x20) - - mstore(add(pos, 0), "ABI decoding: invalid tuple offs") - - mstore(add(pos, 32), "et") - - revert(start, 132) - - } - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { let start := allocate_unbounded() @@ -346,25 +130,241 @@ object "C_15" { } + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + + let start := allocate_unbounded() + let pos := start + mstore(pos, 3963877391197344453575983046348115674221700746820753546331534351508065746944) + pos := add(pos, 4) + mstore(pos, 0x20) + pos := add(pos, 0x20) + mstore(pos, 34) + pos := add(pos, 0x20) + + mstore(add(pos, 0), "ABI decoding: invalid tuple offs") + + mstore(add(pos, 32), "et") + + revert(start, 132) + + } + + function revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d() { + + let start := allocate_unbounded() + let pos := start + mstore(pos, 3963877391197344453575983046348115674221700746820753546331534351508065746944) + pos := add(pos, 4) + mstore(pos, 0x20) + pos := add(pos, 0x20) + mstore(pos, 43) + pos := add(pos, 0x20) + + mstore(add(pos, 0), "ABI decoding: invalid calldata a") + + mstore(add(pos, 32), "rray offset") + + revert(start, 132) + + } + function round_up_to_mul_of_32(value) -> result { result := and(add(value, 31), not(31)) } - function shift_right_224_unsigned(value) -> newValue { - newValue := + function panic_error_0x41() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x41) + revert(0, 0x24) + } - shr(224, value) + function finalize_allocation(memPtr, size) { + let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) + // protect against overflow + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } + mstore(64, newFreePtr) + } + function allocate_memory(size) -> memPtr { + memPtr := allocate_unbounded() + finalize_allocation(memPtr, size) + } + + function array_allocation_size_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptr(length) -> size { + // Make sure we can allocate memory without overflow + if gt(length, 0xffffffffffffffff) { panic_error_0x41() } + + size := mul(length, 0x20) + + // add length slot + size := add(size, 0x20) + + } + + function revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef() { + + let start := allocate_unbounded() + let pos := start + mstore(pos, 3963877391197344453575983046348115674221700746820753546331534351508065746944) + pos := add(pos, 4) + mstore(pos, 0x20) + pos := add(pos, 0x20) + mstore(pos, 43) + pos := add(pos, 0x20) + + mstore(add(pos, 0), "ABI decoding: invalid calldata a") + + mstore(add(pos, 32), "rray stride") + + revert(start, 132) + + } + + function array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr(length) -> size { + // Make sure we can allocate memory without overflow + if gt(length, 0xffffffffffffffff) { panic_error_0x41() } + + size := mul(length, 0x20) + + // add length slot + size := add(size, 0x20) + + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } + + // uint256[] + function abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr(offset, length, end) -> array { + array := allocate_memory(array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr(length)) + let dst := array + + mstore(array, length) + dst := add(array, 0x20) + + let src := offset + if gt(add(src, mul(length, 0x20)), end) { + revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef() + } + for { let i := 0 } lt(i, length) { i := add(i, 1) } + { + + let elementPos := src + + mstore(dst, abi_decode_t_uint256(elementPos, end)) + dst := add(dst, 0x20) + src := add(src, 0x20) + } + } + + // uint256[] + function abi_decode_t_array$_t_uint256_$dyn_memory_ptr(offset, end) -> array { + if iszero(slt(add(offset, 0x1f), end)) { revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d() } + let length := calldataload(offset) + array := abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr(add(offset, 0x20), length, end) + } + + // uint256[][] + function abi_decode_available_length_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptr(offset, length, end) -> array { + array := allocate_memory(array_allocation_size_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptr(length)) + let dst := array + + mstore(array, length) + dst := add(array, 0x20) + + let src := offset + if gt(add(src, mul(length, 0x20)), end) { + revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef() + } + for { let i := 0 } lt(i, length) { i := add(i, 1) } + { + + let innerOffset := calldataload(src) + if gt(innerOffset, 0xffffffffffffffff) { revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d() } + let elementPos := add(offset, innerOffset) + + mstore(dst, abi_decode_t_array$_t_uint256_$dyn_memory_ptr(elementPos, end)) + dst := add(dst, 0x20) + src := add(src, 0x20) + } + } + + // uint256[][] + function abi_decode_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptr(offset, end) -> array { + if iszero(slt(add(offset, 0x1f), end)) { revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d() } + let length := calldataload(offset) + array := abi_decode_available_length_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptr(add(offset, 0x20), length, end) } function validator_revert_t_enum$_E_$3(value) { if iszero(lt(value, 1)) { revert(0, 0) } } - function validator_revert_t_uint256(value) { - if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + function abi_decode_t_enum$_E_$3(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_enum$_E_$3(value) } + function abi_decode_tuple_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptrt_enum$_E_$3(headStart, dataEnd) -> value0, value1 { + if slt(sub(dataEnd, headStart), 64) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := calldataload(add(headStart, 0)) + if gt(offset, 0xffffffffffffffff) { revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() } + + value0 := abi_decode_t_array$_t_array$_t_uint256_$dyn_memory_ptr_$dyn_memory_ptr(add(headStart, offset), dataEnd) + } + + { + + let offset := 32 + + value1 := abi_decode_t_enum$_E_$3(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + + let start := allocate_unbounded() + let pos := start + mstore(pos, 3963877391197344453575983046348115674221700746820753546331534351508065746944) + pos := add(pos, 4) + mstore(pos, 0x20) + pos := add(pos, 0x20) + mstore(pos, 53) + pos := add(pos, 0x20) + + mstore(add(pos, 0), "Contract does not have fallback ") + + mstore(add(pos, 32), "nor receive functions") + + revert(start, 132) + + } + + /// @src 0:93:145 + function fun_f_14(var__7_mpos, var_e_10) { + + } + /// @src 0:59:147 + } data ".metadata" hex"" diff --git a/test/cmdlineTests/standard_function_debug_info/output.json b/test/cmdlineTests/standard_function_debug_info/output.json index e0e6d7257..ed0de9572 100644 --- a/test/cmdlineTests/standard_function_debug_info/output.json +++ b/test/cmdlineTests/standard_function_debug_info/output.json @@ -1 +1 @@ -{"contracts":{"a.sol":{"A":{"evm":{"bytecode":{"functionDebugData":{}},"deployedBytecode":{"functionDebugData":{"@f_19":{"entryPoint":96,"id":19,"parameterSlots":1,"returnSlots":1},"abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":171,"id":null,"parameterSlots":3,"returnSlots":1},"abi_decode_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":283,"id":null,"parameterSlots":2,"returnSlots":1},"abi_decode_t_uint256":{"entryPoint":329,"id":null,"parameterSlots":2,"returnSlots":1},"abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":350,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_t_uint256_to_t_uint256_fromStack":{"entryPoint":423,"id":null,"parameterSlots":2,"returnSlots":0},"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed":{"entryPoint":438,"id":null,"parameterSlots":2,"returnSlots":1},"allocate_memory":{"entryPoint":465,"id":null,"parameterSlots":1,"returnSlots":1},"allocate_unbounded":{"entryPoint":492,"id":null,"parameterSlots":0,"returnSlots":1},"array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":502,"id":null,"parameterSlots":1,"returnSlots":1},"checked_add_t_uint256":{"entryPoint":546,"id":null,"parameterSlots":2,"returnSlots":1},"cleanup_t_uint256":{"entryPoint":632,"id":null,"parameterSlots":1,"returnSlots":1},"finalize_allocation":{"entryPoint":642,"id":null,"parameterSlots":2,"returnSlots":0},"panic_error_0x11":{"entryPoint":691,"id":null,"parameterSlots":0,"returnSlots":0},"panic_error_0x32":{"entryPoint":738,"id":null,"parameterSlots":0,"returnSlots":0},"panic_error_0x41":{"entryPoint":785,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d":{"entryPoint":832,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef":{"entryPoint":837,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db":{"entryPoint":842,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b":{"entryPoint":847,"id":null,"parameterSlots":0,"returnSlots":0},"round_up_to_mul_of_32":{"entryPoint":852,"id":null,"parameterSlots":1,"returnSlots":1},"validator_revert_t_uint256":{"entryPoint":869,"id":null,"parameterSlots":1,"returnSlots":0}}}}}}},"sources":{"a.sol":{"id":0}}} +{"contracts":{"a.sol":{"A":{"evm":{"bytecode":{"functionDebugData":{}},"deployedBytecode":{"functionDebugData":{"@f_19":{"entryPoint":96,"id":19,"parameterSlots":1,"returnSlots":1},"abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":439,"id":null,"parameterSlots":3,"returnSlots":1},"abi_decode_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":551,"id":null,"parameterSlots":2,"returnSlots":1},"abi_decode_t_uint256":{"entryPoint":418,"id":null,"parameterSlots":2,"returnSlots":1},"abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":597,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_t_uint256_to_t_uint256_fromStack":{"entryPoint":670,"id":null,"parameterSlots":2,"returnSlots":0},"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed":{"entryPoint":685,"id":null,"parameterSlots":2,"returnSlots":1},"allocate_memory":{"entryPoint":309,"id":null,"parameterSlots":1,"returnSlots":1},"allocate_unbounded":{"entryPoint":171,"id":null,"parameterSlots":0,"returnSlots":1},"array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":336,"id":null,"parameterSlots":1,"returnSlots":1},"checked_add_t_uint256":{"entryPoint":806,"id":null,"parameterSlots":2,"returnSlots":1},"cleanup_t_uint256":{"entryPoint":385,"id":null,"parameterSlots":1,"returnSlots":1},"finalize_allocation":{"entryPoint":260,"id":null,"parameterSlots":2,"returnSlots":0},"panic_error_0x11":{"entryPoint":759,"id":null,"parameterSlots":0,"returnSlots":0},"panic_error_0x32":{"entryPoint":712,"id":null,"parameterSlots":0,"returnSlots":0},"panic_error_0x41":{"entryPoint":213,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d":{"entryPoint":191,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef":{"entryPoint":380,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db":{"entryPoint":186,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b":{"entryPoint":181,"id":null,"parameterSlots":0,"returnSlots":0},"round_up_to_mul_of_32":{"entryPoint":196,"id":null,"parameterSlots":1,"returnSlots":1},"validator_revert_t_uint256":{"entryPoint":395,"id":null,"parameterSlots":1,"returnSlots":0}}}}}}},"sources":{"a.sol":{"id":0}}} diff --git a/test/cmdlineTests/standard_generatedSources/output.json b/test/cmdlineTests/standard_generatedSources/output.json index b09f6750f..6c7f72b6a 100644 --- a/test/cmdlineTests/standard_generatedSources/output.json +++ b/test/cmdlineTests/standard_generatedSources/output.json @@ -1,4 +1,70 @@ -{"contracts":{"a.sol":{"A":{"evm":{"bytecode":{"generatedSources":[],"object":""},"deployedBytecode":{"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:4001:1","statements":[{"body":{"nodeType":"YulBlock","src":"126:620:1","statements":[{"nodeType":"YulAssignment","src":"136:90:1","value":{"arguments":[{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"218:6:1"}],"functionName":{"name":"array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulIdentifier","src":"161:56:1"},"nodeType":"YulFunctionCall","src":"161:64:1"}],"functionName":{"name":"allocate_memory","nodeType":"YulIdentifier","src":"145:15:1"},"nodeType":"YulFunctionCall","src":"145:81:1"},"variableNames":[{"name":"array","nodeType":"YulIdentifier","src":"136:5:1"}]},{"nodeType":"YulVariableDeclaration","src":"235:16:1","value":{"name":"array","nodeType":"YulIdentifier","src":"246:5:1"},"variables":[{"name":"dst","nodeType":"YulTypedName","src":"239:3:1","type":""}]},{"expression":{"arguments":[{"name":"array","nodeType":"YulIdentifier","src":"268:5:1"},{"name":"length","nodeType":"YulIdentifier","src":"275:6:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"261:6:1"},"nodeType":"YulFunctionCall","src":"261:21:1"},"nodeType":"YulExpressionStatement","src":"261:21:1"},{"nodeType":"YulAssignment","src":"291:23:1","value":{"arguments":[{"name":"array","nodeType":"YulIdentifier","src":"302:5:1"},{"kind":"number","nodeType":"YulLiteral","src":"309:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"298:3:1"},"nodeType":"YulFunctionCall","src":"298:16:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"291:3:1"}]},{"nodeType":"YulVariableDeclaration","src":"324:17:1","value":{"name":"offset","nodeType":"YulIdentifier","src":"335:6:1"},"variables":[{"name":"src","nodeType":"YulTypedName","src":"328:3:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"390:103:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef","nodeType":"YulIdentifier","src":"404:77:1"},"nodeType":"YulFunctionCall","src":"404:79:1"},"nodeType":"YulExpressionStatement","src":"404:79:1"}]},"condition":{"arguments":[{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"360:3:1"},{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"369:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"377:4:1","type":"","value":"0x20"}],"functionName":{"name":"mul","nodeType":"YulIdentifier","src":"365:3:1"},"nodeType":"YulFunctionCall","src":"365:17:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"356:3:1"},"nodeType":"YulFunctionCall","src":"356:27:1"},{"name":"end","nodeType":"YulIdentifier","src":"385:3:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"353:2:1"},"nodeType":"YulFunctionCall","src":"353:36:1"},"nodeType":"YulIf","src":"350:143:1"},{"body":{"nodeType":"YulBlock","src":"562:178:1","statements":[{"nodeType":"YulVariableDeclaration","src":"577:21:1","value":{"name":"src","nodeType":"YulIdentifier","src":"595:3:1"},"variables":[{"name":"elementPos","nodeType":"YulTypedName","src":"581:10:1","type":""}]},{"expression":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"619:3:1"},{"arguments":[{"name":"elementPos","nodeType":"YulIdentifier","src":"645:10:1"},{"name":"end","nodeType":"YulIdentifier","src":"657:3:1"}],"functionName":{"name":"abi_decode_t_uint256","nodeType":"YulIdentifier","src":"624:20:1"},"nodeType":"YulFunctionCall","src":"624:37:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"612:6:1"},"nodeType":"YulFunctionCall","src":"612:50:1"},"nodeType":"YulExpressionStatement","src":"612:50:1"},{"nodeType":"YulAssignment","src":"675:21:1","value":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"686:3:1"},{"kind":"number","nodeType":"YulLiteral","src":"691:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"682:3:1"},"nodeType":"YulFunctionCall","src":"682:14:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"675:3:1"}]},{"nodeType":"YulAssignment","src":"709:21:1","value":{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"720:3:1"},{"kind":"number","nodeType":"YulLiteral","src":"725:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"716:3:1"},"nodeType":"YulFunctionCall","src":"716:14:1"},"variableNames":[{"name":"src","nodeType":"YulIdentifier","src":"709:3:1"}]}]},"condition":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"524:1:1"},{"name":"length","nodeType":"YulIdentifier","src":"527:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"521:2:1"},"nodeType":"YulFunctionCall","src":"521:13:1"},"nodeType":"YulForLoop","post":{"nodeType":"YulBlock","src":"535:18:1","statements":[{"nodeType":"YulAssignment","src":"537:14:1","value":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"546:1:1"},{"kind":"number","nodeType":"YulLiteral","src":"549:1:1","type":"","value":"1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"542:3:1"},"nodeType":"YulFunctionCall","src":"542:9:1"},"variableNames":[{"name":"i","nodeType":"YulIdentifier","src":"537:1:1"}]}]},"pre":{"nodeType":"YulBlock","src":"506:14:1","statements":[{"nodeType":"YulVariableDeclaration","src":"508:10:1","value":{"kind":"number","nodeType":"YulLiteral","src":"517:1:1","type":"","value":"0"},"variables":[{"name":"i","nodeType":"YulTypedName","src":"512:1:1","type":""}]}]},"src":"502:238:1"}]},"name":"abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"offset","nodeType":"YulTypedName","src":"96:6:1","type":""},{"name":"length","nodeType":"YulTypedName","src":"104:6:1","type":""},{"name":"end","nodeType":"YulTypedName","src":"112:3:1","type":""}],"returnVariables":[{"name":"array","nodeType":"YulTypedName","src":"120:5:1","type":""}],"src":"24:722:1"},{"body":{"nodeType":"YulBlock","src":"846:293:1","statements":[{"body":{"nodeType":"YulBlock","src":"895:83:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d","nodeType":"YulIdentifier","src":"897:77:1"},"nodeType":"YulFunctionCall","src":"897:79:1"},"nodeType":"YulExpressionStatement","src":"897:79:1"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"874:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"882:4:1","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"870:3:1"},"nodeType":"YulFunctionCall","src":"870:17:1"},{"name":"end","nodeType":"YulIdentifier","src":"889:3:1"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"866:3:1"},"nodeType":"YulFunctionCall","src":"866:27:1"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"859:6:1"},"nodeType":"YulFunctionCall","src":"859:35:1"},"nodeType":"YulIf","src":"856:122:1"},{"nodeType":"YulVariableDeclaration","src":"987:34:1","value":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"1014:6:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"1001:12:1"},"nodeType":"YulFunctionCall","src":"1001:20:1"},"variables":[{"name":"length","nodeType":"YulTypedName","src":"991:6:1","type":""}]},{"nodeType":"YulAssignment","src":"1030:103:1","value":{"arguments":[{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"1106:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"1114:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1102:3:1"},"nodeType":"YulFunctionCall","src":"1102:17:1"},{"name":"length","nodeType":"YulIdentifier","src":"1121:6:1"},{"name":"end","nodeType":"YulIdentifier","src":"1129:3:1"}],"functionName":{"name":"abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulIdentifier","src":"1039:62:1"},"nodeType":"YulFunctionCall","src":"1039:94:1"},"variableNames":[{"name":"array","nodeType":"YulIdentifier","src":"1030:5:1"}]}]},"name":"abi_decode_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"offset","nodeType":"YulTypedName","src":"824:6:1","type":""},{"name":"end","nodeType":"YulTypedName","src":"832:3:1","type":""}],"returnVariables":[{"name":"array","nodeType":"YulTypedName","src":"840:5:1","type":""}],"src":"769:370:1"},{"body":{"nodeType":"YulBlock","src":"1197:87:1","statements":[{"nodeType":"YulAssignment","src":"1207:29:1","value":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"1229:6:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"1216:12:1"},"nodeType":"YulFunctionCall","src":"1216:20:1"},"variableNames":[{"name":"value","nodeType":"YulIdentifier","src":"1207:5:1"}]},{"expression":{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"1272:5:1"}],"functionName":{"name":"validator_revert_t_uint256","nodeType":"YulIdentifier","src":"1245:26:1"},"nodeType":"YulFunctionCall","src":"1245:33:1"},"nodeType":"YulExpressionStatement","src":"1245:33:1"}]},"name":"abi_decode_t_uint256","nodeType":"YulFunctionDefinition","parameters":[{"name":"offset","nodeType":"YulTypedName","src":"1175:6:1","type":""},{"name":"end","nodeType":"YulTypedName","src":"1183:3:1","type":""}],"returnVariables":[{"name":"value","nodeType":"YulTypedName","src":"1191:5:1","type":""}],"src":"1145:139:1"},{"body":{"nodeType":"YulBlock","src":"1381:448:1","statements":[{"body":{"nodeType":"YulBlock","src":"1427:83:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b","nodeType":"YulIdentifier","src":"1429:77:1"},"nodeType":"YulFunctionCall","src":"1429:79:1"},"nodeType":"YulExpressionStatement","src":"1429:79:1"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"1402:7:1"},{"name":"headStart","nodeType":"YulIdentifier","src":"1411:9:1"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"1398:3:1"},"nodeType":"YulFunctionCall","src":"1398:23:1"},{"kind":"number","nodeType":"YulLiteral","src":"1423:2:1","type":"","value":"32"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"1394:3:1"},"nodeType":"YulFunctionCall","src":"1394:32:1"},"nodeType":"YulIf","src":"1391:119:1"},{"nodeType":"YulBlock","src":"1520:302:1","statements":[{"nodeType":"YulVariableDeclaration","src":"1535:45:1","value":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1566:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"1577:1:1","type":"","value":"0"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1562:3:1"},"nodeType":"YulFunctionCall","src":"1562:17:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"1549:12:1"},"nodeType":"YulFunctionCall","src":"1549:31:1"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"1539:6:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"1627:83:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db","nodeType":"YulIdentifier","src":"1629:77:1"},"nodeType":"YulFunctionCall","src":"1629:79:1"},"nodeType":"YulExpressionStatement","src":"1629:79:1"}]},"condition":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"1599:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"1607:18:1","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"1596:2:1"},"nodeType":"YulFunctionCall","src":"1596:30:1"},"nodeType":"YulIf","src":"1593:117:1"},{"nodeType":"YulAssignment","src":"1724:88:1","value":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1784:9:1"},{"name":"offset","nodeType":"YulIdentifier","src":"1795:6:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1780:3:1"},"nodeType":"YulFunctionCall","src":"1780:22:1"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"1804:7:1"}],"functionName":{"name":"abi_decode_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulIdentifier","src":"1734:45:1"},"nodeType":"YulFunctionCall","src":"1734:78:1"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"1724:6:1"}]}]}]},"name":"abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"1351:9:1","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"1362:7:1","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"1374:6:1","type":""}],"src":"1290:539:1"},{"body":{"nodeType":"YulBlock","src":"1900:53:1","statements":[{"expression":{"arguments":[{"name":"pos","nodeType":"YulIdentifier","src":"1917:3:1"},{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"1940:5:1"}],"functionName":{"name":"cleanup_t_uint256","nodeType":"YulIdentifier","src":"1922:17:1"},"nodeType":"YulFunctionCall","src":"1922:24:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1910:6:1"},"nodeType":"YulFunctionCall","src":"1910:37:1"},"nodeType":"YulExpressionStatement","src":"1910:37:1"}]},"name":"abi_encode_t_uint256_to_t_uint256_fromStack","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"1888:5:1","type":""},{"name":"pos","nodeType":"YulTypedName","src":"1895:3:1","type":""}],"src":"1835:118:1"},{"body":{"nodeType":"YulBlock","src":"2057:124:1","statements":[{"nodeType":"YulAssignment","src":"2067:26:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2079:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"2090:2:1","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2075:3:1"},"nodeType":"YulFunctionCall","src":"2075:18:1"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"2067:4:1"}]},{"expression":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"2147:6:1"},{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"2160:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"2171:1:1","type":"","value":"0"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2156:3:1"},"nodeType":"YulFunctionCall","src":"2156:17:1"}],"functionName":{"name":"abi_encode_t_uint256_to_t_uint256_fromStack","nodeType":"YulIdentifier","src":"2103:43:1"},"nodeType":"YulFunctionCall","src":"2103:71:1"},"nodeType":"YulExpressionStatement","src":"2103:71:1"}]},"name":"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"2029:9:1","type":""},{"name":"value0","nodeType":"YulTypedName","src":"2041:6:1","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"2052:4:1","type":""}],"src":"1959:222:1"},{"body":{"nodeType":"YulBlock","src":"2228:88:1","statements":[{"nodeType":"YulAssignment","src":"2238:30:1","value":{"arguments":[],"functionName":{"name":"allocate_unbounded","nodeType":"YulIdentifier","src":"2248:18:1"},"nodeType":"YulFunctionCall","src":"2248:20:1"},"variableNames":[{"name":"memPtr","nodeType":"YulIdentifier","src":"2238:6:1"}]},{"expression":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"2297:6:1"},{"name":"size","nodeType":"YulIdentifier","src":"2305:4:1"}],"functionName":{"name":"finalize_allocation","nodeType":"YulIdentifier","src":"2277:19:1"},"nodeType":"YulFunctionCall","src":"2277:33:1"},"nodeType":"YulExpressionStatement","src":"2277:33:1"}]},"name":"allocate_memory","nodeType":"YulFunctionDefinition","parameters":[{"name":"size","nodeType":"YulTypedName","src":"2212:4:1","type":""}],"returnVariables":[{"name":"memPtr","nodeType":"YulTypedName","src":"2221:6:1","type":""}],"src":"2187:129:1"},{"body":{"nodeType":"YulBlock","src":"2362:35:1","statements":[{"nodeType":"YulAssignment","src":"2372:19:1","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"2388:2:1","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"2382:5:1"},"nodeType":"YulFunctionCall","src":"2382:9:1"},"variableNames":[{"name":"memPtr","nodeType":"YulIdentifier","src":"2372:6:1"}]}]},"name":"allocate_unbounded","nodeType":"YulFunctionDefinition","returnVariables":[{"name":"memPtr","nodeType":"YulTypedName","src":"2355:6:1","type":""}],"src":"2322:75:1"},{"body":{"nodeType":"YulBlock","src":"2485:229:1","statements":[{"body":{"nodeType":"YulBlock","src":"2590:22:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"2592:16:1"},"nodeType":"YulFunctionCall","src":"2592:18:1"},"nodeType":"YulExpressionStatement","src":"2592:18:1"}]},"condition":{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"2562:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"2570:18:1","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"2559:2:1"},"nodeType":"YulFunctionCall","src":"2559:30:1"},"nodeType":"YulIf","src":"2556:56:1"},{"nodeType":"YulAssignment","src":"2622:25:1","value":{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"2634:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"2642:4:1","type":"","value":"0x20"}],"functionName":{"name":"mul","nodeType":"YulIdentifier","src":"2630:3:1"},"nodeType":"YulFunctionCall","src":"2630:17:1"},"variableNames":[{"name":"size","nodeType":"YulIdentifier","src":"2622:4:1"}]},{"nodeType":"YulAssignment","src":"2684:23:1","value":{"arguments":[{"name":"size","nodeType":"YulIdentifier","src":"2696:4:1"},{"kind":"number","nodeType":"YulLiteral","src":"2702:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2692:3:1"},"nodeType":"YulFunctionCall","src":"2692:15:1"},"variableNames":[{"name":"size","nodeType":"YulIdentifier","src":"2684:4:1"}]}]},"name":"array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"length","nodeType":"YulTypedName","src":"2469:6:1","type":""}],"returnVariables":[{"name":"size","nodeType":"YulTypedName","src":"2480:4:1","type":""}],"src":"2403:311:1"},{"body":{"nodeType":"YulBlock","src":"2765:32:1","statements":[{"nodeType":"YulAssignment","src":"2775:16:1","value":{"name":"value","nodeType":"YulIdentifier","src":"2786:5:1"},"variableNames":[{"name":"cleaned","nodeType":"YulIdentifier","src":"2775:7:1"}]}]},"name":"cleanup_t_uint256","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"2747:5:1","type":""}],"returnVariables":[{"name":"cleaned","nodeType":"YulTypedName","src":"2757:7:1","type":""}],"src":"2720:77:1"},{"body":{"nodeType":"YulBlock","src":"2846:238:1","statements":[{"nodeType":"YulVariableDeclaration","src":"2856:58:1","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"2878:6:1"},{"arguments":[{"name":"size","nodeType":"YulIdentifier","src":"2908:4:1"}],"functionName":{"name":"round_up_to_mul_of_32","nodeType":"YulIdentifier","src":"2886:21:1"},"nodeType":"YulFunctionCall","src":"2886:27:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2874:3:1"},"nodeType":"YulFunctionCall","src":"2874:40:1"},"variables":[{"name":"newFreePtr","nodeType":"YulTypedName","src":"2860:10:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"3025:22:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"3027:16:1"},"nodeType":"YulFunctionCall","src":"3027:18:1"},"nodeType":"YulExpressionStatement","src":"3027:18:1"}]},"condition":{"arguments":[{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"2968:10:1"},{"kind":"number","nodeType":"YulLiteral","src":"2980:18:1","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"2965:2:1"},"nodeType":"YulFunctionCall","src":"2965:34:1"},{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"3004:10:1"},{"name":"memPtr","nodeType":"YulIdentifier","src":"3016:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"3001:2:1"},"nodeType":"YulFunctionCall","src":"3001:22:1"}],"functionName":{"name":"or","nodeType":"YulIdentifier","src":"2962:2:1"},"nodeType":"YulFunctionCall","src":"2962:62:1"},"nodeType":"YulIf","src":"2959:88:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3063:2:1","type":"","value":"64"},{"name":"newFreePtr","nodeType":"YulIdentifier","src":"3067:10:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3056:6:1"},"nodeType":"YulFunctionCall","src":"3056:22:1"},"nodeType":"YulExpressionStatement","src":"3056:22:1"}]},"name":"finalize_allocation","nodeType":"YulFunctionDefinition","parameters":[{"name":"memPtr","nodeType":"YulTypedName","src":"2832:6:1","type":""},{"name":"size","nodeType":"YulTypedName","src":"2840:4:1","type":""}],"src":"2803:281:1"},{"body":{"nodeType":"YulBlock","src":"3118:152:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3135:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"3138:77:1","type":"","value":"35408467139433450592217433187231851964531694900788300625387963629091585785856"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3128:6:1"},"nodeType":"YulFunctionCall","src":"3128:88:1"},"nodeType":"YulExpressionStatement","src":"3128:88:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3232:1:1","type":"","value":"4"},{"kind":"number","nodeType":"YulLiteral","src":"3235:4:1","type":"","value":"0x41"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3225:6:1"},"nodeType":"YulFunctionCall","src":"3225:15:1"},"nodeType":"YulExpressionStatement","src":"3225:15:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3256:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"3259:4:1","type":"","value":"0x24"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"3249:6:1"},"nodeType":"YulFunctionCall","src":"3249:15:1"},"nodeType":"YulExpressionStatement","src":"3249:15:1"}]},"name":"panic_error_0x41","nodeType":"YulFunctionDefinition","src":"3090:180:1"},{"body":{"nodeType":"YulBlock","src":"3365:28:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3382:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"3385:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"3375:6:1"},"nodeType":"YulFunctionCall","src":"3375:12:1"},"nodeType":"YulExpressionStatement","src":"3375:12:1"}]},"name":"revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d","nodeType":"YulFunctionDefinition","src":"3276:117:1"},{"body":{"nodeType":"YulBlock","src":"3488:28:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3505:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"3508:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"3498:6:1"},"nodeType":"YulFunctionCall","src":"3498:12:1"},"nodeType":"YulExpressionStatement","src":"3498:12:1"}]},"name":"revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef","nodeType":"YulFunctionDefinition","src":"3399:117:1"},{"body":{"nodeType":"YulBlock","src":"3611:28:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3628:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"3631:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"3621:6:1"},"nodeType":"YulFunctionCall","src":"3621:12:1"},"nodeType":"YulExpressionStatement","src":"3621:12:1"}]},"name":"revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db","nodeType":"YulFunctionDefinition","src":"3522:117:1"},{"body":{"nodeType":"YulBlock","src":"3734:28:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3751:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"3754:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"3744:6:1"},"nodeType":"YulFunctionCall","src":"3744:12:1"},"nodeType":"YulExpressionStatement","src":"3744:12:1"}]},"name":"revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b","nodeType":"YulFunctionDefinition","src":"3645:117:1"},{"body":{"nodeType":"YulBlock","src":"3816:54:1","statements":[{"nodeType":"YulAssignment","src":"3826:38:1","value":{"arguments":[{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"3844:5:1"},{"kind":"number","nodeType":"YulLiteral","src":"3851:2:1","type":"","value":"31"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3840:3:1"},"nodeType":"YulFunctionCall","src":"3840:14:1"},{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3860:2:1","type":"","value":"31"}],"functionName":{"name":"not","nodeType":"YulIdentifier","src":"3856:3:1"},"nodeType":"YulFunctionCall","src":"3856:7:1"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"3836:3:1"},"nodeType":"YulFunctionCall","src":"3836:28:1"},"variableNames":[{"name":"result","nodeType":"YulIdentifier","src":"3826:6:1"}]}]},"name":"round_up_to_mul_of_32","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"3799:5:1","type":""}],"returnVariables":[{"name":"result","nodeType":"YulTypedName","src":"3809:6:1","type":""}],"src":"3768:102:1"},{"body":{"nodeType":"YulBlock","src":"3919:79:1","statements":[{"body":{"nodeType":"YulBlock","src":"3976:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"3985:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"3988:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"3978:6:1"},"nodeType":"YulFunctionCall","src":"3978:12:1"},"nodeType":"YulExpressionStatement","src":"3978:12:1"}]},"condition":{"arguments":[{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"3942:5:1"},{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"3967:5:1"}],"functionName":{"name":"cleanup_t_uint256","nodeType":"YulIdentifier","src":"3949:17:1"},"nodeType":"YulFunctionCall","src":"3949:24:1"}],"functionName":{"name":"eq","nodeType":"YulIdentifier","src":"3939:2:1"},"nodeType":"YulFunctionCall","src":"3939:35:1"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"3932:6:1"},"nodeType":"YulFunctionCall","src":"3932:43:1"},"nodeType":"YulIf","src":"3929:63:1"}]},"name":"validator_revert_t_uint256","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"3912:5:1","type":""}],"src":"3876:122:1"}]},"contents":"{ +{"contracts":{"a.sol":{"A":{"evm":{"bytecode":{"generatedSources":[],"object":""},"deployedBytecode":{"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:4001:1","statements":[{"body":{"nodeType":"YulBlock","src":"47:35:1","statements":[{"nodeType":"YulAssignment","src":"57:19:1","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"73:2:1","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"67:5:1"},"nodeType":"YulFunctionCall","src":"67:9:1"},"variableNames":[{"name":"memPtr","nodeType":"YulIdentifier","src":"57:6:1"}]}]},"name":"allocate_unbounded","nodeType":"YulFunctionDefinition","returnVariables":[{"name":"memPtr","nodeType":"YulTypedName","src":"40:6:1","type":""}],"src":"7:75:1"},{"body":{"nodeType":"YulBlock","src":"177:28:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"194:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"197:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"187:6:1"},"nodeType":"YulFunctionCall","src":"187:12:1"},"nodeType":"YulExpressionStatement","src":"187:12:1"}]},"name":"revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b","nodeType":"YulFunctionDefinition","src":"88:117:1"},{"body":{"nodeType":"YulBlock","src":"300:28:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"317:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"320:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"310:6:1"},"nodeType":"YulFunctionCall","src":"310:12:1"},"nodeType":"YulExpressionStatement","src":"310:12:1"}]},"name":"revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db","nodeType":"YulFunctionDefinition","src":"211:117:1"},{"body":{"nodeType":"YulBlock","src":"423:28:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"440:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"443:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"433:6:1"},"nodeType":"YulFunctionCall","src":"433:12:1"},"nodeType":"YulExpressionStatement","src":"433:12:1"}]},"name":"revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d","nodeType":"YulFunctionDefinition","src":"334:117:1"},{"body":{"nodeType":"YulBlock","src":"505:54:1","statements":[{"nodeType":"YulAssignment","src":"515:38:1","value":{"arguments":[{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"533:5:1"},{"kind":"number","nodeType":"YulLiteral","src":"540:2:1","type":"","value":"31"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"529:3:1"},"nodeType":"YulFunctionCall","src":"529:14:1"},{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"549:2:1","type":"","value":"31"}],"functionName":{"name":"not","nodeType":"YulIdentifier","src":"545:3:1"},"nodeType":"YulFunctionCall","src":"545:7:1"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"525:3:1"},"nodeType":"YulFunctionCall","src":"525:28:1"},"variableNames":[{"name":"result","nodeType":"YulIdentifier","src":"515:6:1"}]}]},"name":"round_up_to_mul_of_32","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"488:5:1","type":""}],"returnVariables":[{"name":"result","nodeType":"YulTypedName","src":"498:6:1","type":""}],"src":"457:102:1"},{"body":{"nodeType":"YulBlock","src":"593:152:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"610:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"613:77:1","type":"","value":"35408467139433450592217433187231851964531694900788300625387963629091585785856"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"603:6:1"},"nodeType":"YulFunctionCall","src":"603:88:1"},"nodeType":"YulExpressionStatement","src":"603:88:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"707:1:1","type":"","value":"4"},{"kind":"number","nodeType":"YulLiteral","src":"710:4:1","type":"","value":"0x41"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"700:6:1"},"nodeType":"YulFunctionCall","src":"700:15:1"},"nodeType":"YulExpressionStatement","src":"700:15:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"731:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"734:4:1","type":"","value":"0x24"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"724:6:1"},"nodeType":"YulFunctionCall","src":"724:15:1"},"nodeType":"YulExpressionStatement","src":"724:15:1"}]},"name":"panic_error_0x41","nodeType":"YulFunctionDefinition","src":"565:180:1"},{"body":{"nodeType":"YulBlock","src":"794:238:1","statements":[{"nodeType":"YulVariableDeclaration","src":"804:58:1","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"826:6:1"},{"arguments":[{"name":"size","nodeType":"YulIdentifier","src":"856:4:1"}],"functionName":{"name":"round_up_to_mul_of_32","nodeType":"YulIdentifier","src":"834:21:1"},"nodeType":"YulFunctionCall","src":"834:27:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"822:3:1"},"nodeType":"YulFunctionCall","src":"822:40:1"},"variables":[{"name":"newFreePtr","nodeType":"YulTypedName","src":"808:10:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"973:22:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"975:16:1"},"nodeType":"YulFunctionCall","src":"975:18:1"},"nodeType":"YulExpressionStatement","src":"975:18:1"}]},"condition":{"arguments":[{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"916:10:1"},{"kind":"number","nodeType":"YulLiteral","src":"928:18:1","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"913:2:1"},"nodeType":"YulFunctionCall","src":"913:34:1"},{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"952:10:1"},{"name":"memPtr","nodeType":"YulIdentifier","src":"964:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"949:2:1"},"nodeType":"YulFunctionCall","src":"949:22:1"}],"functionName":{"name":"or","nodeType":"YulIdentifier","src":"910:2:1"},"nodeType":"YulFunctionCall","src":"910:62:1"},"nodeType":"YulIf","src":"907:88:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1011:2:1","type":"","value":"64"},{"name":"newFreePtr","nodeType":"YulIdentifier","src":"1015:10:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1004:6:1"},"nodeType":"YulFunctionCall","src":"1004:22:1"},"nodeType":"YulExpressionStatement","src":"1004:22:1"}]},"name":"finalize_allocation","nodeType":"YulFunctionDefinition","parameters":[{"name":"memPtr","nodeType":"YulTypedName","src":"780:6:1","type":""},{"name":"size","nodeType":"YulTypedName","src":"788:4:1","type":""}],"src":"751:281:1"},{"body":{"nodeType":"YulBlock","src":"1079:88:1","statements":[{"nodeType":"YulAssignment","src":"1089:30:1","value":{"arguments":[],"functionName":{"name":"allocate_unbounded","nodeType":"YulIdentifier","src":"1099:18:1"},"nodeType":"YulFunctionCall","src":"1099:20:1"},"variableNames":[{"name":"memPtr","nodeType":"YulIdentifier","src":"1089:6:1"}]},{"expression":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"1148:6:1"},{"name":"size","nodeType":"YulIdentifier","src":"1156:4:1"}],"functionName":{"name":"finalize_allocation","nodeType":"YulIdentifier","src":"1128:19:1"},"nodeType":"YulFunctionCall","src":"1128:33:1"},"nodeType":"YulExpressionStatement","src":"1128:33:1"}]},"name":"allocate_memory","nodeType":"YulFunctionDefinition","parameters":[{"name":"size","nodeType":"YulTypedName","src":"1063:4:1","type":""}],"returnVariables":[{"name":"memPtr","nodeType":"YulTypedName","src":"1072:6:1","type":""}],"src":"1038:129:1"},{"body":{"nodeType":"YulBlock","src":"1255:229:1","statements":[{"body":{"nodeType":"YulBlock","src":"1360:22:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"1362:16:1"},"nodeType":"YulFunctionCall","src":"1362:18:1"},"nodeType":"YulExpressionStatement","src":"1362:18:1"}]},"condition":{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"1332:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"1340:18:1","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"1329:2:1"},"nodeType":"YulFunctionCall","src":"1329:30:1"},"nodeType":"YulIf","src":"1326:56:1"},{"nodeType":"YulAssignment","src":"1392:25:1","value":{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"1404:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"1412:4:1","type":"","value":"0x20"}],"functionName":{"name":"mul","nodeType":"YulIdentifier","src":"1400:3:1"},"nodeType":"YulFunctionCall","src":"1400:17:1"},"variableNames":[{"name":"size","nodeType":"YulIdentifier","src":"1392:4:1"}]},{"nodeType":"YulAssignment","src":"1454:23:1","value":{"arguments":[{"name":"size","nodeType":"YulIdentifier","src":"1466:4:1"},{"kind":"number","nodeType":"YulLiteral","src":"1472:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1462:3:1"},"nodeType":"YulFunctionCall","src":"1462:15:1"},"variableNames":[{"name":"size","nodeType":"YulIdentifier","src":"1454:4:1"}]}]},"name":"array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"length","nodeType":"YulTypedName","src":"1239:6:1","type":""}],"returnVariables":[{"name":"size","nodeType":"YulTypedName","src":"1250:4:1","type":""}],"src":"1173:311:1"},{"body":{"nodeType":"YulBlock","src":"1579:28:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1596:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1599:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"1589:6:1"},"nodeType":"YulFunctionCall","src":"1589:12:1"},"nodeType":"YulExpressionStatement","src":"1589:12:1"}]},"name":"revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef","nodeType":"YulFunctionDefinition","src":"1490:117:1"},{"body":{"nodeType":"YulBlock","src":"1658:32:1","statements":[{"nodeType":"YulAssignment","src":"1668:16:1","value":{"name":"value","nodeType":"YulIdentifier","src":"1679:5:1"},"variableNames":[{"name":"cleaned","nodeType":"YulIdentifier","src":"1668:7:1"}]}]},"name":"cleanup_t_uint256","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"1640:5:1","type":""}],"returnVariables":[{"name":"cleaned","nodeType":"YulTypedName","src":"1650:7:1","type":""}],"src":"1613:77:1"},{"body":{"nodeType":"YulBlock","src":"1739:79:1","statements":[{"body":{"nodeType":"YulBlock","src":"1796:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1805:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1808:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"1798:6:1"},"nodeType":"YulFunctionCall","src":"1798:12:1"},"nodeType":"YulExpressionStatement","src":"1798:12:1"}]},"condition":{"arguments":[{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"1762:5:1"},{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"1787:5:1"}],"functionName":{"name":"cleanup_t_uint256","nodeType":"YulIdentifier","src":"1769:17:1"},"nodeType":"YulFunctionCall","src":"1769:24:1"}],"functionName":{"name":"eq","nodeType":"YulIdentifier","src":"1759:2:1"},"nodeType":"YulFunctionCall","src":"1759:35:1"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"1752:6:1"},"nodeType":"YulFunctionCall","src":"1752:43:1"},"nodeType":"YulIf","src":"1749:63:1"}]},"name":"validator_revert_t_uint256","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"1732:5:1","type":""}],"src":"1696:122:1"},{"body":{"nodeType":"YulBlock","src":"1876:87:1","statements":[{"nodeType":"YulAssignment","src":"1886:29:1","value":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"1908:6:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"1895:12:1"},"nodeType":"YulFunctionCall","src":"1895:20:1"},"variableNames":[{"name":"value","nodeType":"YulIdentifier","src":"1886:5:1"}]},{"expression":{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"1951:5:1"}],"functionName":{"name":"validator_revert_t_uint256","nodeType":"YulIdentifier","src":"1924:26:1"},"nodeType":"YulFunctionCall","src":"1924:33:1"},"nodeType":"YulExpressionStatement","src":"1924:33:1"}]},"name":"abi_decode_t_uint256","nodeType":"YulFunctionDefinition","parameters":[{"name":"offset","nodeType":"YulTypedName","src":"1854:6:1","type":""},{"name":"end","nodeType":"YulTypedName","src":"1862:3:1","type":""}],"returnVariables":[{"name":"value","nodeType":"YulTypedName","src":"1870:5:1","type":""}],"src":"1824:139:1"},{"body":{"nodeType":"YulBlock","src":"2088:620:1","statements":[{"nodeType":"YulAssignment","src":"2098:90:1","value":{"arguments":[{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"2180:6:1"}],"functionName":{"name":"array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulIdentifier","src":"2123:56:1"},"nodeType":"YulFunctionCall","src":"2123:64:1"}],"functionName":{"name":"allocate_memory","nodeType":"YulIdentifier","src":"2107:15:1"},"nodeType":"YulFunctionCall","src":"2107:81:1"},"variableNames":[{"name":"array","nodeType":"YulIdentifier","src":"2098:5:1"}]},{"nodeType":"YulVariableDeclaration","src":"2197:16:1","value":{"name":"array","nodeType":"YulIdentifier","src":"2208:5:1"},"variables":[{"name":"dst","nodeType":"YulTypedName","src":"2201:3:1","type":""}]},{"expression":{"arguments":[{"name":"array","nodeType":"YulIdentifier","src":"2230:5:1"},{"name":"length","nodeType":"YulIdentifier","src":"2237:6:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2223:6:1"},"nodeType":"YulFunctionCall","src":"2223:21:1"},"nodeType":"YulExpressionStatement","src":"2223:21:1"},{"nodeType":"YulAssignment","src":"2253:23:1","value":{"arguments":[{"name":"array","nodeType":"YulIdentifier","src":"2264:5:1"},{"kind":"number","nodeType":"YulLiteral","src":"2271:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2260:3:1"},"nodeType":"YulFunctionCall","src":"2260:16:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"2253:3:1"}]},{"nodeType":"YulVariableDeclaration","src":"2286:17:1","value":{"name":"offset","nodeType":"YulIdentifier","src":"2297:6:1"},"variables":[{"name":"src","nodeType":"YulTypedName","src":"2290:3:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"2352:103:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef","nodeType":"YulIdentifier","src":"2366:77:1"},"nodeType":"YulFunctionCall","src":"2366:79:1"},"nodeType":"YulExpressionStatement","src":"2366:79:1"}]},"condition":{"arguments":[{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"2322:3:1"},{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"2331:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"2339:4:1","type":"","value":"0x20"}],"functionName":{"name":"mul","nodeType":"YulIdentifier","src":"2327:3:1"},"nodeType":"YulFunctionCall","src":"2327:17:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2318:3:1"},"nodeType":"YulFunctionCall","src":"2318:27:1"},{"name":"end","nodeType":"YulIdentifier","src":"2347:3:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"2315:2:1"},"nodeType":"YulFunctionCall","src":"2315:36:1"},"nodeType":"YulIf","src":"2312:143:1"},{"body":{"nodeType":"YulBlock","src":"2524:178:1","statements":[{"nodeType":"YulVariableDeclaration","src":"2539:21:1","value":{"name":"src","nodeType":"YulIdentifier","src":"2557:3:1"},"variables":[{"name":"elementPos","nodeType":"YulTypedName","src":"2543:10:1","type":""}]},{"expression":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"2581:3:1"},{"arguments":[{"name":"elementPos","nodeType":"YulIdentifier","src":"2607:10:1"},{"name":"end","nodeType":"YulIdentifier","src":"2619:3:1"}],"functionName":{"name":"abi_decode_t_uint256","nodeType":"YulIdentifier","src":"2586:20:1"},"nodeType":"YulFunctionCall","src":"2586:37:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2574:6:1"},"nodeType":"YulFunctionCall","src":"2574:50:1"},"nodeType":"YulExpressionStatement","src":"2574:50:1"},{"nodeType":"YulAssignment","src":"2637:21:1","value":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"2648:3:1"},{"kind":"number","nodeType":"YulLiteral","src":"2653:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2644:3:1"},"nodeType":"YulFunctionCall","src":"2644:14:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"2637:3:1"}]},{"nodeType":"YulAssignment","src":"2671:21:1","value":{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"2682:3:1"},{"kind":"number","nodeType":"YulLiteral","src":"2687:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2678:3:1"},"nodeType":"YulFunctionCall","src":"2678:14:1"},"variableNames":[{"name":"src","nodeType":"YulIdentifier","src":"2671:3:1"}]}]},"condition":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"2486:1:1"},{"name":"length","nodeType":"YulIdentifier","src":"2489:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"2483:2:1"},"nodeType":"YulFunctionCall","src":"2483:13:1"},"nodeType":"YulForLoop","post":{"nodeType":"YulBlock","src":"2497:18:1","statements":[{"nodeType":"YulAssignment","src":"2499:14:1","value":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"2508:1:1"},{"kind":"number","nodeType":"YulLiteral","src":"2511:1:1","type":"","value":"1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2504:3:1"},"nodeType":"YulFunctionCall","src":"2504:9:1"},"variableNames":[{"name":"i","nodeType":"YulIdentifier","src":"2499:1:1"}]}]},"pre":{"nodeType":"YulBlock","src":"2468:14:1","statements":[{"nodeType":"YulVariableDeclaration","src":"2470:10:1","value":{"kind":"number","nodeType":"YulLiteral","src":"2479:1:1","type":"","value":"0"},"variables":[{"name":"i","nodeType":"YulTypedName","src":"2474:1:1","type":""}]}]},"src":"2464:238:1"}]},"name":"abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"offset","nodeType":"YulTypedName","src":"2058:6:1","type":""},{"name":"length","nodeType":"YulTypedName","src":"2066:6:1","type":""},{"name":"end","nodeType":"YulTypedName","src":"2074:3:1","type":""}],"returnVariables":[{"name":"array","nodeType":"YulTypedName","src":"2082:5:1","type":""}],"src":"1986:722:1"},{"body":{"nodeType":"YulBlock","src":"2808:293:1","statements":[{"body":{"nodeType":"YulBlock","src":"2857:83:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d","nodeType":"YulIdentifier","src":"2859:77:1"},"nodeType":"YulFunctionCall","src":"2859:79:1"},"nodeType":"YulExpressionStatement","src":"2859:79:1"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"2836:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"2844:4:1","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2832:3:1"},"nodeType":"YulFunctionCall","src":"2832:17:1"},{"name":"end","nodeType":"YulIdentifier","src":"2851:3:1"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"2828:3:1"},"nodeType":"YulFunctionCall","src":"2828:27:1"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"2821:6:1"},"nodeType":"YulFunctionCall","src":"2821:35:1"},"nodeType":"YulIf","src":"2818:122:1"},{"nodeType":"YulVariableDeclaration","src":"2949:34:1","value":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"2976:6:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"2963:12:1"},"nodeType":"YulFunctionCall","src":"2963:20:1"},"variables":[{"name":"length","nodeType":"YulTypedName","src":"2953:6:1","type":""}]},{"nodeType":"YulAssignment","src":"2992:103:1","value":{"arguments":[{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"3068:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"3076:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3064:3:1"},"nodeType":"YulFunctionCall","src":"3064:17:1"},{"name":"length","nodeType":"YulIdentifier","src":"3083:6:1"},{"name":"end","nodeType":"YulIdentifier","src":"3091:3:1"}],"functionName":{"name":"abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulIdentifier","src":"3001:62:1"},"nodeType":"YulFunctionCall","src":"3001:94:1"},"variableNames":[{"name":"array","nodeType":"YulIdentifier","src":"2992:5:1"}]}]},"name":"abi_decode_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"offset","nodeType":"YulTypedName","src":"2786:6:1","type":""},{"name":"end","nodeType":"YulTypedName","src":"2794:3:1","type":""}],"returnVariables":[{"name":"array","nodeType":"YulTypedName","src":"2802:5:1","type":""}],"src":"2731:370:1"},{"body":{"nodeType":"YulBlock","src":"3198:448:1","statements":[{"body":{"nodeType":"YulBlock","src":"3244:83:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b","nodeType":"YulIdentifier","src":"3246:77:1"},"nodeType":"YulFunctionCall","src":"3246:79:1"},"nodeType":"YulExpressionStatement","src":"3246:79:1"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"3219:7:1"},{"name":"headStart","nodeType":"YulIdentifier","src":"3228:9:1"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"3215:3:1"},"nodeType":"YulFunctionCall","src":"3215:23:1"},{"kind":"number","nodeType":"YulLiteral","src":"3240:2:1","type":"","value":"32"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"3211:3:1"},"nodeType":"YulFunctionCall","src":"3211:32:1"},"nodeType":"YulIf","src":"3208:119:1"},{"nodeType":"YulBlock","src":"3337:302:1","statements":[{"nodeType":"YulVariableDeclaration","src":"3352:45:1","value":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3383:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"3394:1:1","type":"","value":"0"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3379:3:1"},"nodeType":"YulFunctionCall","src":"3379:17:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"3366:12:1"},"nodeType":"YulFunctionCall","src":"3366:31:1"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"3356:6:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"3444:83:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db","nodeType":"YulIdentifier","src":"3446:77:1"},"nodeType":"YulFunctionCall","src":"3446:79:1"},"nodeType":"YulExpressionStatement","src":"3446:79:1"}]},"condition":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"3416:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"3424:18:1","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"3413:2:1"},"nodeType":"YulFunctionCall","src":"3413:30:1"},"nodeType":"YulIf","src":"3410:117:1"},{"nodeType":"YulAssignment","src":"3541:88:1","value":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3601:9:1"},{"name":"offset","nodeType":"YulIdentifier","src":"3612:6:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3597:3:1"},"nodeType":"YulFunctionCall","src":"3597:22:1"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"3621:7:1"}],"functionName":{"name":"abi_decode_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulIdentifier","src":"3551:45:1"},"nodeType":"YulFunctionCall","src":"3551:78:1"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"3541:6:1"}]}]}]},"name":"abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"3168:9:1","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"3179:7:1","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"3191:6:1","type":""}],"src":"3107:539:1"},{"body":{"nodeType":"YulBlock","src":"3717:53:1","statements":[{"expression":{"arguments":[{"name":"pos","nodeType":"YulIdentifier","src":"3734:3:1"},{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"3757:5:1"}],"functionName":{"name":"cleanup_t_uint256","nodeType":"YulIdentifier","src":"3739:17:1"},"nodeType":"YulFunctionCall","src":"3739:24:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3727:6:1"},"nodeType":"YulFunctionCall","src":"3727:37:1"},"nodeType":"YulExpressionStatement","src":"3727:37:1"}]},"name":"abi_encode_t_uint256_to_t_uint256_fromStack","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"3705:5:1","type":""},{"name":"pos","nodeType":"YulTypedName","src":"3712:3:1","type":""}],"src":"3652:118:1"},{"body":{"nodeType":"YulBlock","src":"3874:124:1","statements":[{"nodeType":"YulAssignment","src":"3884:26:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3896:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"3907:2:1","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3892:3:1"},"nodeType":"YulFunctionCall","src":"3892:18:1"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"3884:4:1"}]},{"expression":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"3964:6:1"},{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3977:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"3988:1:1","type":"","value":"0"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3973:3:1"},"nodeType":"YulFunctionCall","src":"3973:17:1"}],"functionName":{"name":"abi_encode_t_uint256_to_t_uint256_fromStack","nodeType":"YulIdentifier","src":"3920:43:1"},"nodeType":"YulFunctionCall","src":"3920:71:1"},"nodeType":"YulExpressionStatement","src":"3920:71:1"}]},"name":"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"3846:9:1","type":""},{"name":"value0","nodeType":"YulTypedName","src":"3858:6:1","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"3869:4:1","type":""}],"src":"3776:222:1"}]},"contents":"{ + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d() { + revert(0, 0) + } + + function round_up_to_mul_of_32(value) -> result { + result := and(add(value, 31), not(31)) + } + + function panic_error_0x41() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x41) + revert(0, 0x24) + } + + function finalize_allocation(memPtr, size) { + let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) + // protect against overflow + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } + mstore(64, newFreePtr) + } + + function allocate_memory(size) -> memPtr { + memPtr := allocate_unbounded() + finalize_allocation(memPtr, size) + } + + function array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr(length) -> size { + // Make sure we can allocate memory without overflow + if gt(length, 0xffffffffffffffff) { panic_error_0x41() } + + size := mul(length, 0x20) + + // add length slot + size := add(size, 0x20) + + } + + function revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef() { + revert(0, 0) + } + + function cleanup_t_uint256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_uint256(value) { + if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } + } + + function abi_decode_t_uint256(offset, end) -> value { + value := calldataload(offset) + validator_revert_t_uint256(value) + } // uint256[] function abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr(offset, length, end) -> array { @@ -30,11 +96,6 @@ array := abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr(add(offset, 0x20), length, end) } - function abi_decode_t_uint256(offset, end) -> value { - value := calldataload(offset) - validator_revert_t_uint256(value) - } - function abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr(headStart, dataEnd) -> value0 { if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } @@ -59,67 +120,6 @@ } - function allocate_memory(size) -> memPtr { - memPtr := allocate_unbounded() - finalize_allocation(memPtr, size) - } - - function allocate_unbounded() -> memPtr { - memPtr := mload(64) - } - - function array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr(length) -> size { - // Make sure we can allocate memory without overflow - if gt(length, 0xffffffffffffffff) { panic_error_0x41() } - - size := mul(length, 0x20) - - // add length slot - size := add(size, 0x20) - - } - - function cleanup_t_uint256(value) -> cleaned { - cleaned := value - } - - function finalize_allocation(memPtr, size) { - let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) - // protect against overflow - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } - mstore(64, newFreePtr) - } - - function panic_error_0x41() { - mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) - mstore(4, 0x41) - revert(0, 0x24) - } - - function revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d() { - revert(0, 0) - } - - function revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef() { - revert(0, 0) - } - - function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { - revert(0, 0) - } - - function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { - revert(0, 0) - } - - function round_up_to_mul_of_32(value) -> result { - result := and(add(value, 31), not(31)) - } - - function validator_revert_t_uint256(value) { - if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) } - } - } ","id":1,"language":"Yul","name":"#utility.yul"}]}}}}},"errors":[{"component":"general","errorCode":"3420","formattedMessage":"Warning: Source file does not specify required compiler version! --> a.sol diff --git a/test/cmdlineTests/standard_irOptimized_requested/output.json b/test/cmdlineTests/standard_irOptimized_requested/output.json index e94582898..2651856c0 100644 --- a/test/cmdlineTests/standard_irOptimized_requested/output.json +++ b/test/cmdlineTests/standard_irOptimized_requested/output.json @@ -20,10 +20,10 @@ object \"C_7\" { return(_1, datasize(\"C_7_deployed\")) function allocate_unbounded() -> memPtr { memPtr := mload(64) } - function constructor_C_7() - { } function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { revert(0, 0) } + function constructor_C_7() + { } } /// @use-src 0:\"A\" object \"C_7_deployed\" { @@ -49,6 +49,14 @@ object \"C_7\" { } if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + function shift_right_224_unsigned(value) -> newValue + { newValue := shr(224, value) } + function allocate_unbounded() -> memPtr + { memPtr := mload(64) } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() + { revert(0, 0) } + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() + { revert(0, 0) } function abi_decode_tuple_(headStart, dataEnd) { if slt(sub(dataEnd, headStart), 0) @@ -58,20 +66,11 @@ object \"C_7\" { } function abi_encode_tuple__to__fromStack(headStart) -> tail { tail := add(headStart, 0) } - function allocate_unbounded() -> memPtr - { memPtr := mload(64) } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + { revert(0, 0) } /// @src 0:92:119 function fun_f_6() { } - /// @src 0:79:121 - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() - { revert(0, 0) } - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() - { revert(0, 0) } - function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() - { revert(0, 0) } - function shift_right_224_unsigned(value) -> newValue - { newValue := shr(224, value) } } data \".metadata\" hex\"\" } diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index 3cc5c0808..bc61d38bd 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -24,6 +24,10 @@ object \"C_7\" { memPtr := mload(64) } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + /// @src 0:79:121 function constructor_C_7() { @@ -32,10 +36,6 @@ object \"C_7\" { } /// @src 0:79:121 - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - } /// @use-src 0:\"A\" object \"C_7_deployed\" { @@ -65,13 +65,10 @@ object \"C_7\" { if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() - function abi_decode_tuple_(headStart, dataEnd) { - if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + function shift_right_224_unsigned(value) -> newValue { + newValue := - } - - function abi_encode_tuple__to__fromStack(headStart ) -> tail { - tail := add(headStart, 0) + shr(224, value) } @@ -79,16 +76,6 @@ object \"C_7\" { memPtr := mload(64) } - /// @src 0:92:119 - function fun_f_6() { - - } - /// @src 0:79:121 - - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { - revert(0, 0) - } - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { revert(0, 0) } @@ -97,13 +84,26 @@ object \"C_7\" { revert(0, 0) } - function shift_right_224_unsigned(value) -> newValue { - newValue := - - shr(224, value) + function abi_decode_tuple_(headStart, dataEnd) { + if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } } + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + /// @src 0:92:119 + function fun_f_6() { + + } + /// @src 0:79:121 + } data \".metadata\" hex\"\" diff --git a/test/cmdlineTests/standard_optimizer_generatedSources/output.json b/test/cmdlineTests/standard_optimizer_generatedSources/output.json index 439101cc4..fba776458 100644 --- a/test/cmdlineTests/standard_optimizer_generatedSources/output.json +++ b/test/cmdlineTests/standard_optimizer_generatedSources/output.json @@ -1,5 +1,11 @@ -{"contracts":{"a.sol":{"A":{"evm":{"bytecode":{"generatedSources":[],"object":""},"deployedBytecode":{"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:1456:1","statements":[{"nodeType":"YulBlock","src":"6:3:1","statements":[]},{"body":{"nodeType":"YulBlock","src":"109:1031:1","statements":[{"nodeType":"YulVariableDeclaration","src":"119:12:1","value":{"kind":"number","nodeType":"YulLiteral","src":"129:2:1","type":"","value":"32"},"variables":[{"name":"_1","nodeType":"YulTypedName","src":"123:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"176:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"185:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"188:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"178:6:1"},"nodeType":"YulFunctionCall","src":"178:12:1"},"nodeType":"YulExpressionStatement","src":"178:12:1"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"151:7:1"},{"name":"headStart","nodeType":"YulIdentifier","src":"160:9:1"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"147:3:1"},"nodeType":"YulFunctionCall","src":"147:23:1"},{"name":"_1","nodeType":"YulIdentifier","src":"172:2:1"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"143:3:1"},"nodeType":"YulFunctionCall","src":"143:32:1"},"nodeType":"YulIf","src":"140:52:1"},{"nodeType":"YulVariableDeclaration","src":"201:37:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"228:9:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"215:12:1"},"nodeType":"YulFunctionCall","src":"215:23:1"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"205:6:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"247:28:1","value":{"kind":"number","nodeType":"YulLiteral","src":"257:18:1","type":"","value":"0xffffffffffffffff"},"variables":[{"name":"_2","nodeType":"YulTypedName","src":"251:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"302:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"311:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"314:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"304:6:1"},"nodeType":"YulFunctionCall","src":"304:12:1"},"nodeType":"YulExpressionStatement","src":"304:12:1"}]},"condition":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"290:6:1"},{"name":"_2","nodeType":"YulIdentifier","src":"298:2:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"287:2:1"},"nodeType":"YulFunctionCall","src":"287:14:1"},"nodeType":"YulIf","src":"284:34:1"},{"nodeType":"YulVariableDeclaration","src":"327:32:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"341:9:1"},{"name":"offset","nodeType":"YulIdentifier","src":"352:6:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"337:3:1"},"nodeType":"YulFunctionCall","src":"337:22:1"},"variables":[{"name":"_3","nodeType":"YulTypedName","src":"331:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"407:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"416:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"419:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"409:6:1"},"nodeType":"YulFunctionCall","src":"409:12:1"},"nodeType":"YulExpressionStatement","src":"409:12:1"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"386:2:1"},{"kind":"number","nodeType":"YulLiteral","src":"390:4:1","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"382:3:1"},"nodeType":"YulFunctionCall","src":"382:13:1"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"397:7:1"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"378:3:1"},"nodeType":"YulFunctionCall","src":"378:27:1"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"371:6:1"},"nodeType":"YulFunctionCall","src":"371:35:1"},"nodeType":"YulIf","src":"368:55:1"},{"nodeType":"YulVariableDeclaration","src":"432:26:1","value":{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"455:2:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"442:12:1"},"nodeType":"YulFunctionCall","src":"442:16:1"},"variables":[{"name":"_4","nodeType":"YulTypedName","src":"436:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"481:22:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"483:16:1"},"nodeType":"YulFunctionCall","src":"483:18:1"},"nodeType":"YulExpressionStatement","src":"483:18:1"}]},"condition":{"arguments":[{"name":"_4","nodeType":"YulIdentifier","src":"473:2:1"},{"name":"_2","nodeType":"YulIdentifier","src":"477:2:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"470:2:1"},"nodeType":"YulFunctionCall","src":"470:10:1"},"nodeType":"YulIf","src":"467:36:1"},{"nodeType":"YulVariableDeclaration","src":"512:20:1","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"526:1:1","type":"","value":"5"},{"name":"_4","nodeType":"YulIdentifier","src":"529:2:1"}],"functionName":{"name":"shl","nodeType":"YulIdentifier","src":"522:3:1"},"nodeType":"YulFunctionCall","src":"522:10:1"},"variables":[{"name":"_5","nodeType":"YulTypedName","src":"516:2:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"541:23:1","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"561:2:1","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"555:5:1"},"nodeType":"YulFunctionCall","src":"555:9:1"},"variables":[{"name":"memPtr","nodeType":"YulTypedName","src":"545:6:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"573:56:1","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"595:6:1"},{"arguments":[{"arguments":[{"name":"_5","nodeType":"YulIdentifier","src":"611:2:1"},{"kind":"number","nodeType":"YulLiteral","src":"615:2:1","type":"","value":"63"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"607:3:1"},"nodeType":"YulFunctionCall","src":"607:11:1"},{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"624:2:1","type":"","value":"31"}],"functionName":{"name":"not","nodeType":"YulIdentifier","src":"620:3:1"},"nodeType":"YulFunctionCall","src":"620:7:1"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"603:3:1"},"nodeType":"YulFunctionCall","src":"603:25:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"591:3:1"},"nodeType":"YulFunctionCall","src":"591:38:1"},"variables":[{"name":"newFreePtr","nodeType":"YulTypedName","src":"577:10:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"688:22:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"690:16:1"},"nodeType":"YulFunctionCall","src":"690:18:1"},"nodeType":"YulExpressionStatement","src":"690:18:1"}]},"condition":{"arguments":[{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"647:10:1"},{"name":"_2","nodeType":"YulIdentifier","src":"659:2:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"644:2:1"},"nodeType":"YulFunctionCall","src":"644:18:1"},{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"667:10:1"},{"name":"memPtr","nodeType":"YulIdentifier","src":"679:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"664:2:1"},"nodeType":"YulFunctionCall","src":"664:22:1"}],"functionName":{"name":"or","nodeType":"YulIdentifier","src":"641:2:1"},"nodeType":"YulFunctionCall","src":"641:46:1"},"nodeType":"YulIf","src":"638:72:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"726:2:1","type":"","value":"64"},{"name":"newFreePtr","nodeType":"YulIdentifier","src":"730:10:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"719:6:1"},"nodeType":"YulFunctionCall","src":"719:22:1"},"nodeType":"YulExpressionStatement","src":"719:22:1"},{"nodeType":"YulVariableDeclaration","src":"750:17:1","value":{"name":"memPtr","nodeType":"YulIdentifier","src":"761:6:1"},"variables":[{"name":"dst","nodeType":"YulTypedName","src":"754:3:1","type":""}]},{"expression":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"783:6:1"},{"name":"_4","nodeType":"YulIdentifier","src":"791:2:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"776:6:1"},"nodeType":"YulFunctionCall","src":"776:18:1"},"nodeType":"YulExpressionStatement","src":"776:18:1"},{"nodeType":"YulAssignment","src":"803:22:1","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"814:6:1"},{"name":"_1","nodeType":"YulIdentifier","src":"822:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"810:3:1"},"nodeType":"YulFunctionCall","src":"810:15:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"803:3:1"}]},{"nodeType":"YulVariableDeclaration","src":"834:22:1","value":{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"849:2:1"},{"name":"_1","nodeType":"YulIdentifier","src":"853:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"845:3:1"},"nodeType":"YulFunctionCall","src":"845:11:1"},"variables":[{"name":"src","nodeType":"YulTypedName","src":"838:3:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"902:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"911:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"914:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"904:6:1"},"nodeType":"YulFunctionCall","src":"904:12:1"},"nodeType":"YulExpressionStatement","src":"904:12:1"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"879:2:1"},{"name":"_5","nodeType":"YulIdentifier","src":"883:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"875:3:1"},"nodeType":"YulFunctionCall","src":"875:11:1"},{"name":"_1","nodeType":"YulIdentifier","src":"888:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"871:3:1"},"nodeType":"YulFunctionCall","src":"871:20:1"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"893:7:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"868:2:1"},"nodeType":"YulFunctionCall","src":"868:33:1"},"nodeType":"YulIf","src":"865:53:1"},{"nodeType":"YulVariableDeclaration","src":"927:10:1","value":{"kind":"number","nodeType":"YulLiteral","src":"936:1:1","type":"","value":"0"},"variables":[{"name":"i","nodeType":"YulTypedName","src":"931:1:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"991:118:1","statements":[{"expression":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"1012:3:1"},{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"1030:3:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"1017:12:1"},"nodeType":"YulFunctionCall","src":"1017:17:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1005:6:1"},"nodeType":"YulFunctionCall","src":"1005:30:1"},"nodeType":"YulExpressionStatement","src":"1005:30:1"},{"nodeType":"YulAssignment","src":"1048:19:1","value":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"1059:3:1"},{"name":"_1","nodeType":"YulIdentifier","src":"1064:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1055:3:1"},"nodeType":"YulFunctionCall","src":"1055:12:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"1048:3:1"}]},{"nodeType":"YulAssignment","src":"1080:19:1","value":{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"1091:3:1"},{"name":"_1","nodeType":"YulIdentifier","src":"1096:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1087:3:1"},"nodeType":"YulFunctionCall","src":"1087:12:1"},"variableNames":[{"name":"src","nodeType":"YulIdentifier","src":"1080:3:1"}]}]},"condition":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"957:1:1"},{"name":"_4","nodeType":"YulIdentifier","src":"960:2:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"954:2:1"},"nodeType":"YulFunctionCall","src":"954:9:1"},"nodeType":"YulForLoop","post":{"nodeType":"YulBlock","src":"964:18:1","statements":[{"nodeType":"YulAssignment","src":"966:14:1","value":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"975:1:1"},{"kind":"number","nodeType":"YulLiteral","src":"978:1:1","type":"","value":"1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"971:3:1"},"nodeType":"YulFunctionCall","src":"971:9:1"},"variableNames":[{"name":"i","nodeType":"YulIdentifier","src":"966:1:1"}]}]},"pre":{"nodeType":"YulBlock","src":"950:3:1","statements":[]},"src":"946:163:1"},{"nodeType":"YulAssignment","src":"1118:16:1","value":{"name":"memPtr","nodeType":"YulIdentifier","src":"1128:6:1"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"1118:6:1"}]}]},"name":"abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"75:9:1","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"86:7:1","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"98:6:1","type":""}],"src":"14:1126:1"},{"body":{"nodeType":"YulBlock","src":"1246:76:1","statements":[{"nodeType":"YulAssignment","src":"1256:26:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1268:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"1279:2:1","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1264:3:1"},"nodeType":"YulFunctionCall","src":"1264:18:1"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"1256:4:1"}]},{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1298:9:1"},{"name":"value0","nodeType":"YulIdentifier","src":"1309:6:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1291:6:1"},"nodeType":"YulFunctionCall","src":"1291:25:1"},"nodeType":"YulExpressionStatement","src":"1291:25:1"}]},"name":"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"1215:9:1","type":""},{"name":"value0","nodeType":"YulTypedName","src":"1226:6:1","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"1237:4:1","type":""}],"src":"1145:177:1"},{"body":{"nodeType":"YulBlock","src":"1359:95:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1376:1:1","type":"","value":"0"},{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1383:3:1","type":"","value":"224"},{"kind":"number","nodeType":"YulLiteral","src":"1388:10:1","type":"","value":"0x4e487b71"}],"functionName":{"name":"shl","nodeType":"YulIdentifier","src":"1379:3:1"},"nodeType":"YulFunctionCall","src":"1379:20:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1369:6:1"},"nodeType":"YulFunctionCall","src":"1369:31:1"},"nodeType":"YulExpressionStatement","src":"1369:31:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1416:1:1","type":"","value":"4"},{"kind":"number","nodeType":"YulLiteral","src":"1419:4:1","type":"","value":"0x41"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1409:6:1"},"nodeType":"YulFunctionCall","src":"1409:15:1"},"nodeType":"YulExpressionStatement","src":"1409:15:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1440:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1443:4:1","type":"","value":"0x24"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"1433:6:1"},"nodeType":"YulFunctionCall","src":"1433:15:1"},"nodeType":"YulExpressionStatement","src":"1433:15:1"}]},"name":"panic_error_0x41","nodeType":"YulFunctionDefinition","src":"1327:127:1"}]},"contents":"{ +{"contracts":{"a.sol":{"A":{"evm":{"bytecode":{"generatedSources":[],"object":""},"deployedBytecode":{"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:1456:1","statements":[{"nodeType":"YulBlock","src":"6:3:1","statements":[]},{"body":{"nodeType":"YulBlock","src":"46:95:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"63:1:1","type":"","value":"0"},{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"70:3:1","type":"","value":"224"},{"kind":"number","nodeType":"YulLiteral","src":"75:10:1","type":"","value":"0x4e487b71"}],"functionName":{"name":"shl","nodeType":"YulIdentifier","src":"66:3:1"},"nodeType":"YulFunctionCall","src":"66:20:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"56:6:1"},"nodeType":"YulFunctionCall","src":"56:31:1"},"nodeType":"YulExpressionStatement","src":"56:31:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"103:1:1","type":"","value":"4"},{"kind":"number","nodeType":"YulLiteral","src":"106:4:1","type":"","value":"0x41"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"96:6:1"},"nodeType":"YulFunctionCall","src":"96:15:1"},"nodeType":"YulExpressionStatement","src":"96:15:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"127:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"130:4:1","type":"","value":"0x24"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"120:6:1"},"nodeType":"YulFunctionCall","src":"120:15:1"},"nodeType":"YulExpressionStatement","src":"120:15:1"}]},"name":"panic_error_0x41","nodeType":"YulFunctionDefinition","src":"14:127:1"},{"body":{"nodeType":"YulBlock","src":"241:1031:1","statements":[{"nodeType":"YulVariableDeclaration","src":"251:12:1","value":{"kind":"number","nodeType":"YulLiteral","src":"261:2:1","type":"","value":"32"},"variables":[{"name":"_1","nodeType":"YulTypedName","src":"255:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"308:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"317:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"320:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"310:6:1"},"nodeType":"YulFunctionCall","src":"310:12:1"},"nodeType":"YulExpressionStatement","src":"310:12:1"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"283:7:1"},{"name":"headStart","nodeType":"YulIdentifier","src":"292:9:1"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"279:3:1"},"nodeType":"YulFunctionCall","src":"279:23:1"},{"name":"_1","nodeType":"YulIdentifier","src":"304:2:1"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"275:3:1"},"nodeType":"YulFunctionCall","src":"275:32:1"},"nodeType":"YulIf","src":"272:52:1"},{"nodeType":"YulVariableDeclaration","src":"333:37:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"360:9:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"347:12:1"},"nodeType":"YulFunctionCall","src":"347:23:1"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"337:6:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"379:28:1","value":{"kind":"number","nodeType":"YulLiteral","src":"389:18:1","type":"","value":"0xffffffffffffffff"},"variables":[{"name":"_2","nodeType":"YulTypedName","src":"383:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"434:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"443:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"446:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"436:6:1"},"nodeType":"YulFunctionCall","src":"436:12:1"},"nodeType":"YulExpressionStatement","src":"436:12:1"}]},"condition":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"422:6:1"},{"name":"_2","nodeType":"YulIdentifier","src":"430:2:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"419:2:1"},"nodeType":"YulFunctionCall","src":"419:14:1"},"nodeType":"YulIf","src":"416:34:1"},{"nodeType":"YulVariableDeclaration","src":"459:32:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"473:9:1"},{"name":"offset","nodeType":"YulIdentifier","src":"484:6:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"469:3:1"},"nodeType":"YulFunctionCall","src":"469:22:1"},"variables":[{"name":"_3","nodeType":"YulTypedName","src":"463:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"539:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"548:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"551:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"541:6:1"},"nodeType":"YulFunctionCall","src":"541:12:1"},"nodeType":"YulExpressionStatement","src":"541:12:1"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"518:2:1"},{"kind":"number","nodeType":"YulLiteral","src":"522:4:1","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"514:3:1"},"nodeType":"YulFunctionCall","src":"514:13:1"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"529:7:1"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"510:3:1"},"nodeType":"YulFunctionCall","src":"510:27:1"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"503:6:1"},"nodeType":"YulFunctionCall","src":"503:35:1"},"nodeType":"YulIf","src":"500:55:1"},{"nodeType":"YulVariableDeclaration","src":"564:26:1","value":{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"587:2:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"574:12:1"},"nodeType":"YulFunctionCall","src":"574:16:1"},"variables":[{"name":"_4","nodeType":"YulTypedName","src":"568:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"613:22:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"615:16:1"},"nodeType":"YulFunctionCall","src":"615:18:1"},"nodeType":"YulExpressionStatement","src":"615:18:1"}]},"condition":{"arguments":[{"name":"_4","nodeType":"YulIdentifier","src":"605:2:1"},{"name":"_2","nodeType":"YulIdentifier","src":"609:2:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"602:2:1"},"nodeType":"YulFunctionCall","src":"602:10:1"},"nodeType":"YulIf","src":"599:36:1"},{"nodeType":"YulVariableDeclaration","src":"644:20:1","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"658:1:1","type":"","value":"5"},{"name":"_4","nodeType":"YulIdentifier","src":"661:2:1"}],"functionName":{"name":"shl","nodeType":"YulIdentifier","src":"654:3:1"},"nodeType":"YulFunctionCall","src":"654:10:1"},"variables":[{"name":"_5","nodeType":"YulTypedName","src":"648:2:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"673:23:1","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"693:2:1","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"687:5:1"},"nodeType":"YulFunctionCall","src":"687:9:1"},"variables":[{"name":"memPtr","nodeType":"YulTypedName","src":"677:6:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"705:56:1","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"727:6:1"},{"arguments":[{"arguments":[{"name":"_5","nodeType":"YulIdentifier","src":"743:2:1"},{"kind":"number","nodeType":"YulLiteral","src":"747:2:1","type":"","value":"63"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"739:3:1"},"nodeType":"YulFunctionCall","src":"739:11:1"},{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"756:2:1","type":"","value":"31"}],"functionName":{"name":"not","nodeType":"YulIdentifier","src":"752:3:1"},"nodeType":"YulFunctionCall","src":"752:7:1"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"735:3:1"},"nodeType":"YulFunctionCall","src":"735:25:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"723:3:1"},"nodeType":"YulFunctionCall","src":"723:38:1"},"variables":[{"name":"newFreePtr","nodeType":"YulTypedName","src":"709:10:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"820:22:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"822:16:1"},"nodeType":"YulFunctionCall","src":"822:18:1"},"nodeType":"YulExpressionStatement","src":"822:18:1"}]},"condition":{"arguments":[{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"779:10:1"},{"name":"_2","nodeType":"YulIdentifier","src":"791:2:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"776:2:1"},"nodeType":"YulFunctionCall","src":"776:18:1"},{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"799:10:1"},{"name":"memPtr","nodeType":"YulIdentifier","src":"811:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"796:2:1"},"nodeType":"YulFunctionCall","src":"796:22:1"}],"functionName":{"name":"or","nodeType":"YulIdentifier","src":"773:2:1"},"nodeType":"YulFunctionCall","src":"773:46:1"},"nodeType":"YulIf","src":"770:72:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"858:2:1","type":"","value":"64"},{"name":"newFreePtr","nodeType":"YulIdentifier","src":"862:10:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"851:6:1"},"nodeType":"YulFunctionCall","src":"851:22:1"},"nodeType":"YulExpressionStatement","src":"851:22:1"},{"nodeType":"YulVariableDeclaration","src":"882:17:1","value":{"name":"memPtr","nodeType":"YulIdentifier","src":"893:6:1"},"variables":[{"name":"dst","nodeType":"YulTypedName","src":"886:3:1","type":""}]},{"expression":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"915:6:1"},{"name":"_4","nodeType":"YulIdentifier","src":"923:2:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"908:6:1"},"nodeType":"YulFunctionCall","src":"908:18:1"},"nodeType":"YulExpressionStatement","src":"908:18:1"},{"nodeType":"YulAssignment","src":"935:22:1","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"946:6:1"},{"name":"_1","nodeType":"YulIdentifier","src":"954:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"942:3:1"},"nodeType":"YulFunctionCall","src":"942:15:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"935:3:1"}]},{"nodeType":"YulVariableDeclaration","src":"966:22:1","value":{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"981:2:1"},{"name":"_1","nodeType":"YulIdentifier","src":"985:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"977:3:1"},"nodeType":"YulFunctionCall","src":"977:11:1"},"variables":[{"name":"src","nodeType":"YulTypedName","src":"970:3:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"1034:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1043:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1046:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"1036:6:1"},"nodeType":"YulFunctionCall","src":"1036:12:1"},"nodeType":"YulExpressionStatement","src":"1036:12:1"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"1011:2:1"},{"name":"_5","nodeType":"YulIdentifier","src":"1015:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1007:3:1"},"nodeType":"YulFunctionCall","src":"1007:11:1"},{"name":"_1","nodeType":"YulIdentifier","src":"1020:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1003:3:1"},"nodeType":"YulFunctionCall","src":"1003:20:1"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"1025:7:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"1000:2:1"},"nodeType":"YulFunctionCall","src":"1000:33:1"},"nodeType":"YulIf","src":"997:53:1"},{"nodeType":"YulVariableDeclaration","src":"1059:10:1","value":{"kind":"number","nodeType":"YulLiteral","src":"1068:1:1","type":"","value":"0"},"variables":[{"name":"i","nodeType":"YulTypedName","src":"1063:1:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"1123:118:1","statements":[{"expression":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"1144:3:1"},{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"1162:3:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"1149:12:1"},"nodeType":"YulFunctionCall","src":"1149:17:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1137:6:1"},"nodeType":"YulFunctionCall","src":"1137:30:1"},"nodeType":"YulExpressionStatement","src":"1137:30:1"},{"nodeType":"YulAssignment","src":"1180:19:1","value":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"1191:3:1"},{"name":"_1","nodeType":"YulIdentifier","src":"1196:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1187:3:1"},"nodeType":"YulFunctionCall","src":"1187:12:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"1180:3:1"}]},{"nodeType":"YulAssignment","src":"1212:19:1","value":{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"1223:3:1"},{"name":"_1","nodeType":"YulIdentifier","src":"1228:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1219:3:1"},"nodeType":"YulFunctionCall","src":"1219:12:1"},"variableNames":[{"name":"src","nodeType":"YulIdentifier","src":"1212:3:1"}]}]},"condition":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"1089:1:1"},{"name":"_4","nodeType":"YulIdentifier","src":"1092:2:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"1086:2:1"},"nodeType":"YulFunctionCall","src":"1086:9:1"},"nodeType":"YulForLoop","post":{"nodeType":"YulBlock","src":"1096:18:1","statements":[{"nodeType":"YulAssignment","src":"1098:14:1","value":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"1107:1:1"},{"kind":"number","nodeType":"YulLiteral","src":"1110:1:1","type":"","value":"1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1103:3:1"},"nodeType":"YulFunctionCall","src":"1103:9:1"},"variableNames":[{"name":"i","nodeType":"YulIdentifier","src":"1098:1:1"}]}]},"pre":{"nodeType":"YulBlock","src":"1082:3:1","statements":[]},"src":"1078:163:1"},{"nodeType":"YulAssignment","src":"1250:16:1","value":{"name":"memPtr","nodeType":"YulIdentifier","src":"1260:6:1"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"1250:6:1"}]}]},"name":"abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"207:9:1","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"218:7:1","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"230:6:1","type":""}],"src":"146:1126:1"},{"body":{"nodeType":"YulBlock","src":"1378:76:1","statements":[{"nodeType":"YulAssignment","src":"1388:26:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1400:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"1411:2:1","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1396:3:1"},"nodeType":"YulFunctionCall","src":"1396:18:1"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"1388:4:1"}]},{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1430:9:1"},{"name":"value0","nodeType":"YulIdentifier","src":"1441:6:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1423:6:1"},"nodeType":"YulFunctionCall","src":"1423:25:1"},"nodeType":"YulExpressionStatement","src":"1423:25:1"}]},"name":"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"1347:9:1","type":""},{"name":"value0","nodeType":"YulTypedName","src":"1358:6:1","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"1369:4:1","type":""}],"src":"1277:177:1"}]},"contents":"{ { } + function panic_error_0x41() + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 0x41) + revert(0, 0x24) + } function abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr(headStart, dataEnd) -> value0 { let _1 := 32 @@ -35,10 +41,4 @@ tail := add(headStart, 32) mstore(headStart, value0) } - function panic_error_0x41() - { - mstore(0, shl(224, 0x4e487b71)) - mstore(4, 0x41) - revert(0, 0x24) - } }","id":1,"language":"Yul","name":"#utility.yul"}]}}}}},"sources":{"a.sol":{"id":0}}} diff --git a/test/cmdlineTests/standard_viair_requested/output.json b/test/cmdlineTests/standard_viair_requested/output.json index 9fa0b02a9..3ba066ab4 100644 --- a/test/cmdlineTests/standard_viair_requested/output.json +++ b/test/cmdlineTests/standard_viair_requested/output.json @@ -24,6 +24,10 @@ object \"C_3\" { memPtr := mload(64) } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + /// @src 0:79:92 function constructor_C_3() { @@ -32,10 +36,6 @@ object \"C_3\" { } /// @src 0:79:92 - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - } /// @use-src 0:\"A\" object \"C_3_deployed\" { @@ -53,6 +53,13 @@ object \"C_3\" { if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + function allocate_unbounded() -> memPtr { memPtr := mload(64) } @@ -61,13 +68,6 @@ object \"C_3\" { revert(0, 0) } - function shift_right_224_unsigned(value) -> newValue { - newValue := - - shr(224, value) - - } - } data \".metadata\" hex\"\" @@ -101,6 +101,10 @@ object \"D_16\" { memPtr := mload(64) } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + /// @src 0:93:146 function constructor_D_16() { @@ -109,10 +113,6 @@ object \"D_16\" { } /// @src 0:93:146 - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - } /// @use-src 0:\"A\" object \"D_16_deployed\" { @@ -142,6 +142,25 @@ object \"D_16\" { if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + function abi_decode_tuple_(headStart, dataEnd) { if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } @@ -152,8 +171,20 @@ object \"D_16\" { } - function allocate_unbounded() -> memPtr { - memPtr := mload(64) + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function panic_error_0x41() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x41) + revert(0, 0x24) + } + + function revert_forward_1() { + let pos := allocate_unbounded() + returndatacopy(pos, 0, returndatasize()) + revert(pos, returndatasize()) } /// @src 0:106:144 @@ -176,37 +207,6 @@ object \"D_16\" { } /// @src 0:93:146 - function panic_error_0x41() { - mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) - mstore(4, 0x41) - revert(0, 0x24) - } - - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { - revert(0, 0) - } - - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - - function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { - revert(0, 0) - } - - function revert_forward_1() { - let pos := allocate_unbounded() - returndatacopy(pos, 0, returndatasize()) - revert(pos, returndatasize()) - } - - function shift_right_224_unsigned(value) -> newValue { - newValue := - - shr(224, value) - - } - } /*=====================================================* * WARNING * @@ -233,6 +233,10 @@ object \"D_16\" { memPtr := mload(64) } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + /// @src 0:79:92 function constructor_C_3() { @@ -241,10 +245,6 @@ object \"D_16\" { } /// @src 0:79:92 - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - } /// @use-src 0:\"A\" object \"C_3_deployed\" { @@ -262,6 +262,13 @@ object \"D_16\" { if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + function allocate_unbounded() -> memPtr { memPtr := mload(64) } @@ -270,13 +277,6 @@ object \"D_16\" { revert(0, 0) } - function shift_right_224_unsigned(value) -> newValue { - newValue := - - shr(224, value) - - } - } data \".metadata\" hex\"\" diff --git a/test/cmdlineTests/viair_abicoder_v1/output b/test/cmdlineTests/viair_abicoder_v1/output index 6a164cc43..c3715f007 100644 --- a/test/cmdlineTests/viair_abicoder_v1/output +++ b/test/cmdlineTests/viair_abicoder_v1/output @@ -25,6 +25,10 @@ object "test_11" { memPtr := mload(64) } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + /// @src 0:79:169 function constructor_test_11() { @@ -33,10 +37,6 @@ object "test_11" { } /// @src 0:79:169 - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - } /// @use-src 0:"viair_abicoder_v1/input.sol" object "test_11_deployed" { @@ -66,11 +66,34 @@ object "test_11" { if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + function abi_decode_tuple_(headStart, dataEnd) { if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } } + function cleanup_t_bool(value) -> cleaned { + cleaned := iszero(iszero(value)) + } + function abi_encode_t_bool_to_t_bool_fromStack(value, pos) { mstore(pos, cleanup_t_bool(value)) } @@ -82,12 +105,12 @@ object "test_11" { } - function allocate_unbounded() -> memPtr { - memPtr := mload(64) + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) } - function cleanup_t_bool(value) -> cleaned { - cleaned := iszero(iszero(value)) + function zero_value_for_split_t_bool() -> ret { + ret := 0 } /// @src 0:99:167 @@ -105,29 +128,6 @@ object "test_11" { } /// @src 0:79:169 - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { - revert(0, 0) - } - - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - - function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { - revert(0, 0) - } - - function shift_right_224_unsigned(value) -> newValue { - newValue := - - shr(224, value) - - } - - function zero_value_for_split_t_bool() -> ret { - ret := 0 - } - } data ".metadata" hex"" diff --git a/test/cmdlineTests/yul_optimizer_steps/output b/test/cmdlineTests/yul_optimizer_steps/output index 5db709e53..3e4ba5809 100644 --- a/test/cmdlineTests/yul_optimizer_steps/output +++ b/test/cmdlineTests/yul_optimizer_steps/output @@ -39,10 +39,10 @@ object "C_7" { pop(iszero(calldatasize())) revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() } - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() - { revert(0, 0) } function shift_right_unsigned(value) -> newValue { newValue := shr(224, value) } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + { revert(0, 0) } } data ".metadata" hex"" } diff --git a/test/cmdlineTests/yul_source_locations/output.json b/test/cmdlineTests/yul_source_locations/output.json index 4ce705261..f6f431177 100644 --- a/test/cmdlineTests/yul_source_locations/output.json +++ b/test/cmdlineTests/yul_source_locations/output.json @@ -23,6 +23,52 @@ object \"C_54\" { return(_2, datasize(\"C_54_deployed\")) + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function round_up_to_mul_of_32(value) -> result { + result := and(add(value, 31), not(31)) + } + + function panic_error_0x41() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x41) + revert(0, 0x24) + } + + function finalize_allocation(memPtr, size) { + let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) + // protect against overflow + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } + mstore(64, newFreePtr) + } + + function allocate_memory(size) -> memPtr { + memPtr := allocate_unbounded() + finalize_allocation(memPtr, size) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_int256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_int256(value) { + if iszero(eq(value, cleanup_t_int256(value))) { revert(0, 0) } + } + function abi_decode_t_int256_fromMemory(offset, end) -> value { value := mload(offset) validator_revert_t_int256(value) @@ -40,23 +86,55 @@ object \"C_54\" { } - function allocate_memory(size) -> memPtr { - memPtr := allocate_unbounded() - finalize_allocation(memPtr, size) - } + function copy_arguments_for_constructor_20_object_C_54() -> ret_param_0 { + let programSize := datasize(\"C_54\") + let argSize := sub(codesize(), programSize) - function allocate_unbounded() -> memPtr { - memPtr := mload(64) - } + let memoryDataOffset := allocate_memory(argSize) + codecopy(memoryDataOffset, programSize, argSize) - function cleanup_t_int256(value) -> cleaned { - cleaned := value + ret_param_0 := abi_decode_tuple_t_int256_fromMemory(memoryDataOffset, add(memoryDataOffset, argSize)) } function cleanup_t_rational_42_by_1(value) -> cleaned { cleaned := value } + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_42_by_1_to_t_int256(value) -> converted { + converted := cleanup_t_int256(identity(cleanup_t_rational_42_by_1(value))) + } + + function shift_left_0(value) -> newValue { + newValue := + + shl(0, value) + + } + + function update_byte_slice_32_shift_0(value, toInsert) -> result { + let mask := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + toInsert := shift_left_0(toInsert) + value := and(value, not(mask)) + result := or(value, and(toInsert, mask)) + } + + function convert_t_int256_to_t_int256(value) -> converted { + converted := cleanup_t_int256(identity(cleanup_t_int256(value))) + } + + function prepare_store_t_int256(value) -> ret { + ret := value + } + + function update_storage_value_offset_0t_int256_to_t_int256(slot, value_0) { + let convertedValue_0 := convert_t_int256_to_t_int256(value_0) + sstore(slot, update_byte_slice_32_shift_0(sload(slot), prepare_store_t_int256(convertedValue_0))) + } + /// @src 0:175:223 function constructor_C_54(var__init_12) { @@ -77,84 +155,6 @@ object \"C_54\" { } /// @src 0:79:428 - function convert_t_int256_to_t_int256(value) -> converted { - converted := cleanup_t_int256(identity(cleanup_t_int256(value))) - } - - function convert_t_rational_42_by_1_to_t_int256(value) -> converted { - converted := cleanup_t_int256(identity(cleanup_t_rational_42_by_1(value))) - } - - function copy_arguments_for_constructor_20_object_C_54() -> ret_param_0 { - let programSize := datasize(\"C_54\") - let argSize := sub(codesize(), programSize) - - let memoryDataOffset := allocate_memory(argSize) - codecopy(memoryDataOffset, programSize, argSize) - - ret_param_0 := abi_decode_tuple_t_int256_fromMemory(memoryDataOffset, add(memoryDataOffset, argSize)) - } - - function finalize_allocation(memPtr, size) { - let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) - // protect against overflow - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } - mstore(64, newFreePtr) - } - - function identity(value) -> ret { - ret := value - } - - function panic_error_0x41() { - mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) - mstore(4, 0x41) - revert(0, 0x24) - } - - function prepare_store_t_int256(value) -> ret { - ret := value - } - - function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { - revert(0, 0) - } - - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - - function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { - revert(0, 0) - } - - function round_up_to_mul_of_32(value) -> result { - result := and(add(value, 31), not(31)) - } - - function shift_left_0(value) -> newValue { - newValue := - - shl(0, value) - - } - - function update_byte_slice_32_shift_0(value, toInsert) -> result { - let mask := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - toInsert := shift_left_0(toInsert) - value := and(value, not(mask)) - result := or(value, and(toInsert, mask)) - } - - function update_storage_value_offset_0t_int256_to_t_int256(slot, value_0) { - let convertedValue_0 := convert_t_int256_to_t_int256(value_0) - sstore(slot, update_byte_slice_32_shift_0(sload(slot), prepare_store_t_int256(convertedValue_0))) - } - - function validator_revert_t_int256(value) { - if iszero(eq(value, cleanup_t_int256(value))) { revert(0, 0) } - } - } /// @use-src 0:\"C\" object \"C_54_deployed\" { @@ -208,9 +208,23 @@ object \"C_54\" { if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() - function abi_decode_t_int256_fromMemory(offset, end) -> value { - value := mload(offset) - validator_revert_t_int256(value) + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) } function abi_decode_tuple_(headStart, dataEnd) { @@ -218,27 +232,14 @@ object \"C_54\" { } - function abi_decode_tuple_t_int256_fromMemory(headStart, dataEnd) -> value0 { - if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } - - { - - let offset := 0 - - value0 := abi_decode_t_int256_fromMemory(add(headStart, offset), dataEnd) - } - + function cleanup_t_int256(value) -> cleaned { + cleaned := value } function abi_encode_t_int256_to_t_int256_fromStack(value, pos) { mstore(pos, cleanup_t_int256(value)) } - function abi_encode_tuple__to__fromStack(headStart ) -> tail { - tail := add(headStart, 0) - - } - function abi_encode_tuple_t_int256__to_t_int256__fromStack(headStart , value0) -> tail { tail := add(headStart, 32) @@ -246,8 +247,70 @@ object \"C_54\" { } - function allocate_unbounded() -> memPtr { - memPtr := mload(64) + function shift_right_unsigned_dynamic(bits, value) -> newValue { + newValue := + + shr(bits, value) + + } + + function cleanup_from_storage_t_int256(value) -> cleaned { + cleaned := value + } + + function extract_from_storage_value_dynamict_int256(slot_value, offset) -> value { + value := cleanup_from_storage_t_int256(shift_right_unsigned_dynamic(mul(offset, 8), slot_value)) + } + + function read_from_storage_split_dynamic_t_int256(slot, offset) -> value { + value := extract_from_storage_value_dynamict_int256(sload(slot), offset) + + } + + /// @src 0:152:171 + function getter_fun_stateVar_10() -> ret { + + let slot := 0 + let offset := 0 + + ret := read_from_storage_split_dynamic_t_int256(slot, offset) + + } + /// @src 0:79:428 + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function zero_value_for_split_t_int256() -> ret { + ret := 0 + } + + function cleanup_t_rational_41_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_41_by_1_to_t_int256(value) -> converted { + converted := cleanup_t_int256(identity(cleanup_t_rational_41_by_1(value))) + } + + /// @src 0:93:119 + function constant_constVar_5() -> ret { + /// @src 0:117:119 + let expr_4 := 0x29 + let _2 := convert_t_rational_41_by_1_to_t_int256(expr_4) + + ret := _2 + } + + function panic_error_0x11() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x11) + revert(0, 0x24) } function checked_add_t_int256(x, y) -> sum { @@ -262,57 +325,119 @@ object \"C_54\" { sum := add(x, y) } - function cleanup_from_storage_t_int256(value) -> cleaned { - cleaned := value + /// @src 0:226:302 + function fun_f_30() -> var__23 { + /// @src 0:262:265 + let zero_t_int256_1 := zero_value_for_split_t_int256() + var__23 := zero_t_int256_1 + + /// @src 0:279:287 + let expr_25 := constant_constVar_5() + /// @src 0:290:298 + let _3 := loadimmutable(\"8\") + let expr_26 := _3 + /// @src 0:279:298 + let expr_27 := checked_add_t_int256(expr_25, expr_26) + + /// @src 0:272:298 + var__23 := expr_27 + leave + + } + /// @src 0:79:428 + + function shift_right_0_unsigned(value) -> newValue { + newValue := + + shr(0, value) + } - function cleanup_t_int256(value) -> cleaned { - cleaned := value + function extract_from_storage_value_offset_0t_int256(slot_value) -> value { + value := cleanup_from_storage_t_int256(shift_right_0_unsigned(slot_value)) } - function cleanup_t_rational_41_by_1(value) -> cleaned { - cleaned := value + function read_from_storage_split_offset_0_t_int256(slot) -> value { + value := extract_from_storage_value_offset_0t_int256(sload(slot)) + } - function cleanup_t_uint160(value) -> cleaned { - cleaned := and(value, 0xffffffffffffffffffffffffffffffffffffffff) + function increment_t_int256(value) -> ret { + value := cleanup_t_int256(value) + if eq(value, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) { panic_error_0x11() } + ret := add(value, 1) } - /// @src 0:93:119 - function constant_constVar_5() -> ret { - /// @src 0:117:119 - let expr_4 := 0x29 - let _2 := convert_t_rational_41_by_1_to_t_int256(expr_4) + function shift_left_0(value) -> newValue { + newValue := + + shl(0, value) - ret := _2 } - function convert_t_contract$_C_$54_to_t_address(value) -> converted { - converted := convert_t_uint160_to_t_address(value) + function update_byte_slice_32_shift_0(value, toInsert) -> result { + let mask := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + toInsert := shift_left_0(toInsert) + value := and(value, not(mask)) + result := or(value, and(toInsert, mask)) } function convert_t_int256_to_t_int256(value) -> converted { converted := cleanup_t_int256(identity(cleanup_t_int256(value))) } - function convert_t_rational_41_by_1_to_t_int256(value) -> converted { - converted := cleanup_t_int256(identity(cleanup_t_rational_41_by_1(value))) + function prepare_store_t_int256(value) -> ret { + ret := value } - function convert_t_uint160_to_t_address(value) -> converted { - converted := convert_t_uint160_to_t_uint160(value) + function update_storage_value_offset_0t_int256_to_t_int256(slot, value_0) { + let convertedValue_0 := convert_t_int256_to_t_int256(value_0) + sstore(slot, update_byte_slice_32_shift_0(sload(slot), prepare_store_t_int256(convertedValue_0))) + } + + /// @src 0:304:341 + function modifier_m_40(var__42) -> _5 { + _5 := var__42 + + /// @src 0:322:332 + let _7 := read_from_storage_split_offset_0_t_int256(0x00) + let _6 := increment_t_int256(_7) + update_storage_value_offset_0t_int256_to_t_int256(0x00, _6) + let expr_33 := _7 + /// @src 0:336:337 + _5 := fun_f2_53_inner(var__42) + + } + /// @src 0:79:428 + + function cleanup_t_uint160(value) -> cleaned { + cleaned := and(value, 0xffffffffffffffffffffffffffffffffffffffff) } function convert_t_uint160_to_t_uint160(value) -> converted { converted := cleanup_t_uint160(identity(cleanup_t_uint160(value))) } - function extract_from_storage_value_dynamict_int256(slot_value, offset) -> value { - value := cleanup_from_storage_t_int256(shift_right_unsigned_dynamic(mul(offset, 8), slot_value)) + function convert_t_uint160_to_t_address(value) -> converted { + converted := convert_t_uint160_to_t_uint160(value) } - function extract_from_storage_value_offset_0t_int256(slot_value) -> value { - value := cleanup_from_storage_t_int256(shift_right_0_unsigned(slot_value)) + function convert_t_contract$_C_$54_to_t_address(value) -> converted { + converted := convert_t_uint160_to_t_address(value) + } + + function revert_error_0cc013b6b3b6beabea4e3a74a6d380f0df81852ca99887912475e1f66b2a2c20() { + revert(0, 0) + } + + function round_up_to_mul_of_32(value) -> result { + result := and(add(value, 31), not(31)) + } + + function panic_error_0x41() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x41) + revert(0, 0x24) } function finalize_allocation(memPtr, size) { @@ -322,15 +447,48 @@ object \"C_54\" { mstore(64, newFreePtr) } - /// @src 0:343:426 - function fun_f2_53() -> var__42 { - /// @src 0:375:378 - let zero_t_int256_4 := zero_value_for_split_t_int256() - var__42 := zero_t_int256_4 + function shift_left_224(value) -> newValue { + newValue := + + shl(224, value) - var__42 := modifier_m_40(var__42) } - /// @src 0:79:428 + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function validator_revert_t_int256(value) { + if iszero(eq(value, cleanup_t_int256(value))) { revert(0, 0) } + } + + function abi_decode_t_int256_fromMemory(offset, end) -> value { + value := mload(offset) + validator_revert_t_int256(value) + } + + function abi_decode_tuple_t_int256_fromMemory(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_int256_fromMemory(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function revert_forward_1() { + let pos := allocate_unbounded() + returndatacopy(pos, 0, returndatasize()) + revert(pos, returndatasize()) + } /// @src 0:343:426 function fun_f2_53_inner(_8) -> var__42 { @@ -381,174 +539,16 @@ object \"C_54\" { } /// @src 0:79:428 - /// @src 0:226:302 - function fun_f_30() -> var__23 { - /// @src 0:262:265 - let zero_t_int256_1 := zero_value_for_split_t_int256() - var__23 := zero_t_int256_1 - - /// @src 0:279:287 - let expr_25 := constant_constVar_5() - /// @src 0:290:298 - let _3 := loadimmutable(\"8\") - let expr_26 := _3 - /// @src 0:279:298 - let expr_27 := checked_add_t_int256(expr_25, expr_26) - - /// @src 0:272:298 - var__23 := expr_27 - leave + /// @src 0:343:426 + function fun_f2_53() -> var__42 { + /// @src 0:375:378 + let zero_t_int256_4 := zero_value_for_split_t_int256() + var__42 := zero_t_int256_4 + var__42 := modifier_m_40(var__42) } /// @src 0:79:428 - /// @src 0:152:171 - function getter_fun_stateVar_10() -> ret { - - let slot := 0 - let offset := 0 - - ret := read_from_storage_split_dynamic_t_int256(slot, offset) - - } - /// @src 0:79:428 - - function identity(value) -> ret { - ret := value - } - - function increment_t_int256(value) -> ret { - value := cleanup_t_int256(value) - if eq(value, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) { panic_error_0x11() } - ret := add(value, 1) - } - - /// @src 0:304:341 - function modifier_m_40(var__42) -> _5 { - _5 := var__42 - - /// @src 0:322:332 - let _7 := read_from_storage_split_offset_0_t_int256(0x00) - let _6 := increment_t_int256(_7) - update_storage_value_offset_0t_int256_to_t_int256(0x00, _6) - let expr_33 := _7 - /// @src 0:336:337 - _5 := fun_f2_53_inner(var__42) - - } - /// @src 0:79:428 - - function panic_error_0x11() { - mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) - mstore(4, 0x11) - revert(0, 0x24) - } - - function panic_error_0x41() { - mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) - mstore(4, 0x41) - revert(0, 0x24) - } - - function prepare_store_t_int256(value) -> ret { - ret := value - } - - function read_from_storage_split_dynamic_t_int256(slot, offset) -> value { - value := extract_from_storage_value_dynamict_int256(sload(slot), offset) - - } - - function read_from_storage_split_offset_0_t_int256(slot) -> value { - value := extract_from_storage_value_offset_0t_int256(sload(slot)) - - } - - function revert_error_0cc013b6b3b6beabea4e3a74a6d380f0df81852ca99887912475e1f66b2a2c20() { - revert(0, 0) - } - - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { - revert(0, 0) - } - - function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { - revert(0, 0) - } - - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - - function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { - revert(0, 0) - } - - function revert_forward_1() { - let pos := allocate_unbounded() - returndatacopy(pos, 0, returndatasize()) - revert(pos, returndatasize()) - } - - function round_up_to_mul_of_32(value) -> result { - result := and(add(value, 31), not(31)) - } - - function shift_left_0(value) -> newValue { - newValue := - - shl(0, value) - - } - - function shift_left_224(value) -> newValue { - newValue := - - shl(224, value) - - } - - function shift_right_0_unsigned(value) -> newValue { - newValue := - - shr(0, value) - - } - - function shift_right_224_unsigned(value) -> newValue { - newValue := - - shr(224, value) - - } - - function shift_right_unsigned_dynamic(bits, value) -> newValue { - newValue := - - shr(bits, value) - - } - - function update_byte_slice_32_shift_0(value, toInsert) -> result { - let mask := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - toInsert := shift_left_0(toInsert) - value := and(value, not(mask)) - result := or(value, and(toInsert, mask)) - } - - function update_storage_value_offset_0t_int256_to_t_int256(slot, value_0) { - let convertedValue_0 := convert_t_int256_to_t_int256(value_0) - sstore(slot, update_byte_slice_32_shift_0(sload(slot), prepare_store_t_int256(convertedValue_0))) - } - - function validator_revert_t_int256(value) { - if iszero(eq(value, cleanup_t_int256(value))) { revert(0, 0) } - } - - function zero_value_for_split_t_int256() -> ret { - ret := 0 - } - } data \".metadata\" hex\"\" @@ -581,6 +581,52 @@ object \"D_72\" { return(_2, datasize(\"D_72_deployed\")) + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function round_up_to_mul_of_32(value) -> result { + result := and(add(value, 31), not(31)) + } + + function panic_error_0x41() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x41) + revert(0, 0x24) + } + + function finalize_allocation(memPtr, size) { + let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) + // protect against overflow + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } + mstore(64, newFreePtr) + } + + function allocate_memory(size) -> memPtr { + memPtr := allocate_unbounded() + finalize_allocation(memPtr, size) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function cleanup_t_int256(value) -> cleaned { + cleaned := value + } + + function validator_revert_t_int256(value) { + if iszero(eq(value, cleanup_t_int256(value))) { revert(0, 0) } + } + function abi_decode_t_int256_fromMemory(offset, end) -> value { value := mload(offset) validator_revert_t_int256(value) @@ -598,13 +644,52 @@ object \"D_72\" { } - function allocate_memory(size) -> memPtr { - memPtr := allocate_unbounded() - finalize_allocation(memPtr, size) + function copy_arguments_for_constructor_71_object_D_72() -> ret_param_0 { + let programSize := datasize(\"D_72\") + let argSize := sub(codesize(), programSize) + + let memoryDataOffset := allocate_memory(argSize) + codecopy(memoryDataOffset, programSize, argSize) + + ret_param_0 := abi_decode_tuple_t_int256_fromMemory(memoryDataOffset, add(memoryDataOffset, argSize)) } - function allocate_unbounded() -> memPtr { - memPtr := mload(64) + function cleanup_t_rational_3_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_3_by_1_to_t_int256(value) -> converted { + converted := cleanup_t_int256(identity(cleanup_t_rational_3_by_1(value))) + } + + function shift_right_0_unsigned(value) -> newValue { + newValue := + + shr(0, value) + + } + + function cleanup_from_storage_t_int256(value) -> cleaned { + cleaned := value + } + + function extract_from_storage_value_offset_0t_int256(slot_value) -> value { + value := cleanup_from_storage_t_int256(shift_right_0_unsigned(slot_value)) + } + + function read_from_storage_split_offset_0_t_int256(slot) -> value { + value := extract_from_storage_value_offset_0t_int256(sload(slot)) + + } + + function panic_error_0x11() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x11) + revert(0, 0x24) } function checked_add_t_int256(x, y) -> sum { @@ -619,41 +704,32 @@ object \"D_72\" { sum := add(x, y) } - function cleanup_from_storage_t_int256(value) -> cleaned { - cleaned := value - } + function shift_left_0(value) -> newValue { + newValue := - function cleanup_t_int256(value) -> cleaned { - cleaned := value - } - - function cleanup_t_rational_3_by_1(value) -> cleaned { - cleaned := value - } - - function cleanup_t_rational_42_by_1(value) -> cleaned { - cleaned := value - } - - /// @src 0:175:223 - function constructor_C_54(var__init_12) { - - /// @src 0:175:223 - - /// @src 0:147:149 - let expr_7 := 0x2a - let _6 := convert_t_rational_42_by_1_to_t_int256(expr_7) - mstore(128, _6) - - /// @src 0:214:219 - let _7 := var__init_12 - let expr_16 := _7 - /// @src 0:203:219 - update_storage_value_offset_0t_int256_to_t_int256(0x00, expr_16) - let expr_17 := expr_16 + shl(0, value) } - /// @src 1:91:166 + + function update_byte_slice_32_shift_0(value, toInsert) -> result { + let mask := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + toInsert := shift_left_0(toInsert) + value := and(value, not(mask)) + result := or(value, and(toInsert, mask)) + } + + function convert_t_int256_to_t_int256(value) -> converted { + converted := cleanup_t_int256(identity(cleanup_t_int256(value))) + } + + function prepare_store_t_int256(value) -> ret { + ret := value + } + + function update_storage_value_offset_0t_int256_to_t_int256(slot, value_0) { + let convertedValue_0 := convert_t_int256_to_t_int256(value_0) + sstore(slot, update_byte_slice_32_shift_0(sload(slot), prepare_store_t_int256(convertedValue_0))) + } /// @src 1:113:164 function constructor_D_72(var__init2_63) { @@ -676,109 +752,33 @@ object \"D_72\" { } /// @src 1:91:166 - function convert_t_int256_to_t_int256(value) -> converted { - converted := cleanup_t_int256(identity(cleanup_t_int256(value))) - } - - function convert_t_rational_3_by_1_to_t_int256(value) -> converted { - converted := cleanup_t_int256(identity(cleanup_t_rational_3_by_1(value))) + function cleanup_t_rational_42_by_1(value) -> cleaned { + cleaned := value } function convert_t_rational_42_by_1_to_t_int256(value) -> converted { converted := cleanup_t_int256(identity(cleanup_t_rational_42_by_1(value))) } - function copy_arguments_for_constructor_71_object_D_72() -> ret_param_0 { - let programSize := datasize(\"D_72\") - let argSize := sub(codesize(), programSize) + /// @src 0:175:223 + function constructor_C_54(var__init_12) { - let memoryDataOffset := allocate_memory(argSize) - codecopy(memoryDataOffset, programSize, argSize) + /// @src 0:175:223 - ret_param_0 := abi_decode_tuple_t_int256_fromMemory(memoryDataOffset, add(memoryDataOffset, argSize)) - } + /// @src 0:147:149 + let expr_7 := 0x2a + let _6 := convert_t_rational_42_by_1_to_t_int256(expr_7) + mstore(128, _6) - function extract_from_storage_value_offset_0t_int256(slot_value) -> value { - value := cleanup_from_storage_t_int256(shift_right_0_unsigned(slot_value)) - } - - function finalize_allocation(memPtr, size) { - let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) - // protect against overflow - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } - mstore(64, newFreePtr) - } - - function identity(value) -> ret { - ret := value - } - - function panic_error_0x11() { - mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) - mstore(4, 0x11) - revert(0, 0x24) - } - - function panic_error_0x41() { - mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) - mstore(4, 0x41) - revert(0, 0x24) - } - - function prepare_store_t_int256(value) -> ret { - ret := value - } - - function read_from_storage_split_offset_0_t_int256(slot) -> value { - value := extract_from_storage_value_offset_0t_int256(sload(slot)) + /// @src 0:214:219 + let _7 := var__init_12 + let expr_16 := _7 + /// @src 0:203:219 + update_storage_value_offset_0t_int256_to_t_int256(0x00, expr_16) + let expr_17 := expr_16 } - - function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { - revert(0, 0) - } - - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - - function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { - revert(0, 0) - } - - function round_up_to_mul_of_32(value) -> result { - result := and(add(value, 31), not(31)) - } - - function shift_left_0(value) -> newValue { - newValue := - - shl(0, value) - - } - - function shift_right_0_unsigned(value) -> newValue { - newValue := - - shr(0, value) - - } - - function update_byte_slice_32_shift_0(value, toInsert) -> result { - let mask := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - toInsert := shift_left_0(toInsert) - value := and(value, not(mask)) - result := or(value, and(toInsert, mask)) - } - - function update_storage_value_offset_0t_int256_to_t_int256(slot, value_0) { - let convertedValue_0 := convert_t_int256_to_t_int256(value_0) - sstore(slot, update_byte_slice_32_shift_0(sload(slot), prepare_store_t_int256(convertedValue_0))) - } - - function validator_revert_t_int256(value) { - if iszero(eq(value, cleanup_t_int256(value))) { revert(0, 0) } - } + /// @src 1:91:166 } /// @use-src 0:\"C\", 1:\"D\" @@ -833,9 +833,23 @@ object \"D_72\" { if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() - function abi_decode_t_int256_fromMemory(offset, end) -> value { - value := mload(offset) - validator_revert_t_int256(value) + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) } function abi_decode_tuple_(headStart, dataEnd) { @@ -843,27 +857,14 @@ object \"D_72\" { } - function abi_decode_tuple_t_int256_fromMemory(headStart, dataEnd) -> value0 { - if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } - - { - - let offset := 0 - - value0 := abi_decode_t_int256_fromMemory(add(headStart, offset), dataEnd) - } - + function cleanup_t_int256(value) -> cleaned { + cleaned := value } function abi_encode_t_int256_to_t_int256_fromStack(value, pos) { mstore(pos, cleanup_t_int256(value)) } - function abi_encode_tuple__to__fromStack(headStart ) -> tail { - tail := add(headStart, 0) - - } - function abi_encode_tuple_t_int256__to_t_int256__fromStack(headStart , value0) -> tail { tail := add(headStart, 32) @@ -871,8 +872,70 @@ object \"D_72\" { } - function allocate_unbounded() -> memPtr { - memPtr := mload(64) + function shift_right_unsigned_dynamic(bits, value) -> newValue { + newValue := + + shr(bits, value) + + } + + function cleanup_from_storage_t_int256(value) -> cleaned { + cleaned := value + } + + function extract_from_storage_value_dynamict_int256(slot_value, offset) -> value { + value := cleanup_from_storage_t_int256(shift_right_unsigned_dynamic(mul(offset, 8), slot_value)) + } + + function read_from_storage_split_dynamic_t_int256(slot, offset) -> value { + value := extract_from_storage_value_dynamict_int256(sload(slot), offset) + + } + + /// @src 0:152:171 + function getter_fun_stateVar_10() -> ret { + + let slot := 0 + let offset := 0 + + ret := read_from_storage_split_dynamic_t_int256(slot, offset) + + } + /// @src 1:91:166 + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function zero_value_for_split_t_int256() -> ret { + ret := 0 + } + + function cleanup_t_rational_41_by_1(value) -> cleaned { + cleaned := value + } + + function identity(value) -> ret { + ret := value + } + + function convert_t_rational_41_by_1_to_t_int256(value) -> converted { + converted := cleanup_t_int256(identity(cleanup_t_rational_41_by_1(value))) + } + + /// @src 0:93:119 + function constant_constVar_5() -> ret { + /// @src 0:117:119 + let expr_4 := 0x29 + let _2 := convert_t_rational_41_by_1_to_t_int256(expr_4) + + ret := _2 + } + + function panic_error_0x11() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x11) + revert(0, 0x24) } function checked_add_t_int256(x, y) -> sum { @@ -887,57 +950,119 @@ object \"D_72\" { sum := add(x, y) } - function cleanup_from_storage_t_int256(value) -> cleaned { - cleaned := value + /// @src 0:226:302 + function fun_f_30() -> var__23 { + /// @src 0:262:265 + let zero_t_int256_1 := zero_value_for_split_t_int256() + var__23 := zero_t_int256_1 + + /// @src 0:279:287 + let expr_25 := constant_constVar_5() + /// @src 0:290:298 + let _3 := loadimmutable(\"8\") + let expr_26 := _3 + /// @src 0:279:298 + let expr_27 := checked_add_t_int256(expr_25, expr_26) + + /// @src 0:272:298 + var__23 := expr_27 + leave + + } + /// @src 1:91:166 + + function shift_right_0_unsigned(value) -> newValue { + newValue := + + shr(0, value) + } - function cleanup_t_int256(value) -> cleaned { - cleaned := value + function extract_from_storage_value_offset_0t_int256(slot_value) -> value { + value := cleanup_from_storage_t_int256(shift_right_0_unsigned(slot_value)) } - function cleanup_t_rational_41_by_1(value) -> cleaned { - cleaned := value + function read_from_storage_split_offset_0_t_int256(slot) -> value { + value := extract_from_storage_value_offset_0t_int256(sload(slot)) + } - function cleanup_t_uint160(value) -> cleaned { - cleaned := and(value, 0xffffffffffffffffffffffffffffffffffffffff) + function increment_t_int256(value) -> ret { + value := cleanup_t_int256(value) + if eq(value, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) { panic_error_0x11() } + ret := add(value, 1) } - /// @src 0:93:119 - function constant_constVar_5() -> ret { - /// @src 0:117:119 - let expr_4 := 0x29 - let _2 := convert_t_rational_41_by_1_to_t_int256(expr_4) + function shift_left_0(value) -> newValue { + newValue := + + shl(0, value) - ret := _2 } - function convert_t_contract$_C_$54_to_t_address(value) -> converted { - converted := convert_t_uint160_to_t_address(value) + function update_byte_slice_32_shift_0(value, toInsert) -> result { + let mask := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + toInsert := shift_left_0(toInsert) + value := and(value, not(mask)) + result := or(value, and(toInsert, mask)) } function convert_t_int256_to_t_int256(value) -> converted { converted := cleanup_t_int256(identity(cleanup_t_int256(value))) } - function convert_t_rational_41_by_1_to_t_int256(value) -> converted { - converted := cleanup_t_int256(identity(cleanup_t_rational_41_by_1(value))) + function prepare_store_t_int256(value) -> ret { + ret := value } - function convert_t_uint160_to_t_address(value) -> converted { - converted := convert_t_uint160_to_t_uint160(value) + function update_storage_value_offset_0t_int256_to_t_int256(slot, value_0) { + let convertedValue_0 := convert_t_int256_to_t_int256(value_0) + sstore(slot, update_byte_slice_32_shift_0(sload(slot), prepare_store_t_int256(convertedValue_0))) + } + + /// @src 0:304:341 + function modifier_m_40(var__42) -> _5 { + _5 := var__42 + + /// @src 0:322:332 + let _7 := read_from_storage_split_offset_0_t_int256(0x00) + let _6 := increment_t_int256(_7) + update_storage_value_offset_0t_int256_to_t_int256(0x00, _6) + let expr_33 := _7 + /// @src 0:336:337 + _5 := fun_f2_53_inner(var__42) + + } + /// @src 1:91:166 + + function cleanup_t_uint160(value) -> cleaned { + cleaned := and(value, 0xffffffffffffffffffffffffffffffffffffffff) } function convert_t_uint160_to_t_uint160(value) -> converted { converted := cleanup_t_uint160(identity(cleanup_t_uint160(value))) } - function extract_from_storage_value_dynamict_int256(slot_value, offset) -> value { - value := cleanup_from_storage_t_int256(shift_right_unsigned_dynamic(mul(offset, 8), slot_value)) + function convert_t_uint160_to_t_address(value) -> converted { + converted := convert_t_uint160_to_t_uint160(value) } - function extract_from_storage_value_offset_0t_int256(slot_value) -> value { - value := cleanup_from_storage_t_int256(shift_right_0_unsigned(slot_value)) + function convert_t_contract$_C_$54_to_t_address(value) -> converted { + converted := convert_t_uint160_to_t_address(value) + } + + function revert_error_0cc013b6b3b6beabea4e3a74a6d380f0df81852ca99887912475e1f66b2a2c20() { + revert(0, 0) + } + + function round_up_to_mul_of_32(value) -> result { + result := and(add(value, 31), not(31)) + } + + function panic_error_0x41() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x41) + revert(0, 0x24) } function finalize_allocation(memPtr, size) { @@ -947,15 +1072,48 @@ object \"D_72\" { mstore(64, newFreePtr) } - /// @src 0:343:426 - function fun_f2_53() -> var__42 { - /// @src 0:375:378 - let zero_t_int256_4 := zero_value_for_split_t_int256() - var__42 := zero_t_int256_4 + function shift_left_224(value) -> newValue { + newValue := + + shl(224, value) - var__42 := modifier_m_40(var__42) } - /// @src 1:91:166 + + function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { + revert(0, 0) + } + + function validator_revert_t_int256(value) { + if iszero(eq(value, cleanup_t_int256(value))) { revert(0, 0) } + } + + function abi_decode_t_int256_fromMemory(offset, end) -> value { + value := mload(offset) + validator_revert_t_int256(value) + } + + function abi_decode_tuple_t_int256_fromMemory(headStart, dataEnd) -> value0 { + if slt(sub(dataEnd, headStart), 32) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + { + + let offset := 0 + + value0 := abi_decode_t_int256_fromMemory(add(headStart, offset), dataEnd) + } + + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function revert_forward_1() { + let pos := allocate_unbounded() + returndatacopy(pos, 0, returndatasize()) + revert(pos, returndatasize()) + } /// @src 0:343:426 function fun_f2_53_inner(_8) -> var__42 { @@ -1006,174 +1164,16 @@ object \"D_72\" { } /// @src 1:91:166 - /// @src 0:226:302 - function fun_f_30() -> var__23 { - /// @src 0:262:265 - let zero_t_int256_1 := zero_value_for_split_t_int256() - var__23 := zero_t_int256_1 - - /// @src 0:279:287 - let expr_25 := constant_constVar_5() - /// @src 0:290:298 - let _3 := loadimmutable(\"8\") - let expr_26 := _3 - /// @src 0:279:298 - let expr_27 := checked_add_t_int256(expr_25, expr_26) - - /// @src 0:272:298 - var__23 := expr_27 - leave + /// @src 0:343:426 + function fun_f2_53() -> var__42 { + /// @src 0:375:378 + let zero_t_int256_4 := zero_value_for_split_t_int256() + var__42 := zero_t_int256_4 + var__42 := modifier_m_40(var__42) } /// @src 1:91:166 - /// @src 0:152:171 - function getter_fun_stateVar_10() -> ret { - - let slot := 0 - let offset := 0 - - ret := read_from_storage_split_dynamic_t_int256(slot, offset) - - } - /// @src 1:91:166 - - function identity(value) -> ret { - ret := value - } - - function increment_t_int256(value) -> ret { - value := cleanup_t_int256(value) - if eq(value, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) { panic_error_0x11() } - ret := add(value, 1) - } - - /// @src 0:304:341 - function modifier_m_40(var__42) -> _5 { - _5 := var__42 - - /// @src 0:322:332 - let _7 := read_from_storage_split_offset_0_t_int256(0x00) - let _6 := increment_t_int256(_7) - update_storage_value_offset_0t_int256_to_t_int256(0x00, _6) - let expr_33 := _7 - /// @src 0:336:337 - _5 := fun_f2_53_inner(var__42) - - } - /// @src 1:91:166 - - function panic_error_0x11() { - mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) - mstore(4, 0x11) - revert(0, 0x24) - } - - function panic_error_0x41() { - mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) - mstore(4, 0x41) - revert(0, 0x24) - } - - function prepare_store_t_int256(value) -> ret { - ret := value - } - - function read_from_storage_split_dynamic_t_int256(slot, offset) -> value { - value := extract_from_storage_value_dynamict_int256(sload(slot), offset) - - } - - function read_from_storage_split_offset_0_t_int256(slot) -> value { - value := extract_from_storage_value_offset_0t_int256(sload(slot)) - - } - - function revert_error_0cc013b6b3b6beabea4e3a74a6d380f0df81852ca99887912475e1f66b2a2c20() { - revert(0, 0) - } - - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { - revert(0, 0) - } - - function revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db() { - revert(0, 0) - } - - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - - function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { - revert(0, 0) - } - - function revert_forward_1() { - let pos := allocate_unbounded() - returndatacopy(pos, 0, returndatasize()) - revert(pos, returndatasize()) - } - - function round_up_to_mul_of_32(value) -> result { - result := and(add(value, 31), not(31)) - } - - function shift_left_0(value) -> newValue { - newValue := - - shl(0, value) - - } - - function shift_left_224(value) -> newValue { - newValue := - - shl(224, value) - - } - - function shift_right_0_unsigned(value) -> newValue { - newValue := - - shr(0, value) - - } - - function shift_right_224_unsigned(value) -> newValue { - newValue := - - shr(224, value) - - } - - function shift_right_unsigned_dynamic(bits, value) -> newValue { - newValue := - - shr(bits, value) - - } - - function update_byte_slice_32_shift_0(value, toInsert) -> result { - let mask := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - toInsert := shift_left_0(toInsert) - value := and(value, not(mask)) - result := or(value, and(toInsert, mask)) - } - - function update_storage_value_offset_0t_int256_to_t_int256(slot, value_0) { - let convertedValue_0 := convert_t_int256_to_t_int256(value_0) - sstore(slot, update_byte_slice_32_shift_0(sload(slot), prepare_store_t_int256(convertedValue_0))) - } - - function validator_revert_t_int256(value) { - if iszero(eq(value, cleanup_t_int256(value))) { revert(0, 0) } - } - - function zero_value_for_split_t_int256() -> ret { - ret := 0 - } - } data \".metadata\" hex\"\" diff --git a/test/cmdlineTests/yul_source_locations_in_asm/output.json b/test/cmdlineTests/yul_source_locations_in_asm/output.json index 7c96a12db..56e0a6f31 100644 --- a/test/cmdlineTests/yul_source_locations_in_asm/output.json +++ b/test/cmdlineTests/yul_source_locations_in_asm/output.json @@ -55,6 +55,7 @@ tag_3: mload(0xa0) /* \"C\":147:149 42 */ mstore(0x80, 0x2a) + /* \"C\":203:219 stateVar = _init */ 0x00 /* \"C\":79:428 contract C... */ sstore @@ -186,26 +187,11 @@ sub_0: assembly { tag_23: pop jump\t// out - tag_24: - 0x00 - 0x20 - dup3 - dup5 - sub - slt - iszero - tag_26 - jumpi - 0x00 - dup1 - revert - tag_26: - pop - mload - swap2 - swap1 - pop - jump\t// out + /* \"C\":117:119 41 */ + tag_25: + mstore(0x00, shl(0xe0, 0x4e487b71)) + mstore(0x04, 0x11) + revert(0x00, 0x24) tag_10: 0x00 sub(shl(0xff, 0x01), 0x2a) @@ -214,20 +200,18 @@ sub_0: assembly { 0x01 and iszero - tag_30 + tag_29 jumpi - tag_30 - tag_31 + tag_29 + tag_25 jump\t// in - tag_30: + tag_29: pop - /* \"C\":117:119 41 */ 0x29 - /* \"C\":79:428 contract C... */ add swap1 jump\t// out - tag_32: + tag_30: 0x00 dup1 dup3 @@ -242,12 +226,12 @@ sub_0: assembly { sgt and iszero - tag_35 + tag_33 jumpi - tag_35 - tag_31 + tag_33 + tag_25 jump\t// in - tag_35: + tag_33: shl(0xff, 0x01) dup4 swap1 @@ -257,12 +241,12 @@ sub_0: assembly { dup2 and iszero - tag_37 + tag_35 jumpi - tag_37 - tag_31 + tag_35 + tag_25 jump\t// in - tag_37: + tag_35: pop pop add @@ -282,13 +266,15 @@ sub_0: assembly { dup2 eq iszero - tag_40 + tag_38 jumpi - tag_40 - tag_31 + tag_38 + tag_25 jump\t// in - tag_40: + tag_38: + /* \"C\":117:119 41 */ 0x01 + /* \"C\":79:428 contract C... */ add dup1 dup3 @@ -297,14 +283,14 @@ sub_0: assembly { address /* \"C\":403:411 this.f() */ extcodesize - tag_41 + tag_39 jumpi /* \"C\":79:428 contract C... */ dup2 dup3 revert /* \"C\":403:411 this.f() */ - tag_41: + tag_39: /* \"C\":79:428 contract C... */ mload(0x40) shl(0xe4, 0x026121ff) @@ -324,7 +310,7 @@ sub_0: assembly { gas staticcall dup1 - tag_42 + tag_40 jumpi /* \"C\":79:428 contract C... */ mload(0x40) @@ -336,13 +322,13 @@ sub_0: assembly { dup2 revert /* \"C\":403:411 this.f() */ - tag_42: + tag_40: /* \"C\":79:428 contract C... */ dup4 /* \"C\":403:411 this.f() */ dup2 iszero - tag_43 + tag_41 jumpi returndatasize /* \"C\":79:428 contract C... */ @@ -350,7 +336,6 @@ sub_0: assembly { add not(0x1f) and - /* \"C\":117:119 41 */ dup4 add 0xffffffffffffffff @@ -361,10 +346,9 @@ sub_0: assembly { lt or iszero - tag_44 + tag_42 jumpi shl(0xe0, 0x4e487b71) - /* \"C\":79:428 contract C... */ dup7 mstore 0x41 @@ -375,31 +359,28 @@ sub_0: assembly { 0x24 dup7 revert - /* \"C\":117:119 41 */ - tag_44: - /* \"C\":79:428 contract C... */ + tag_42: 0x40 - /* \"C\":117:119 41 */ mstore /* \"C\":403:411 this.f() */ - tag_45 + tag_43 returndatasize dup5 add dup5 - tag_24 + tag_44 jump\t// in - tag_45: + tag_43: swap1 pop - tag_43: + tag_41: /* \"C\":392:411 stateVar + this.f() */ - tag_46 + tag_45 dup2 dup6 - tag_32 + tag_30 jump\t// in - tag_46: + tag_45: swap5 pop pop @@ -407,14 +388,14 @@ sub_0: assembly { pop pop /* \"C\":392:422 stateVar + this.f() + immutVar */ - tag_47 + tag_46 /* \"C\":414:422 immutVar */ immutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\") /* \"C\":392:422 stateVar + this.f() + immutVar */ dup3 - tag_32 + tag_30 jump\t// in - tag_47: + tag_46: /* \"C\":336:337 _ */ swap2 pop @@ -423,10 +404,26 @@ sub_0: assembly { swap1 jump\t// out /* \"C\":79:428 contract C... */ - tag_31: - mstore(0x00, shl(0xe0, 0x4e487b71)) - mstore(0x04, 0x11) - revert(0x00, 0x24) + tag_44: + 0x00 + 0x20 + dup3 + dup5 + sub + slt + iszero + tag_48 + jumpi + 0x00 + dup1 + revert + tag_48: + pop + mload + swap2 + swap1 + pop + jump\t// out auxdata: } @@ -506,6 +503,7 @@ tag_5: mstore(0x80, 0x2a) /* \"D\":107:108 3 */ 0x03 + /* \"C\":203:219 stateVar = _init */ 0x00 /* \"D\":91:166 contract D is C(3)... */ sstore @@ -517,15 +515,25 @@ tag_5: iszero tag_8 jumpi - mstore(0x00, shl(0xe0, 0x4e487b71)) + shl(0xe0, 0x4e487b71) + /* \"C\":203:219 stateVar = _init */ + 0x00 + /* \"D\":91:166 contract D is C(3)... */ + mstore mstore(0x04, 0x11) - revert(0x00, 0x24) + 0x24 + /* \"C\":203:219 stateVar = _init */ + 0x00 + /* \"D\":91:166 contract D is C(3)... */ + revert tag_8: /* \"D\":107:108 3 */ 0x03 /* \"D\":91:166 contract D is C(3)... */ add + /* \"C\":203:219 stateVar = _init */ 0x00 + /* \"D\":91:166 contract D is C(3)... */ sstore /* \"D\":113:164 constructor(int _init2)... */ jump\t// out @@ -641,26 +649,11 @@ sub_0: assembly { tag_23: pop jump\t// out - tag_24: - 0x00 - 0x20 - dup3 - dup5 - sub - slt - iszero - tag_26 - jumpi - 0x00 - dup1 - revert - tag_26: - pop - mload - swap2 - swap1 - pop - jump\t// out + /* \"C\":117:119 41 */ + tag_25: + mstore(0x00, shl(0xe0, 0x4e487b71)) + mstore(0x04, 0x11) + revert(0x00, 0x24) tag_10: 0x00 sub(shl(0xff, 0x01), 0x2a) @@ -669,20 +662,18 @@ sub_0: assembly { 0x01 and iszero - tag_30 + tag_29 jumpi - tag_30 - tag_31 + tag_29 + tag_25 jump\t// in - tag_30: + tag_29: pop - /* \"C\":117:119 41 */ 0x29 - /* \"D\":91:166 contract D is C(3)... */ add swap1 jump\t// out - tag_32: + tag_30: 0x00 dup1 dup3 @@ -697,12 +688,12 @@ sub_0: assembly { sgt and iszero - tag_35 + tag_33 jumpi - tag_35 - tag_31 + tag_33 + tag_25 jump\t// in - tag_35: + tag_33: shl(0xff, 0x01) dup4 swap1 @@ -712,12 +703,12 @@ sub_0: assembly { dup2 and iszero - tag_37 + tag_35 jumpi - tag_37 - tag_31 + tag_35 + tag_25 jump\t// in - tag_37: + tag_35: pop pop add @@ -737,13 +728,15 @@ sub_0: assembly { dup2 eq iszero - tag_40 + tag_38 jumpi - tag_40 - tag_31 + tag_38 + tag_25 jump\t// in - tag_40: + tag_38: + /* \"C\":117:119 41 */ 0x01 + /* \"D\":91:166 contract D is C(3)... */ add dup1 dup3 @@ -752,14 +745,14 @@ sub_0: assembly { address /* \"C\":403:411 this.f() */ extcodesize - tag_41 + tag_39 jumpi /* \"D\":91:166 contract D is C(3)... */ dup2 dup3 revert /* \"C\":403:411 this.f() */ - tag_41: + tag_39: /* \"D\":91:166 contract D is C(3)... */ mload(0x40) shl(0xe4, 0x026121ff) @@ -779,7 +772,7 @@ sub_0: assembly { gas staticcall dup1 - tag_42 + tag_40 jumpi /* \"D\":91:166 contract D is C(3)... */ mload(0x40) @@ -791,13 +784,13 @@ sub_0: assembly { dup2 revert /* \"C\":403:411 this.f() */ - tag_42: + tag_40: /* \"D\":91:166 contract D is C(3)... */ dup4 /* \"C\":403:411 this.f() */ dup2 iszero - tag_43 + tag_41 jumpi returndatasize /* \"D\":91:166 contract D is C(3)... */ @@ -805,7 +798,6 @@ sub_0: assembly { add not(0x1f) and - /* \"C\":117:119 41 */ dup4 add 0xffffffffffffffff @@ -816,10 +808,9 @@ sub_0: assembly { lt or iszero - tag_44 + tag_42 jumpi shl(0xe0, 0x4e487b71) - /* \"D\":91:166 contract D is C(3)... */ dup7 mstore 0x41 @@ -830,31 +821,28 @@ sub_0: assembly { 0x24 dup7 revert - /* \"C\":117:119 41 */ - tag_44: - /* \"D\":91:166 contract D is C(3)... */ + tag_42: 0x40 - /* \"C\":117:119 41 */ mstore /* \"C\":403:411 this.f() */ - tag_45 + tag_43 returndatasize dup5 add dup5 - tag_24 + tag_44 jump\t// in - tag_45: + tag_43: swap1 pop - tag_43: + tag_41: /* \"C\":392:411 stateVar + this.f() */ - tag_46 + tag_45 dup2 dup6 - tag_32 + tag_30 jump\t// in - tag_46: + tag_45: swap5 pop pop @@ -862,14 +850,14 @@ sub_0: assembly { pop pop /* \"C\":392:422 stateVar + this.f() + immutVar */ - tag_47 + tag_46 /* \"C\":414:422 immutVar */ immutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\") /* \"C\":392:422 stateVar + this.f() + immutVar */ dup3 - tag_32 + tag_30 jump\t// in - tag_47: + tag_46: /* \"C\":336:337 _ */ swap2 pop @@ -878,10 +866,26 @@ sub_0: assembly { swap1 jump\t// out /* \"D\":91:166 contract D is C(3)... */ - tag_31: - mstore(0x00, shl(0xe0, 0x4e487b71)) - mstore(0x04, 0x11) - revert(0x00, 0x24) + tag_44: + 0x00 + 0x20 + dup3 + dup5 + sub + slt + iszero + tag_48 + jumpi + 0x00 + dup1 + revert + tag_48: + pop + mload + swap2 + swap1 + pop + jump\t// out auxdata: } diff --git a/test/cmdlineTests/yul_string_format_ascii/output.json b/test/cmdlineTests/yul_string_format_ascii/output.json index 76a14d5cb..4c42c4f78 100644 --- a/test/cmdlineTests/yul_string_format_ascii/output.json +++ b/test/cmdlineTests/yul_string_format_ascii/output.json @@ -24,6 +24,10 @@ object \"C_11\" { memPtr := mload(64) } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + /// @src 0:78:164 function constructor_C_11() { @@ -32,10 +36,6 @@ object \"C_11\" { } /// @src 0:78:164 - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - } /// @use-src 0:\"A\" object \"C_11_deployed\" { @@ -65,11 +65,58 @@ object \"C_11\" { if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + function abi_decode_tuple_(headStart, dataEnd) { if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } } + function array_length_t_string_memory_ptr(value) -> length { + + length := mload(value) + + } + + function array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, length) -> updated_pos { + mstore(pos, length) + updated_pos := add(pos, 0x20) + } + + function copy_memory_to_memory(src, dst, length) { + let i := 0 + for { } lt(i, length) { i := add(i, 32) } + { + mstore(add(dst, i), mload(add(src, i))) + } + if gt(i, length) + { + // clear end + mstore(add(dst, length), 0) + } + } + + function round_up_to_mul_of_32(value) -> result { + result := and(add(value, 31), not(31)) + } + function abi_encode_t_string_memory_ptr_to_t_string_memory_ptr_fromStack(value, pos) -> end { let length := array_length_t_string_memory_ptr(value) pos := array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, length) @@ -85,23 +132,32 @@ object \"C_11\" { } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function zero_value_for_split_t_string_memory_ptr() -> ret { + ret := 96 + } + + function panic_error_0x41() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x41) + revert(0, 0x24) + } + + function finalize_allocation(memPtr, size) { + let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) + // protect against overflow + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } + mstore(64, newFreePtr) + } + function allocate_memory(size) -> memPtr { memPtr := allocate_unbounded() finalize_allocation(memPtr, size) } - function allocate_memory_array_t_string_memory_ptr(length) -> memPtr { - let allocSize := array_allocation_size_t_string_memory_ptr(length) - memPtr := allocate_memory(allocSize) - - mstore(memPtr, length) - - } - - function allocate_unbounded() -> memPtr { - memPtr := mload(64) - } - function array_allocation_size_t_string_memory_ptr(length) -> size { // Make sure we can allocate memory without overflow if gt(length, 0xffffffffffffffff) { panic_error_0x41() } @@ -113,19 +169,18 @@ object \"C_11\" { } - function array_length_t_string_memory_ptr(value) -> length { + function allocate_memory_array_t_string_memory_ptr(length) -> memPtr { + let allocSize := array_allocation_size_t_string_memory_ptr(length) + memPtr := allocate_memory(allocSize) - length := mload(value) + mstore(memPtr, length) } - function array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, length) -> updated_pos { - mstore(pos, length) - updated_pos := add(pos, 0x20) - } + function store_literal_in_memory_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21(memPtr) { + + mstore(add(memPtr, 0), \"abcabc\") - function convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_string_memory_ptr() -> converted { - converted := copy_literal_to_memory_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21() } function copy_literal_to_memory_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21() -> memPtr { @@ -133,24 +188,8 @@ object \"C_11\" { store_literal_in_memory_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21(add(memPtr, 32)) } - function copy_memory_to_memory(src, dst, length) { - let i := 0 - for { } lt(i, length) { i := add(i, 32) } - { - mstore(add(dst, i), mload(add(src, i))) - } - if gt(i, length) - { - // clear end - mstore(add(dst, length), 0) - } - } - - function finalize_allocation(memPtr, size) { - let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) - // protect against overflow - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } - mstore(64, newFreePtr) + function convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_string_memory_ptr() -> converted { + converted := copy_literal_to_memory_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21() } /// @src 0:91:162 @@ -166,45 +205,6 @@ object \"C_11\" { } /// @src 0:78:164 - function panic_error_0x41() { - mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) - mstore(4, 0x41) - revert(0, 0x24) - } - - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { - revert(0, 0) - } - - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - - function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { - revert(0, 0) - } - - function round_up_to_mul_of_32(value) -> result { - result := and(add(value, 31), not(31)) - } - - function shift_right_224_unsigned(value) -> newValue { - newValue := - - shr(224, value) - - } - - function store_literal_in_memory_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21(memPtr) { - - mstore(add(memPtr, 0), \"abcabc\") - - } - - function zero_value_for_split_t_string_memory_ptr() -> ret { - ret := 96 - } - } data \".metadata\" hex\"\" diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json index 39046124f..0832d0e4e 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json @@ -24,6 +24,10 @@ object \"C_11\" { memPtr := mload(64) } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + /// @src 0:78:158 function constructor_C_11() { @@ -32,10 +36,6 @@ object \"C_11\" { } /// @src 0:78:158 - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - } /// @use-src 0:\"A\" object \"C_11_deployed\" { @@ -65,11 +65,34 @@ object \"C_11\" { if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + function abi_decode_tuple_(headStart, dataEnd) { if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } } + function cleanup_t_bytes32(value) -> cleaned { + cleaned := value + } + function abi_encode_t_bytes32_to_t_bytes32_fromStack(value, pos) { mstore(pos, cleanup_t_bytes32(value)) } @@ -81,12 +104,12 @@ object \"C_11\" { } - function allocate_unbounded() -> memPtr { - memPtr := mload(64) + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) } - function cleanup_t_bytes32(value) -> cleaned { - cleaned := value + function zero_value_for_split_t_bytes32() -> ret { + ret := 0 } function convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_bytes32() -> converted { @@ -106,29 +129,6 @@ object \"C_11\" { } /// @src 0:78:158 - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { - revert(0, 0) - } - - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - - function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { - revert(0, 0) - } - - function shift_right_224_unsigned(value) -> newValue { - newValue := - - shr(224, value) - - } - - function zero_value_for_split_t_bytes32() -> ret { - ret := 0 - } - } data \".metadata\" hex\"\" diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json index 8ff41db27..f6c63057c 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json @@ -24,6 +24,10 @@ object \"C_11\" { memPtr := mload(64) } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + /// @src 0:78:159 function constructor_C_11() { @@ -32,10 +36,6 @@ object \"C_11\" { } /// @src 0:78:159 - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - } /// @use-src 0:\"A\" object \"C_11_deployed\" { @@ -65,11 +65,34 @@ object \"C_11\" { if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + function abi_decode_tuple_(headStart, dataEnd) { if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } } + function cleanup_t_bytes4(value) -> cleaned { + cleaned := and(value, 0xffffffff00000000000000000000000000000000000000000000000000000000) + } + function abi_encode_t_bytes4_to_t_bytes4_fromStack(value, pos) { mstore(pos, cleanup_t_bytes4(value)) } @@ -81,18 +104,25 @@ object \"C_11\" { } - function allocate_unbounded() -> memPtr { - memPtr := mload(64) + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) } - function cleanup_t_bytes4(value) -> cleaned { - cleaned := and(value, 0xffffffff00000000000000000000000000000000000000000000000000000000) + function zero_value_for_split_t_bytes4() -> ret { + ret := 0 } function cleanup_t_rational_1633837924_by_1(value) -> cleaned { cleaned := value } + function shift_left_224(value) -> newValue { + newValue := + + shl(224, value) + + } + function convert_t_rational_1633837924_by_1_to_t_bytes4(value) -> converted { converted := cleanup_t_bytes4(shift_left_224(cleanup_t_rational_1633837924_by_1(value))) } @@ -112,36 +142,6 @@ object \"C_11\" { } /// @src 0:78:159 - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { - revert(0, 0) - } - - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - - function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { - revert(0, 0) - } - - function shift_left_224(value) -> newValue { - newValue := - - shl(224, value) - - } - - function shift_right_224_unsigned(value) -> newValue { - newValue := - - shr(224, value) - - } - - function zero_value_for_split_t_bytes4() -> ret { - ret := 0 - } - } data \".metadata\" hex\"\" diff --git a/test/cmdlineTests/yul_string_format_ascii_long/output.json b/test/cmdlineTests/yul_string_format_ascii_long/output.json index 8c7c8b38a..c1f4cd6e2 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/output.json @@ -24,6 +24,10 @@ object \"C_11\" { memPtr := mload(64) } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + /// @src 0:78:243 function constructor_C_11() { @@ -32,10 +36,6 @@ object \"C_11\" { } /// @src 0:78:243 - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - } /// @use-src 0:\"A\" object \"C_11_deployed\" { @@ -65,11 +65,58 @@ object \"C_11\" { if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + function abi_decode_tuple_(headStart, dataEnd) { if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } } + function array_length_t_string_memory_ptr(value) -> length { + + length := mload(value) + + } + + function array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, length) -> updated_pos { + mstore(pos, length) + updated_pos := add(pos, 0x20) + } + + function copy_memory_to_memory(src, dst, length) { + let i := 0 + for { } lt(i, length) { i := add(i, 32) } + { + mstore(add(dst, i), mload(add(src, i))) + } + if gt(i, length) + { + // clear end + mstore(add(dst, length), 0) + } + } + + function round_up_to_mul_of_32(value) -> result { + result := and(add(value, 31), not(31)) + } + function abi_encode_t_string_memory_ptr_to_t_string_memory_ptr_fromStack(value, pos) -> end { let length := array_length_t_string_memory_ptr(value) pos := array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, length) @@ -85,23 +132,32 @@ object \"C_11\" { } + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function zero_value_for_split_t_string_memory_ptr() -> ret { + ret := 96 + } + + function panic_error_0x41() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x41) + revert(0, 0x24) + } + + function finalize_allocation(memPtr, size) { + let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) + // protect against overflow + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } + mstore(64, newFreePtr) + } + function allocate_memory(size) -> memPtr { memPtr := allocate_unbounded() finalize_allocation(memPtr, size) } - function allocate_memory_array_t_string_memory_ptr(length) -> memPtr { - let allocSize := array_allocation_size_t_string_memory_ptr(length) - memPtr := allocate_memory(allocSize) - - mstore(memPtr, length) - - } - - function allocate_unbounded() -> memPtr { - memPtr := mload(64) - } - function array_allocation_size_t_string_memory_ptr(length) -> size { // Make sure we can allocate memory without overflow if gt(length, 0xffffffffffffffff) { panic_error_0x41() } @@ -113,19 +169,22 @@ object \"C_11\" { } - function array_length_t_string_memory_ptr(value) -> length { + function allocate_memory_array_t_string_memory_ptr(length) -> memPtr { + let allocSize := array_allocation_size_t_string_memory_ptr(length) + memPtr := allocate_memory(allocSize) - length := mload(value) + mstore(memPtr, length) } - function array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, length) -> updated_pos { - mstore(pos, length) - updated_pos := add(pos, 0x20) - } + function store_literal_in_memory_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571(memPtr) { + + mstore(add(memPtr, 0), \"abcdabcdcafecafeabcdabcdcafecafe\") + + mstore(add(memPtr, 32), \"ffffzzzzoooo0123456789,.<,>.?:;'\") + + mstore(add(memPtr, 64), \"[{]}|`~!@#$%^&*()-_=+\") - function convert_t_stringliteral_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571_to_t_string_memory_ptr() -> converted { - converted := copy_literal_to_memory_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571() } function copy_literal_to_memory_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571() -> memPtr { @@ -133,24 +192,8 @@ object \"C_11\" { store_literal_in_memory_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571(add(memPtr, 32)) } - function copy_memory_to_memory(src, dst, length) { - let i := 0 - for { } lt(i, length) { i := add(i, 32) } - { - mstore(add(dst, i), mload(add(src, i))) - } - if gt(i, length) - { - // clear end - mstore(add(dst, length), 0) - } - } - - function finalize_allocation(memPtr, size) { - let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) - // protect against overflow - if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } - mstore(64, newFreePtr) + function convert_t_stringliteral_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571_to_t_string_memory_ptr() -> converted { + converted := copy_literal_to_memory_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571() } /// @src 0:91:241 @@ -166,49 +209,6 @@ object \"C_11\" { } /// @src 0:78:243 - function panic_error_0x41() { - mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) - mstore(4, 0x41) - revert(0, 0x24) - } - - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { - revert(0, 0) - } - - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - - function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { - revert(0, 0) - } - - function round_up_to_mul_of_32(value) -> result { - result := and(add(value, 31), not(31)) - } - - function shift_right_224_unsigned(value) -> newValue { - newValue := - - shr(224, value) - - } - - function store_literal_in_memory_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571(memPtr) { - - mstore(add(memPtr, 0), \"abcdabcdcafecafeabcdabcdcafecafe\") - - mstore(add(memPtr, 32), \"ffffzzzzoooo0123456789,.<,>.?:;'\") - - mstore(add(memPtr, 64), \"[{]}|`~!@#$%^&*()-_=+\") - - } - - function zero_value_for_split_t_string_memory_ptr() -> ret { - ret := 96 - } - } data \".metadata\" hex\"\" diff --git a/test/cmdlineTests/yul_string_format_hex/output.json b/test/cmdlineTests/yul_string_format_hex/output.json index 58f2d628a..a5a46751a 100644 --- a/test/cmdlineTests/yul_string_format_hex/output.json +++ b/test/cmdlineTests/yul_string_format_hex/output.json @@ -24,6 +24,10 @@ object \"C_11\" { memPtr := mload(64) } + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + /// @src 0:78:159 function constructor_C_11() { @@ -32,10 +36,6 @@ object \"C_11\" { } /// @src 0:78:159 - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - } /// @use-src 0:\"A\" object \"C_11_deployed\" { @@ -65,11 +65,34 @@ object \"C_11\" { if iszero(calldatasize()) { } revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + function abi_decode_tuple_(headStart, dataEnd) { if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } } + function cleanup_t_bytes4(value) -> cleaned { + cleaned := and(value, 0xffffffff00000000000000000000000000000000000000000000000000000000) + } + function abi_encode_t_bytes4_to_t_bytes4_fromStack(value, pos) { mstore(pos, cleanup_t_bytes4(value)) } @@ -81,18 +104,25 @@ object \"C_11\" { } - function allocate_unbounded() -> memPtr { - memPtr := mload(64) + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) } - function cleanup_t_bytes4(value) -> cleaned { - cleaned := and(value, 0xffffffff00000000000000000000000000000000000000000000000000000000) + function zero_value_for_split_t_bytes4() -> ret { + ret := 0 } function cleanup_t_rational_2864434397_by_1(value) -> cleaned { cleaned := value } + function shift_left_224(value) -> newValue { + newValue := + + shl(224, value) + + } + function convert_t_rational_2864434397_by_1_to_t_bytes4(value) -> converted { converted := cleanup_t_bytes4(shift_left_224(cleanup_t_rational_2864434397_by_1(value))) } @@ -112,36 +142,6 @@ object \"C_11\" { } /// @src 0:78:159 - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { - revert(0, 0) - } - - function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { - revert(0, 0) - } - - function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { - revert(0, 0) - } - - function shift_left_224(value) -> newValue { - newValue := - - shl(224, value) - - } - - function shift_right_224_unsigned(value) -> newValue { - newValue := - - shr(224, value) - - } - - function zero_value_for_split_t_bytes4() -> ret { - ret := 0 - } - } data \".metadata\" hex\"\" From 4b0cd6cc8cdfa6337421c0a9610c3a2c0343c08f Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 7 Sep 2021 18:01:45 +0200 Subject: [PATCH 038/232] Update gas costs. --- test/libsolidity/GasCosts.cpp | 6 +++--- test/libsolidity/gasTests/abiv2_optimised.sol | 4 ++-- ...abi_encode_v2_in_function_inherited_in_v1_contract.sol | 2 +- .../array/copying/array_copy_storage_storage_dyn_dyn.sol | 2 +- .../array/copying/array_nested_memory_to_storage.sol | 2 +- ...y_of_structs_containing_arrays_calldata_to_storage.sol | 2 +- .../semanticTests/externalContracts/prbmath_unsigned.sol | 4 ++-- .../semanticTests/externalContracts/ramanujan_pi.sol | 6 +++--- .../semanticTests/externalContracts/strings.sol | 8 ++++---- .../semanticTests/functionTypes/store_function.sol | 2 +- .../structs/struct_delete_storage_nested_small.sol | 2 +- test/libsolidity/semanticTests/various/erc20.sol | 8 ++++---- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/test/libsolidity/GasCosts.cpp b/test/libsolidity/GasCosts.cpp index a03ccbb1e..b3fb9d8b7 100644 --- a/test/libsolidity/GasCosts.cpp +++ b/test/libsolidity/GasCosts.cpp @@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(string_storage) if (CommonOptions::get().useABIEncoderV1) CHECK_DEPLOY_GAS(133045, 129731, evmVersion); else - CHECK_DEPLOY_GAS(144679, 121229, evmVersion); + CHECK_DEPLOY_GAS(144999, 121229, evmVersion); } // This is only correct on >=Constantinople. else if (!CommonOptions::get().useABIEncoderV1) @@ -117,9 +117,9 @@ BOOST_AUTO_TEST_CASE(string_storage) else { if (evmVersion < EVMVersion::istanbul()) - CHECK_DEPLOY_GAS(138693, 123969, evmVersion); + CHECK_DEPLOY_GAS(139013, 123969, evmVersion); else - CHECK_DEPLOY_GAS(123301, 110969, evmVersion); + CHECK_DEPLOY_GAS(123361, 110969, evmVersion); } } else if (evmVersion < EVMVersion::istanbul()) diff --git a/test/libsolidity/gasTests/abiv2_optimised.sol b/test/libsolidity/gasTests/abiv2_optimised.sol index 093acf49a..074e75f1b 100644 --- a/test/libsolidity/gasTests/abiv2_optimised.sol +++ b/test/libsolidity/gasTests/abiv2_optimised.sol @@ -17,9 +17,9 @@ contract C { // optimize-yul: true // ---- // creation: -// codeDepositCost: 680600 +// codeDepositCost: 681000 // executionCost: 715 -// totalCost: 681315 +// totalCost: 681715 // external: // a(): 2285 // b(uint256): 4652 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol index f278d314a..a216efec1 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol @@ -32,6 +32,6 @@ contract C is B { // compileViaYul: also // ---- // test() -> 77 -// gas irOptimized: 120952 +// gas irOptimized: 121752 // gas legacy: 155249 // gas legacyOptimized: 111743 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_dyn_dyn.sol b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_dyn_dyn.sol index b28049ce7..05e038378 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_dyn_dyn.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_dyn_dyn.sol @@ -17,7 +17,7 @@ contract c { // ---- // setData1(uint256,uint256,uint256): 10, 5, 4 -> // copyStorageStorage() -> -// gas irOptimized: 111487 +// gas irOptimized: 111488 // gas legacy: 109278 // gas legacyOptimized: 109268 // getData2(uint256): 5 -> 10, 4 diff --git a/test/libsolidity/semanticTests/array/copying/array_nested_memory_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_nested_memory_to_storage.sol index f807b8e2c..707e25056 100644 --- a/test/libsolidity/semanticTests/array/copying/array_nested_memory_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/array_nested_memory_to_storage.sol @@ -46,6 +46,6 @@ contract Test { // test1() -> 3 // test2() -> 6 // test3() -> 24 -// gas irOptimized: 133742 +// gas irOptimized: 133753 // gas legacy: 134295 // gas legacyOptimized: 133383 diff --git a/test/libsolidity/semanticTests/array/copying/array_of_structs_containing_arrays_calldata_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_of_structs_containing_arrays_calldata_to_storage.sol index db32fc1d3..970a5dced 100644 --- a/test/libsolidity/semanticTests/array/copying/array_of_structs_containing_arrays_calldata_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/array_of_structs_containing_arrays_calldata_to_storage.sol @@ -23,4 +23,4 @@ contract C { // compileViaYul: true // ---- // f((uint256[])[]): 0x20, 3, 0x60, 0x60, 0x60, 0x20, 3, 1, 2, 3 -> 3, 1 -// gas irOptimized: 330384 +// gas irOptimized: 330385 diff --git a/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol b/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol index b15cf5deb..8a096f524 100644 --- a/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol +++ b/test/libsolidity/semanticTests/externalContracts/prbmath_unsigned.sol @@ -50,7 +50,7 @@ contract test { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 1770739 +// gas irOptimized: 1769431 // gas legacy: 2356230 // gas legacyOptimized: 1746528 // div(uint256,uint256): 3141592653589793238, 88714123 -> 35412542528203691288251815328 @@ -58,7 +58,7 @@ contract test { // gas legacy: 22497 // gas legacyOptimized: 22010 // exp(uint256): 3141592653589793238 -> 23140692632779268978 -// gas irOptimized: 24245 +// gas irOptimized: 24234 // gas legacy: 25104 // gas legacyOptimized: 24258 // exp2(uint256): 3141592653589793238 -> 8824977827076287620 diff --git a/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol b/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol index 98eb25470..2c9376b22 100644 --- a/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol +++ b/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol @@ -35,10 +35,10 @@ contract test { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 526745 +// gas irOptimized: 528041 // gas legacy: 733634 -// gas legacyOptimized: 478742 +// gas legacyOptimized: 479606 // prb_pi() -> 3141592656369545286 -// gas irOptimized: 62867 +// gas irOptimized: 63027 // gas legacy: 98903 // gas legacyOptimized: 75735 diff --git a/test/libsolidity/semanticTests/externalContracts/strings.sol b/test/libsolidity/semanticTests/externalContracts/strings.sol index b20d53f29..1fa79f382 100644 --- a/test/libsolidity/semanticTests/externalContracts/strings.sol +++ b/test/libsolidity/semanticTests/externalContracts/strings.sol @@ -51,11 +51,11 @@ contract test { // compileViaYul: also // ---- // constructor() -// gas irOptimized: 776466 +// gas irOptimized: 778254 // gas legacy: 1188228 -// gas legacyOptimized: 749336 +// gas legacyOptimized: 750416 // toSlice(string): 0x20, 11, "hello world" -> 11, 0xa0 -// gas irOptimized: 22723 +// gas irOptimized: 22734 // gas legacy: 23190 // gas legacyOptimized: 22508 // roundtrip(string): 0x20, 11, "hello world" -> 0x20, 11, "hello world" @@ -67,7 +67,7 @@ contract test { // gas legacy: 25716 // gas legacyOptimized: 24115 // multiconcat(string,uint256): 0x40, 3, 11, "hello world" -> 0x20, 0x58, 0x68656c6c6f20776f726c6468656c6c6f20776f726c6468656c6c6f20776f726c, 0x6468656c6c6f20776f726c6468656c6c6f20776f726c6468656c6c6f20776f72, 49027192869463622675296414541903001712009715982962058146354235762728281047040 # concatenating 3 times # -// gas irOptimized: 28962 +// gas irOptimized: 28958 // gas legacy: 31621 // gas legacyOptimized: 27914 // benchmark(string,bytes32): 0x40, 0x0842021, 8, "solidity" -> 0x2020 diff --git a/test/libsolidity/semanticTests/functionTypes/store_function.sol b/test/libsolidity/semanticTests/functionTypes/store_function.sol index 9537fda7f..ddebc11b7 100644 --- a/test/libsolidity/semanticTests/functionTypes/store_function.sol +++ b/test/libsolidity/semanticTests/functionTypes/store_function.sol @@ -28,6 +28,6 @@ contract C { // compileViaYul: also // ---- // t() -> 9 -// gas irOptimized: 99004 +// gas irOptimized: 99010 // gas legacy: 159083 // gas legacyOptimized: 108916 diff --git a/test/libsolidity/semanticTests/structs/struct_delete_storage_nested_small.sol b/test/libsolidity/semanticTests/structs/struct_delete_storage_nested_small.sol index b0e6b7b10..838539628 100644 --- a/test/libsolidity/semanticTests/structs/struct_delete_storage_nested_small.sol +++ b/test/libsolidity/semanticTests/structs/struct_delete_storage_nested_small.sol @@ -33,4 +33,4 @@ contract C { // compileViaYul: true // ---- // f() -> 0, 0, 0 -// gas irOptimized: 117648 +// gas irOptimized: 117388 diff --git a/test/libsolidity/semanticTests/various/erc20.sol b/test/libsolidity/semanticTests/various/erc20.sol index 61c1f0bab..6e7487ee5 100644 --- a/test/libsolidity/semanticTests/various/erc20.sol +++ b/test/libsolidity/semanticTests/various/erc20.sol @@ -98,7 +98,7 @@ contract ERC20 { // ---- // constructor() // ~ emit Transfer(address,address,uint256): #0x00, #0x1212121212121212121212121212120000000012, 0x14 -// gas irOptimized: 460447 +// gas irOptimized: 459547 // gas legacy: 833310 // gas legacyOptimized: 416135 // totalSupply() -> 20 @@ -107,12 +107,12 @@ contract ERC20 { // gas legacyOptimized: 23368 // transfer(address,uint256): 2, 5 -> true // ~ emit Transfer(address,address,uint256): #0x1212121212121212121212121212120000000012, #0x02, 0x05 -// gas irOptimized: 48514 +// gas irOptimized: 48503 // gas legacy: 49317 // gas legacyOptimized: 48491 // decreaseAllowance(address,uint256): 2, 0 -> true // ~ emit Approval(address,address,uint256): #0x1212121212121212121212121212120000000012, #0x02, 0x00 -// gas irOptimized: 26316 +// gas irOptimized: 26327 // gas legacy: 27012 // gas legacyOptimized: 26275 // decreaseAllowance(address,uint256): 2, 1 -> FAILURE, hex"4e487b71", 0x11 @@ -121,7 +121,7 @@ contract ERC20 { // gas legacyOptimized: 24056 // transfer(address,uint256): 2, 14 -> true // ~ emit Transfer(address,address,uint256): #0x1212121212121212121212121212120000000012, #0x02, 0x0e -// gas irOptimized: 28614 +// gas irOptimized: 28603 // gas legacy: 29417 // gas legacyOptimized: 28591 // transfer(address,uint256): 2, 2 -> FAILURE, hex"4e487b71", 0x11 From 0b5671c885331e2ab33c1386ba16e0118f2e65b3 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 8 Sep 2021 12:18:00 +0200 Subject: [PATCH 039/232] Clarify C++ evaluation order. --- .../codegen/ir/IRGeneratorForStatements.cpp | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 8f281a10e..48e381e31 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -798,10 +798,8 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp) if (auto type = dynamic_cast(commonType)) isSigned = type->isSigned(); - string args = - expressionAsType(_binOp.leftExpression(), *commonType, true) + - ", " + - expressionAsType(_binOp.rightExpression(), *commonType, true); + string args = expressionAsType(_binOp.leftExpression(), *commonType, true); + args += ", " + expressionAsType(_binOp.rightExpression(), *commonType, true); string expr; if (op == Token::Equal) @@ -1115,16 +1113,14 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) IRVariable array = convert(*arguments[0], *TypeProvider::bytesMemory()); IRVariable hashVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(32)); + string dataAreaFunction = m_utils.arrayDataAreaFunction(*TypeProvider::bytesMemory()); + string arrayLengthFunction = m_utils.arrayLengthFunction(*TypeProvider::bytesMemory()); define(hashVariable) << "keccak256(" << - m_utils.arrayDataAreaFunction(*TypeProvider::bytesMemory()) << - "(" << - array.commaSeparatedList() << - "), " << - m_utils.arrayLengthFunction(*TypeProvider::bytesMemory()) << - "(" << - array.commaSeparatedList() << - "))\n"; + (dataAreaFunction + "(" + array.commaSeparatedList() + ")") << + ", " << + (arrayLengthFunction + "(" + array.commaSeparatedList() +")") << + ")\n"; IRVariable selectorVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(4)); define(selectorVariable, hashVariable); selector = selectorVariable.name(); @@ -1249,16 +1245,14 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) { auto array = convert(*arguments[0], *arrayType); + string dataAreaFunction = m_utils.arrayDataAreaFunction(*arrayType); + string arrayLengthFunction = m_utils.arrayLengthFunction(*arrayType); define(_functionCall) << "keccak256(" << - m_utils.arrayDataAreaFunction(*arrayType) << - "(" << - array.commaSeparatedList() << - "), " << - m_utils.arrayLengthFunction(*arrayType) << - "(" << - array.commaSeparatedList() << - "))\n"; + (dataAreaFunction + "(" + array.commaSeparatedList() + ")") << + ", " << + (arrayLengthFunction + "(" + array.commaSeparatedList() +")") << + ")\n"; } break; } @@ -1646,11 +1640,14 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) expressionAsType(_memberAccess.expression(), *TypeProvider::address()) << ")\n"; else if (member == "code") + { + string externalCodeFunction = m_utils.externalCodeFunction(); define(_memberAccess) << - m_utils.externalCodeFunction() << + externalCodeFunction << "(" << expressionAsType(_memberAccess.expression(), *TypeProvider::address()) << ")\n"; + } else if (member == "codehash") define(_memberAccess) << "extcodehash(" << @@ -1946,7 +1943,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) assignInternalFunctionIDIfNotCalledDirectly(_memberAccess, resolvedFunctionDef); } else if (auto const* variable = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) - handleVariableReference(*variable, _memberAccess); + handleVariableReference(*variable, _memberAccess); else if (memberFunctionType) { switch (memberFunctionType->kind()) @@ -2149,8 +2146,9 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess) } case DataLocation::CallData: { + string indexAccessFunction = m_utils.calldataArrayIndexAccessFunction(arrayType); string const indexAccessFunctionCall = - m_utils.calldataArrayIndexAccessFunction(arrayType) + + indexAccessFunction + "(" + IRVariable(_indexAccess.baseExpression()).commaSeparatedList() + ", " + @@ -2867,13 +2865,16 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable ")\n"; } else if (auto const* literalType = dynamic_cast(&_value.type())) + { + string writeUInt = m_utils.writeToMemoryFunction(*TypeProvider::uint256()); appendCode() << - m_utils.writeToMemoryFunction(*TypeProvider::uint256()) << + writeUInt << "(" << _memory.address << ", " << m_utils.copyLiteralToMemoryFunction(literalType->value()) + "()" << ")\n"; + } else { solAssert(_lvalue.type.sizeOnStack() == 1, ""); @@ -2949,11 +2950,14 @@ IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue) solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1, ""); solAssert(_lvalue.type == *_immutable.variable->type(), ""); if (m_context.executionContext() == IRGenerationContext::ExecutionContext::Creation) + { + string readFunction = m_utils.readFromMemory(*_immutable.variable->type()); define(result) << - m_utils.readFromMemory(*_immutable.variable->type()) << + readFunction << "(" << to_string(m_context.immutableMemoryOffset(*_immutable.variable)) << ")\n"; + } else define(result) << "loadimmutable(\"" << to_string(_immutable.variable->id()) << "\")\n"; }, From 59faffcd5f3436342622b18f2b3cff177bd068fe Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 8 Sep 2021 12:18:42 +0200 Subject: [PATCH 040/232] Changelog entry. --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index fc61a1b19..bdd90663f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -15,6 +15,7 @@ Compiler Features: Bugfixes: + * Code Generator: Use stable source order for ABI functions. * Opcode Optimizer: Prevent the optimizer from running multiple times to avoid potential bytecode differences for referenced code. * Name Resolver: Fix that when importing an aliased symbol using ``import {AliasedName} from "a.sol"`` it would use the original name of the symbol and not the aliased one. * SMTChecker: Fix false negative caused by ``push`` on storage array references returned by internal functions. From c499f27a636c7eef50b0b7bb25e03ad72e044e32 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 8 Sep 2021 13:50:36 +0200 Subject: [PATCH 041/232] Change RematCandidateSelector to not depend on variable name sorting. --- libyul/optimiser/StackCompressor.cpp | 80 +++++++++++-------- .../yulOptimizerTests/fullSuite/aztec.yul | 22 ++--- 2 files changed, 58 insertions(+), 44 deletions(-) diff --git a/libyul/optimiser/StackCompressor.cpp b/libyul/optimiser/StackCompressor.cpp index 5e9202530..a57d9738b 100644 --- a/libyul/optimiser/StackCompressor.cpp +++ b/libyul/optimiser/StackCompressor.cpp @@ -31,6 +31,8 @@ #include +#include + using namespace std; using namespace solidity; using namespace solidity::yul; @@ -47,16 +49,19 @@ class RematCandidateSelector: public DataFlowAnalyzer public: explicit RematCandidateSelector(Dialect const& _dialect): DataFlowAnalyzer(_dialect) {} - /// @returns a set of tuples of rematerialisation costs, variable to rematerialise - /// and variables that occur in its expression. - /// Note that this set is sorted by cost. - set>> candidates() + /// @returns a map from rematerialisation costs to a vector of variables to rematerialise + /// and variables that occur in their expression. + /// While the map is sorted by cost, the contained vectors are sorted by the order of occurrence. + map>>> candidates() { - set>> cand; - for (auto const& codeCost: m_expressionCodeCost) + map>>> cand; + for (auto const& candidate: m_candidates) { - size_t numRef = m_numReferences[codeCost.first]; - cand.emplace(make_tuple(codeCost.second * numRef, codeCost.first, m_references[codeCost.first])); + if (size_t const* cost = util::valueOrNullptr(m_expressionCodeCost, candidate)) + { + size_t numRef = m_numReferences[candidate]; + cand[*cost * numRef].emplace_back(candidate, m_references[candidate]); + } } return cand; } @@ -69,7 +74,11 @@ public: { YulString varName = _varDecl.variables.front().name; if (m_value.count(varName)) + { + yulAssert(!m_expressionCodeCost.count(varName), ""); + m_candidates.emplace_back(varName); m_expressionCodeCost[varName] = CodeCost::codeCost(m_dialect, *m_value[varName].value); + } } } @@ -105,12 +114,40 @@ public: m_expressionCodeCost.erase(_variable); } + /// All candidate variables in order of occurrence. + vector m_candidates; /// Candidate variables and the code cost of their value. map m_expressionCodeCost; /// Number of references to each candidate variable. map m_numReferences; }; +/// Selects at most @a _numVariables among @a _candidates. +set chooseVarsToEliminate( + map>>> const& _candidates, + size_t _numVariables +) +{ + set varsToEliminate; + for (auto&& [cost, candidates]: _candidates) + for (auto&& [candidate, references]: candidates) + { + if (varsToEliminate.size() >= _numVariables) + return varsToEliminate; + // If a variable we would like to eliminate references another one + // we already selected for elimination, then stop selecting + // candidates. If we would add that variable, then the cost calculation + // for the previous variable would be off. Furthermore, we + // do not skip the variable because it would be better to properly re-compute + // the costs of all other variables instead. + for (YulString const& referencedVar: references) + if (varsToEliminate.count(referencedVar)) + return varsToEliminate; + varsToEliminate.insert(candidate); + } + return varsToEliminate; +} + template void eliminateVariables( Dialect const& _dialect, @@ -121,32 +158,7 @@ void eliminateVariables( { RematCandidateSelector selector{_dialect}; selector(_node); - - // Select at most _numVariables - set varsToEliminate; - for (auto const& costs: selector.candidates()) - { - if (varsToEliminate.size() >= _numVariables) - break; - // If a variable we would like to eliminate references another one - // we already selected for elimination, then stop selecting - // candidates. If we would add that variable, then the cost calculation - // for the previous variable would be off. Furthermore, we - // do not skip the variable because it would be better to properly re-compute - // the costs of all other variables instead. - bool referencesVarToEliminate = false; - for (YulString const& referencedVar: get<2>(costs)) - if (varsToEliminate.count(referencedVar)) - { - referencesVarToEliminate = true; - break; - } - if (referencesVarToEliminate) - break; - varsToEliminate.insert(get<1>(costs)); - } - - Rematerialiser::run(_dialect, _node, std::move(varsToEliminate)); + Rematerialiser::run(_dialect, _node, chooseVarsToEliminate(selector.candidates(), _numVariables)); UnusedPruner::runUntilStabilised(_dialect, _node, _allowMSizeOptimization); } diff --git a/test/libyul/yulOptimizerTests/fullSuite/aztec.yul b/test/libyul/yulOptimizerTests/fullSuite/aztec.yul index 68640c7ca..ae1ca7848 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/aztec.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/aztec.yul @@ -284,15 +284,17 @@ // let _5 := 0x40 // calldatacopy(0xe0, add(_3, 164), _5) // calldatacopy(0x20, add(_3, 100), _5) -// mstore(0x120, sub(_2, c)) -// mstore(0x60, k) +// let _6 := 0x120 +// mstore(_6, sub(_2, c)) +// let _7 := 0x60 +// mstore(_7, k) // mstore(0xc0, a) -// let result := call(gas(), 7, 0, 0xe0, 0x60, 0x1a0, _5) -// let result_1 := and(result, call(gas(), 7, 0, 0x20, 0x60, 0x120, _5)) -// let _6 := 0x160 -// let result_2 := and(result_1, call(gas(), 7, 0, 0x80, 0x60, _6, _5)) -// let result_3 := and(result_2, call(gas(), 6, 0, 0x120, 0x80, _6, _5)) -// result := and(result_3, call(gas(), 6, 0, _6, 0x80, b, _5)) +// let result := call(gas(), 7, 0, 0xe0, _7, 0x1a0, _5) +// let result_1 := and(result, call(gas(), 7, 0, 0x20, _7, _6, _5)) +// let _8 := 0x160 +// let result_2 := and(result_1, call(gas(), 7, 0, 0x80, _7, _8, _5)) +// let result_3 := and(result_2, call(gas(), 6, 0, _6, 0x80, _8, _5)) +// result := and(result_3, call(gas(), 6, 0, _8, 0x80, b, _5)) // if eq(i, m) // { // mstore(0x260, mload(0x20)) @@ -302,8 +304,8 @@ // } // if gt(i, m) // { -// mstore(0x60, c) -// let result_4 := and(result, call(gas(), 7, 0, 0x20, 0x60, 0x220, _5)) +// mstore(_7, c) +// let result_4 := and(result, call(gas(), 7, 0, 0x20, _7, 0x220, _5)) // let result_5 := and(result_4, call(gas(), 6, 0, 0x220, 0x80, 0x260, _5)) // result := and(result_5, call(gas(), 6, 0, 0x1a0, 0x80, 0x1e0, _5)) // } From 54484e9795f1bd5c5916b25ee84b812f5d5b2072 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 16 Aug 2021 14:28:15 +0200 Subject: [PATCH 042/232] Implemented codegen for UserDefinedValueType --- libsolidity/codegen/CompilerUtils.cpp | 27 +++++++++++++++ libsolidity/codegen/ExpressionCompiler.cpp | 33 +++++++++++++++++++ libsolidity/codegen/YulUtilFunctions.cpp | 14 ++++++++ .../codegen/ir/IRGeneratorForStatements.cpp | 24 ++++++++++++++ 4 files changed, 98 insertions(+) diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 9ae1741dd..61eed4abd 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -772,6 +772,33 @@ void CompilerUtils::convertType( Type::Category stackTypeCategory = _typeOnStack.category(); Type::Category targetTypeCategory = _targetType.category(); + if (stackTypeCategory == Type::Category::UserDefinedValueType) + { + solAssert(_cleanupNeeded, ""); + auto& userDefined = dynamic_cast(_typeOnStack); + solAssert(_typeOnStack == _targetType || _targetType == userDefined.underlyingType(), ""); + return convertType( + userDefined.underlyingType(), + _targetType, + _cleanupNeeded, + _chopSignBits, + _asPartOfArgumentDecoding + ); + } + if (targetTypeCategory == Type::Category::UserDefinedValueType) + { + solAssert(_cleanupNeeded, ""); + auto& userDefined = dynamic_cast(_targetType); + solAssert(_typeOnStack.isImplicitlyConvertibleTo(userDefined.underlyingType()), ""); + return convertType( + _typeOnStack, + userDefined.underlyingType(), + _cleanupNeeded, + _chopSignBits, + _asPartOfArgumentDecoding + ); + } + if (auto contrType = dynamic_cast(&_typeOnStack)) solAssert(!contrType->isSuper(), "Cannot convert magic variable \"super\""); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 210504868..8f364df1b 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -957,6 +957,35 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) ); break; } + case FunctionType::Kind::Wrap: + case FunctionType::Kind::Unwrap: + { + solAssert(arguments.size() == 1, ""); + Type const* argumentType = arguments.at(0)->annotation().type; + Type const* functionCallType = _functionCall.annotation().type; + solAssert(argumentType, ""); + solAssert(functionCallType, ""); + FunctionType::Kind kind = functionType->kind(); + if (kind == FunctionType::Kind::Wrap) + { + solAssert( + argumentType->isImplicitlyConvertibleTo( + dynamic_cast(*functionCallType).underlyingType() + ), + "" + ); + solAssert(argumentType->isImplicitlyConvertibleTo(*function.parameterTypes()[0]), ""); + } + else + solAssert( + dynamic_cast(*argumentType) == + dynamic_cast(*function.parameterTypes()[0]), + "" + ); + + acceptAndConvert(*arguments[0], *function.parameterTypes()[0]); + break; + } case FunctionType::Kind::BlockHash: { acceptAndConvert(*arguments[0], *function.parameterTypes()[0], true); @@ -2157,6 +2186,10 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier) { // no-op } + else if (dynamic_cast(declaration)) + { + // no-op + } else if (dynamic_cast(declaration)) { // no-op diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index f61a76d32..bb56c43df 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -3168,6 +3168,16 @@ string YulUtilFunctions::allocateAndInitializeMemoryStructFunction(StructType co string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) { + if (_from.category() == Type::Category::UserDefinedValueType) + { + solAssert(_from == _to || _to == dynamic_cast(_from).underlyingType(), ""); + return conversionFunction(dynamic_cast(_from).underlyingType(), _to); + } + if (_to.category() == Type::Category::UserDefinedValueType) + { + solAssert(_from == _to || _from.isImplicitlyConvertibleTo(dynamic_cast(_to).underlyingType()), ""); + return conversionFunction(_from, dynamic_cast(_to).underlyingType()); + } if (_from.category() == Type::Category::Function) { solAssert(_to.category() == Type::Category::Function, ""); @@ -3696,6 +3706,9 @@ string YulUtilFunctions::arrayConversionFunction(ArrayType const& _from, ArrayTy string YulUtilFunctions::cleanupFunction(Type const& _type) { + if (auto userDefinedValueType = dynamic_cast(&_type)) + return cleanupFunction(userDefinedValueType->underlyingType()); + string functionName = string("cleanup_") + _type.identifier(); return m_functionCollector.createFunction(functionName, [&]() { Whiskers templ(R"( @@ -3816,6 +3829,7 @@ string YulUtilFunctions::validatorFunction(Type const& _type, bool _revertOnFail case Type::Category::Mapping: case Type::Category::FixedBytes: case Type::Category::Contract: + case Type::Category::UserDefinedValueType: { templ("condition", "eq(value, " + cleanupFunction(_type) + "(value))"); break; diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 8f281a10e..0318b6226 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1051,6 +1051,24 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) ); break; } + case FunctionType::Kind::Wrap: + case FunctionType::Kind::Unwrap: + { + solAssert(arguments.size() == 1, ""); + FunctionType::Kind kind = functionType->kind(); + if (kind == FunctionType::Kind::Wrap) + solAssert( + type(*arguments.at(0)).isImplicitlyConvertibleTo( + dynamic_cast(type(_functionCall)).underlyingType() + ), + "" + ); + else + solAssert(type(*arguments.at(0)).category() == Type::Category::UserDefinedValueType, ""); + + define(_functionCall, *arguments.at(0)); + break; + } case FunctionType::Kind::Assert: case FunctionType::Kind::Require: { @@ -2004,6 +2022,8 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) } 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", ""); else if (auto const* arrayType = dynamic_cast(&actualType)) solAssert(arrayType->isByteArray() && member == "concat", ""); else @@ -2314,6 +2334,10 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier) { // no-op } + else if (dynamic_cast(declaration)) + { + // no-op + } else { solAssert(false, "Identifier type not expected in expression context."); From 229f50eef1aaf49f358cbd6b5ee8adc64988f4f7 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Tue, 7 Sep 2021 18:43:04 +0200 Subject: [PATCH 043/232] Syntax checks for user defined value types --- .../explicit_conversion_self.sol | 4 ++++ .../explicit_conversions_err.sol | 24 +++++++++++++++++++ .../explicit_conversions_wrap.sol | 8 +++++++ .../explicit_literal_conversion_wrap.sol | 9 +++++++ .../forward_reference_err.sol | 4 ++++ .../implicit_conversion.sol | 14 +++++++++++ .../implicit_conversion_err.sol | 22 +++++++++++++++++ .../userDefinedValueType/in_parenthesis.sol | 7 ++++++ .../overload_clash_err.sol | 19 +++++++++++++++ .../wrap_unwrap_assign_err.sol | 8 +++++++ 10 files changed, 119 insertions(+) create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversion_self.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversions_err.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversions_wrap.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/explicit_literal_conversion_wrap.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/forward_reference_err.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/implicit_conversion.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/implicit_conversion_err.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/in_parenthesis.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/overload_clash_err.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_assign_err.sol diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversion_self.sol b/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversion_self.sol new file mode 100644 index 000000000..c2fdc84e4 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversion_self.sol @@ -0,0 +1,4 @@ +type MyInt is int; +function f(MyInt a) pure returns (MyInt b) { + b = MyInt(a); +} diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversions_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversions_err.sol new file mode 100644 index 000000000..876a3e282 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversions_err.sol @@ -0,0 +1,24 @@ +type MyUInt is uint; +type MyAddress is address; +type AnotherUInt is uint; + +function f() pure { + MyUInt(-1); + MyAddress(-1); + MyUInt(5); + MyAddress(address(5)); + + AnotherUInt(MyUInt.wrap(5)); + MyUInt(AnotherUInt.wrap(10)); + AnotherUInt.unwrap(MyUInt.wrap(5)); + MyUInt.unwrap(AnotherUInt.wrap(10)); +} +// ---- +// TypeError 9640: (99-109): Explicit type conversion not allowed from "int_const -1" to "user defined type MyUInt". +// TypeError 9640: (115-128): Explicit type conversion not allowed from "int_const -1" to "user defined type MyAddress". +// TypeError 9640: (134-143): Explicit type conversion not allowed from "int_const 5" to "user defined type MyUInt". +// TypeError 9640: (149-170): Explicit type conversion not allowed from "address" to "user defined type MyAddress". +// TypeError 9640: (177-204): Explicit type conversion not allowed from "user defined type MyUInt" to "user defined type AnotherUInt". +// TypeError 9640: (210-238): Explicit type conversion not allowed from "user defined type AnotherUInt" to "user defined type MyUInt". +// TypeError 9553: (263-277): Invalid type for argument in function call. Invalid implicit conversion from user defined type MyUInt to user defined type AnotherUInt requested. +// TypeError 9553: (298-318): Invalid type for argument in function call. Invalid implicit conversion from user defined type AnotherUInt to user defined type MyUInt requested. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversions_wrap.sol b/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversions_wrap.sol new file mode 100644 index 000000000..fa343572d --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversions_wrap.sol @@ -0,0 +1,8 @@ +type MyUint is uint; +type MyAddress is address; + +function f() pure { + MyUint.wrap(5); + MyAddress.wrap(address(5)); +} +// ---- diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/explicit_literal_conversion_wrap.sol b/test/libsolidity/syntaxTests/userDefinedValueType/explicit_literal_conversion_wrap.sol new file mode 100644 index 000000000..7bca6f27b --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/explicit_literal_conversion_wrap.sol @@ -0,0 +1,9 @@ +type MyAddress is address; +type MyUInt8 is uint8; + +function f() pure { + MyAddress.wrap(address(5)); + MyUInt8.wrap(5); + MyUInt8.wrap(50); +} +// ---- diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/forward_reference_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/forward_reference_err.sol new file mode 100644 index 000000000..9ea93cb09 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/forward_reference_err.sol @@ -0,0 +1,4 @@ +function f(MyIntB x) pure {} +type MyIntB is MyIntB; +// ---- +// TypeError 8657: (44-50): The underlying type for a user defined value type has to be an elementary value type. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/implicit_conversion.sol b/test/libsolidity/syntaxTests/userDefinedValueType/implicit_conversion.sol new file mode 100644 index 000000000..8837db7d1 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/implicit_conversion.sol @@ -0,0 +1,14 @@ +type MyInt is uint; +type MyAddress is address; +function f() pure { + MyInt a; + MyInt b = a; + MyAddress c; + MyAddress d = c; + b; + d; +} + +function g(MyInt a) pure returns (MyInt) { + return a; +} diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/implicit_conversion_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/implicit_conversion_err.sol new file mode 100644 index 000000000..ad115051e --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/implicit_conversion_err.sol @@ -0,0 +1,22 @@ +type MyInt is int; +function f(int a) pure returns (int) { + MyInt b = a; + + int c = b; + + address d = b; + + MyInt e = d; + + uint x = 0; + MyInt y = MyInt(x); + + return e; +} +// ---- +// TypeError 9574: (62-73): Type int256 is not implicitly convertible to expected type user defined type MyInt. +// TypeError 9574: (80-89): Type user defined type MyInt is not implicitly convertible to expected type int256. +// TypeError 9574: (96-109): Type user defined type MyInt is not implicitly convertible to expected type address. +// TypeError 9574: (116-127): Type address is not implicitly convertible to expected type user defined type MyInt. +// TypeError 9640: (160-168): Explicit type conversion not allowed from "uint256" to "user defined type MyInt". +// TypeError 6359: (182-183): Return argument type user defined type MyInt is not implicitly convertible to expected type (type of first return variable) int256. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/in_parenthesis.sol b/test/libsolidity/syntaxTests/userDefinedValueType/in_parenthesis.sol new file mode 100644 index 000000000..403ceaa7a --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/in_parenthesis.sol @@ -0,0 +1,7 @@ +type MyInt is int; +function f() pure { + (MyInt).wrap; + (MyInt).wrap(5); + (MyInt).unwrap; + (MyInt).unwrap(MyInt.wrap(5)); +} diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/overload_clash_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/overload_clash_err.sol new file mode 100644 index 000000000..a84930433 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/overload_clash_err.sol @@ -0,0 +1,19 @@ +type MyAddress is address; +interface I {} +contract C { + function f(MyAddress a) external { + } + function f(address a) external { + } +} +contract D { + function g(MyAddress a) external { + } +} +contract E is D { + function g(I a) external { + } +} +// ---- +// TypeError 9914: (104-142): Function overload clash during conversion to external types for arguments. +// TypeError 9914: (162-202): Function overload clash during conversion to external types for arguments. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_assign_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_assign_err.sol new file mode 100644 index 000000000..67ce77331 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_assign_err.sol @@ -0,0 +1,8 @@ +type MyInt is int; +function test() pure { + function (MyInt) returns (int) f = MyInt.unwrap; + function (int) returns (MyInt) g = MyInt.wrap; +} +// ---- +// TypeError 9574: (46-93): Type function (user defined type MyInt) pure returns (int256) is not implicitly convertible to expected type function (user defined type MyInt) returns (int256). Special functions can not be converted to function types. +// TypeError 9574: (99-144): Type function (int256) pure returns (user defined type MyInt) is not implicitly convertible to expected type function (int256) returns (user defined type MyInt). Special functions can not be converted to function types. From 5f393d1694d71eab7b741ee907ae1bb83288d215 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Tue, 17 Aug 2021 11:29:45 +0200 Subject: [PATCH 044/232] Semantic tests for User Defined Value types --- .../userDefinedValueType/calldata.sol | 65 ++++++++ .../userDefinedValueType/cleanup.sol | 44 ++++++ .../cleanup_abicoderv1.sol | 44 ++++++ .../userDefinedValueType/conversion.sol | 57 +++++++ .../conversion_abicoderv1.sol | 57 +++++++ .../userDefinedValueType/erc20.sol | 147 ++++++++++++++++++ .../userDefinedValueType/fixedpoint.sol | 42 +++++ .../userDefinedValueType/ownable.sol | 32 ++++ .../userDefinedValueType/parameter.sol | 42 +++++ .../userDefinedValueType/simple.sol | 14 ++ .../userDefinedValueType/wrap_unwrap.sol | 11 ++ 11 files changed, 555 insertions(+) create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/calldata.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/cleanup.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/cleanup_abicoderv1.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/conversion.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/conversion_abicoderv1.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/erc20.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/fixedpoint.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/ownable.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/parameter.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/simple.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/wrap_unwrap.sol diff --git a/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol b/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol new file mode 100644 index 000000000..68164f180 --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol @@ -0,0 +1,65 @@ +pragma abicoder v2; +type MyAddress is address; + +contract C { + MyAddress[] public addresses; + function f(MyAddress[] calldata _addresses) external { + for (uint i = 0; i < _addresses.length; i++) { + MyAddress.unwrap(_addresses[i]).call(""); + } + addresses = _addresses; + } + function g(MyAddress[] memory _addresses) external { + for (uint i = 0; i < _addresses.length; i++) { + MyAddress.unwrap(_addresses[i]).call(""); + } + addresses = _addresses; + } + function test_f() external returns (bool) { + clean(); + MyAddress[] memory test = new MyAddress[](3); + test[0] = MyAddress.wrap(address(21)); + test[1] = MyAddress.wrap(address(22)); + test[2] = MyAddress.wrap(address(23)); + this.f(test); + test_equality(test); + return true; + } + function test_g() external returns (bool) { + clean(); + MyAddress[] memory test = new MyAddress[](5); + test[0] = MyAddress.wrap(address(24)); + test[1] = MyAddress.wrap(address(25)); + test[2] = MyAddress.wrap(address(26)); + test[3] = MyAddress.wrap(address(27)); + test[4] = MyAddress.wrap(address(28)); + this.g(test); + test_equality(test); + return true; + } + function clean() internal { + delete addresses; + } + function test_equality(MyAddress[] memory _addresses) internal view { + require (_addresses.length == addresses.length); + for (uint i = 0; i < _addresses.length; i++) { + require(MyAddress.unwrap(_addresses[i]) == MyAddress.unwrap(addresses[i])); + } + } +} +// ==== +// compileViaYul: also +// ---- +// test_f() -> true +// gas irOptimized: 122655 +// gas legacy: 125037 +// gas legacyOptimized: 122605 +// test_g() -> true +// gas irOptimized: 95940 +// gas legacy: 100656 +// gas legacyOptimized: 96057 +// addresses(uint256): 0 -> 0x18 +// addresses(uint256): 1 -> 0x19 +// addresses(uint256): 3 -> 0x1b +// addresses(uint256): 4 -> 0x1c +// addresses(uint256): 5 -> FAILURE diff --git a/test/libsolidity/semanticTests/userDefinedValueType/cleanup.sol b/test/libsolidity/semanticTests/userDefinedValueType/cleanup.sol new file mode 100644 index 000000000..771e0f80c --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/cleanup.sol @@ -0,0 +1,44 @@ +pragma abicoder v2; +type MyUInt8 is uint8; + +// Note that this wraps from a uint256 +function wrap(uint x) pure returns (MyUInt8 y) { assembly { y := x } } +function unwrap(MyUInt8 x) pure returns (uint8 y) { assembly { y := x } } + +contract C { + uint8 a; + MyUInt8 b; + uint8 c; + function ret() external returns(MyUInt8) { + return wrap(0x1ff); + } + function f(MyUInt8 x) external returns(MyUInt8) { + return x; + } + function mem() external returns (MyUInt8[] memory) { + MyUInt8[] memory x = new MyUInt8[](2); + x[0] = wrap(0x1ff); + x[1] = wrap(0xff); + require(unwrap(x[0]) == unwrap(x[1])); + assembly { + mstore(add(x, 0x20), 0x1ff) + } + require(unwrap(x[0]) == unwrap(x[1])); + return x; + } + function stor() external returns (uint8, MyUInt8, uint8) { + a = 1; + c = 2; + b = wrap(0x1ff); + return (a, b, c); + } +} + +// ==== +// compileViaYul: also +// ---- +// ret() -> 0xff +// f(uint8): 0x1ff -> FAILURE +// f(uint8): 0xff -> 0xff +// mem() -> 0x20, 2, 0xff, 0xff +// stor() -> 1, 0xff, 2 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/cleanup_abicoderv1.sol b/test/libsolidity/semanticTests/userDefinedValueType/cleanup_abicoderv1.sol new file mode 100644 index 000000000..f5de5e501 --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/cleanup_abicoderv1.sol @@ -0,0 +1,44 @@ +pragma abicoder v1; +type MyUInt8 is uint8; + +// Note that this wraps from a uint256 +function wrap(uint x) pure returns (MyUInt8 y) { assembly { y := x } } +function unwrap(MyUInt8 x) pure returns (uint8 y) { assembly { y := x } } + +contract C { + uint8 a; + MyUInt8 b; + uint8 c; + function ret() external returns(MyUInt8) { + return wrap(0x1ff); + } + function f(MyUInt8 x) external returns(MyUInt8) { + return x; + } + function mem() external returns (MyUInt8[] memory) { + MyUInt8[] memory x = new MyUInt8[](2); + x[0] = wrap(0x1ff); + x[1] = wrap(0xff); + require(unwrap(x[0]) == unwrap(x[1])); + assembly { + mstore(add(x, 0x20), 0x1ff) + } + require(unwrap(x[0]) == unwrap(x[1])); + return x; + } + function stor() external returns (uint8, MyUInt8, uint8) { + a = 1; + c = 2; + b = wrap(0x1ff); + return (a, b, c); + } +} + +// ==== +// compileViaYul: false +// ---- +// ret() -> 0xff +// f(uint8): 0x1ff -> 0xff +// f(uint8): 0xff -> 0xff +// mem() -> 0x20, 2, 0x01ff, 0xff +// stor() -> 1, 0xff, 2 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/conversion.sol b/test/libsolidity/semanticTests/userDefinedValueType/conversion.sol new file mode 100644 index 000000000..bbf5dcf29 --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/conversion.sol @@ -0,0 +1,57 @@ +pragma abicoder v2; + +type MyUInt8 is uint8; +type MyInt8 is int8; +type MyUInt16 is uint16; + +contract C { + function f(uint a) external returns(MyUInt8) { + return MyUInt8.wrap(uint8(a)); + } + function g(uint a) external returns(MyInt8) { + return MyInt8.wrap(int8(int(a))); + } + function h(MyUInt8 a) external returns (MyInt8) { + return MyInt8.wrap(int8(MyUInt8.unwrap(a))); + } + function i(MyUInt8 a) external returns(MyUInt16) { + return MyUInt16.wrap(MyUInt8.unwrap(a)); + } + function j(MyUInt8 a) external returns (uint) { + return MyUInt8.unwrap(a); + } + function k(MyUInt8 a) external returns (MyUInt16) { + return MyUInt16.wrap(MyUInt8.unwrap(a)); + } + function m(MyUInt16 a) external returns (MyUInt8) { + return MyUInt8.wrap(uint8(MyUInt16.unwrap(a))); + } +} + +// ==== +// compileViaYul: also +// ---- +// f(uint256): 1 -> 1 +// f(uint256): 2 -> 2 +// f(uint256): 257 -> 1 +// g(uint256): 1 -> 1 +// g(uint256): 2 -> 2 +// g(uint256): 255 -> -1 +// g(uint256): 257 -> 1 +// h(uint8): 1 -> 1 +// h(uint8): 2 -> 2 +// h(uint8): 255 -> -1 +// h(uint8): 257 -> FAILURE +// i(uint8): 250 -> 250 +// j(uint8): 1 -> 1 +// j(uint8): 2 -> 2 +// j(uint8): 255 -> 0xff +// j(uint8): 257 -> FAILURE +// k(uint8): 1 -> 1 +// k(uint8): 2 -> 2 +// k(uint8): 255 -> 0xff +// k(uint8): 257 -> FAILURE +// m(uint16): 1 -> 1 +// m(uint16): 2 -> 2 +// m(uint16): 255 -> 0xff +// m(uint16): 257 -> 1 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/conversion_abicoderv1.sol b/test/libsolidity/semanticTests/userDefinedValueType/conversion_abicoderv1.sol new file mode 100644 index 000000000..af91aab0c --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/conversion_abicoderv1.sol @@ -0,0 +1,57 @@ +pragma abicoder v1; + +type MyUInt8 is uint8; +type MyInt8 is int8; +type MyUInt16 is uint16; + +contract C { + function f(uint a) external returns(MyUInt8) { + return MyUInt8.wrap(uint8(a)); + } + function g(uint a) external returns(MyInt8) { + return MyInt8.wrap(int8(int(a))); + } + function h(MyUInt8 a) external returns (MyInt8) { + return MyInt8.wrap(int8(MyUInt8.unwrap(a))); + } + function i(MyUInt8 a) external returns(MyUInt16) { + return MyUInt16.wrap(MyUInt8.unwrap(a)); + } + function j(MyUInt8 a) external returns (uint) { + return MyUInt8.unwrap(a); + } + function k(MyUInt8 a) external returns (MyUInt16) { + return MyUInt16.wrap(MyUInt8.unwrap(a)); + } + function m(MyUInt16 a) external returns (MyUInt8) { + return MyUInt8.wrap(uint8(MyUInt16.unwrap(a))); + } +} + +// ==== +// compileViaYul: false +// ---- +// f(uint256): 1 -> 1 +// f(uint256): 2 -> 2 +// f(uint256): 257 -> 1 +// g(uint256): 1 -> 1 +// g(uint256): 2 -> 2 +// g(uint256): 255 -> -1 +// g(uint256): 257 -> 1 +// h(uint8): 1 -> 1 +// h(uint8): 2 -> 2 +// h(uint8): 255 -> -1 +// h(uint8): 257 -> 1 +// i(uint8): 250 -> 250 +// j(uint8): 1 -> 1 +// j(uint8): 2 -> 2 +// j(uint8): 255 -> 0xff +// j(uint8): 257 -> 1 +// k(uint8): 1 -> 1 +// k(uint8): 2 -> 2 +// k(uint8): 255 -> 0xff +// k(uint8): 257 -> 1 +// m(uint16): 1 -> 1 +// m(uint16): 2 -> 2 +// m(uint16): 255 -> 0xff +// m(uint16): 257 -> 1 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol b/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol new file mode 100644 index 000000000..57826ebe4 --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol @@ -0,0 +1,147 @@ +pragma abicoder v2; +// A rewrite of the test/libsolidity/semanticTests/various/erc20.sol, but using user defined value +// types. + +// User defined type name. Indicating a type with 18 decimals. +type UFixed18 is uint256; + +library FixedMath +{ + function add(UFixed18 a, UFixed18 b) internal pure returns (UFixed18 c) { + return UFixed18.wrap(UFixed18.unwrap(a) + UFixed18.unwrap(b)); + } + function sub(UFixed18 a, UFixed18 b) internal pure returns (UFixed18 c) { + return UFixed18.wrap(UFixed18.unwrap(a) - UFixed18.unwrap(b)); + } +} + +contract ERC20 { + using FixedMath for UFixed18; + + event Transfer(address indexed from, address indexed to, UFixed18 value); + event Approval(address indexed owner, address indexed spender, UFixed18 value); + + mapping (address => UFixed18) private _balances; + mapping (address => mapping (address => UFixed18)) private _allowances; + UFixed18 private _totalSupply; + + constructor() { + _mint(msg.sender, UFixed18.wrap(20)); + } + + function totalSupply() public view returns (UFixed18) { + return _totalSupply; + } + + function balanceOf(address owner) public view returns (UFixed18) { + return _balances[owner]; + } + + function allowance(address owner, address spender) public view returns (UFixed18) { + return _allowances[owner][spender]; + } + + function transfer(address to, UFixed18 value) public returns (bool) { + _transfer(msg.sender, to, value); + return true; + } + + function approve(address spender, UFixed18 value) public returns (bool) { + _approve(msg.sender, spender, value); + return true; + } + + function transferFrom(address from, address to, UFixed18 value) public returns (bool) { + _transfer(from, to, value); + // The subtraction here will revert on overflow. + _approve(from, msg.sender, _allowances[from][msg.sender].sub(value)); + return true; + } + + function increaseAllowance(address spender, UFixed18 addedValue) public returns (bool) { + // The addition here will revert on overflow. + _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue)); + return true; + } + + function decreaseAllowance(address spender, UFixed18 subtractedValue) public returns (bool) { + // The subtraction here will revert on overflow. + _approve(msg.sender, spender, _allowances[msg.sender][spender].sub(subtractedValue)); + return true; + } + + function _transfer(address from, address to, UFixed18 value) internal { + require(to != address(0), "ERC20: transfer to the zero address"); + + // The subtraction and addition here will revert on overflow. + _balances[from] = _balances[from].sub(value); + _balances[to] = _balances[to].add(value); + emit Transfer(from, to, value); + } + + function _mint(address account, UFixed18 value) internal { + require(account != address(0), "ERC20: mint to the zero address"); + + // The additions here will revert on overflow. + _totalSupply = _totalSupply.add(value); + _balances[account] = _balances[account].add(value); + emit Transfer(address(0), account, value); + } + + function _burn(address account, UFixed18 value) internal { + require(account != address(0), "ERC20: burn from the zero address"); + + // The subtractions here will revert on overflow. + _totalSupply = _totalSupply.sub(value); + _balances[account] = _balances[account].sub(value); + emit Transfer(account, address(0), value); + } + + function _approve(address owner, address spender, UFixed18 value) internal { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = value; + emit Approval(owner, spender, value); + } + + function _burnFrom(address account, UFixed18 value) internal { + _burn(account, value); + _approve(account, msg.sender, _allowances[account][msg.sender].sub(value)); + } +} +// ==== +// compileViaYul: also +// ---- +// constructor() +// ~ emit Transfer(address,address,uint256): #0x00, #0x1212121212121212121212121212120000000012, 0x14 +// gas irOptimized: 460447 +// gas legacy: 861547 +// gas legacyOptimized: 420959 +// totalSupply() -> 20 +// gas irOptimized: 23378 +// gas legacy: 23653 +// gas legacyOptimized: 23368 +// transfer(address,uint256): 2, 5 -> true +// ~ emit Transfer(address,address,uint256): #0x1212121212121212121212121212120000000012, #0x02, 0x05 +// gas irOptimized: 48514 +// gas legacy: 49572 +// gas legacyOptimized: 48575 +// decreaseAllowance(address,uint256): 2, 0 -> true +// ~ emit Approval(address,address,uint256): #0x1212121212121212121212121212120000000012, #0x02, 0x00 +// gas irOptimized: 26316 +// gas legacy: 27204 +// gas legacyOptimized: 26317 +// decreaseAllowance(address,uint256): 2, 1 -> FAILURE, hex"4e487b71", 0x11 +// gas irOptimized: 24040 +// gas legacy: 24506 +// gas legacyOptimized: 24077 +// transfer(address,uint256): 2, 14 -> true +// ~ emit Transfer(address,address,uint256): #0x1212121212121212121212121212120000000012, #0x02, 0x0e +// gas irOptimized: 28614 +// gas legacy: 29672 +// gas legacyOptimized: 28675 +// transfer(address,uint256): 2, 2 -> FAILURE, hex"4e487b71", 0x11 +// gas irOptimized: 24052 +// gas legacy: 24492 +// gas legacyOptimized: 24074 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/fixedpoint.sol b/test/libsolidity/semanticTests/userDefinedValueType/fixedpoint.sol new file mode 100644 index 000000000..38a27e7be --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/fixedpoint.sol @@ -0,0 +1,42 @@ +// Represent a 18 decimal, 256 bit wide fixed point type using a user defined value type. +type UFixed256x18 is uint256; + +/// A minimal library to do fixed point operations on UFixed256x18. +library FixedMath { + /// Adds two UFixed256x18 numbers. Reverts on overflow, relying on checked arithmetic on + /// uint256. + function add(UFixed256x18 a, UFixed256x18 b) internal returns (UFixed256x18) { + return UFixed256x18.wrap(UFixed256x18.unwrap(a) + UFixed256x18.unwrap(b)); + } + /// Multiplies UFixed256x18 and uint256. Reverts on overflow, relying on checked arithmetic on + /// uint256. + function mul(UFixed256x18 a, uint256 b) internal returns (UFixed256x18) { + return UFixed256x18.wrap(UFixed256x18.unwrap(a) * b); + } + /// Truncates UFixed256x18 to the nearest uint256 number. + function truncate(UFixed256x18 a) internal returns (uint256) { + return UFixed256x18.unwrap(a) / 10**18; + } +} + +contract TestFixedMath { + function add(UFixed256x18 a, UFixed256x18 b) external returns (UFixed256x18) { + return FixedMath.add(a, b); + } + function mul(UFixed256x18 a, uint256 b) external returns (UFixed256x18) { + return FixedMath.mul(a, b); + } + function truncate(UFixed256x18 a) external returns (uint256) { + return FixedMath.truncate(a); + } +} +// ==== +// compileViaYul: also +// ---- +// add(uint256,uint256): 0, 0 -> 0 +// add(uint256,uint256): 25, 45 -> 0x46 +// add(uint256,uint256): 115792089237316195423570985008687907853269984665640564039457584007913129639935, 10 -> FAILURE, hex"4e487b71", 0x11 +// mul(uint256,uint256): 340282366920938463463374607431768211456, 45671926166590716193865151022383844364247891968 -> FAILURE, hex"4e487b71", 0x11 +// mul(uint256,uint256): 340282366920938463463374607431768211456, 20 -> 6805647338418769269267492148635364229120 +// truncate(uint256): 11579208923731619542357098500868790785326998665640564039457584007913129639930 -> 11579208923731619542357098500868790785326998665640564039457 +// truncate(uint256): 115792089237316195423570985008687907853269984665640564039457584007913129639935 -> 115792089237316195423570985008687907853269984665640564039457 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/ownable.sol b/test/libsolidity/semanticTests/userDefinedValueType/ownable.sol new file mode 100644 index 000000000..3f31acaca --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/ownable.sol @@ -0,0 +1,32 @@ +// Implementation of OpenZepplin's +// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol +// using user defined value types. + +contract Ownable { + type Owner is address; + Owner public owner = Owner.wrap(msg.sender); + error OnlyOwner(); + modifier onlyOwner() { + if (Owner.unwrap(owner) != msg.sender) + revert OnlyOwner(); + + _; + } + event OwnershipTransferred(Owner indexed previousOwner, Owner indexed newOwner); + function setOwner(Owner newOwner) onlyOwner external { + emit OwnershipTransferred({previousOwner: owner, newOwner: newOwner}); + owner = newOwner; + } + function renounceOwnership() onlyOwner external { + owner = Owner.wrap(address(0)); + } +} +// ==== +// compileViaYul: also +// ---- +// owner() -> 0x1212121212121212121212121212120000000012 +// setOwner(address): 0x1212121212121212121212121212120000000012 -> +// ~ emit OwnershipTransferred(address,address): #0x1212121212121212121212121212120000000012, #0x1212121212121212121212121212120000000012 +// renounceOwnership() -> +// owner() -> 0 +// setOwner(address): 0x1212121212121212121212121212120000000012 -> FAILURE, hex"5fc483c5" diff --git a/test/libsolidity/semanticTests/userDefinedValueType/parameter.sol b/test/libsolidity/semanticTests/userDefinedValueType/parameter.sol new file mode 100644 index 000000000..56cebc923 --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/parameter.sol @@ -0,0 +1,42 @@ +pragma abicoder v2; + +type MyAddress is address; +contract C { + function id(MyAddress a) external returns (MyAddress b) { + b = a; + } + + function unwrap_assembly(MyAddress a) external returns (address b) { + assembly { b := a } + } + + function wrap_assembly(address a) external returns (MyAddress b) { + assembly { b := a } + } + + function unwrap(MyAddress a) external returns (address b) { + b = MyAddress.unwrap(a); + } + function wrap(address a) external returns (MyAddress b) { + b = MyAddress.wrap(a); + } + +} +// ==== +// compileViaYul: also +// ---- +// id(address): 5 -> 5 +// id(address): 0xffffffffffffffffffffffffffffffffffffffff -> 0xffffffffffffffffffffffffffffffffffffffff +// id(address): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> FAILURE +// unwrap(address): 5 -> 5 +// unwrap(address): 0xffffffffffffffffffffffffffffffffffffffff -> 0xffffffffffffffffffffffffffffffffffffffff +// unwrap(address): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> FAILURE +// wrap(address): 5 -> 5 +// wrap(address): 0xffffffffffffffffffffffffffffffffffffffff -> 0xffffffffffffffffffffffffffffffffffffffff +// wrap(address): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> FAILURE +// unwrap_assembly(address): 5 -> 5 +// unwrap_assembly(address): 0xffffffffffffffffffffffffffffffffffffffff -> 0xffffffffffffffffffffffffffffffffffffffff +// unwrap_assembly(address): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> FAILURE +// wrap_assembly(address): 5 -> 5 +// wrap_assembly(address): 0xffffffffffffffffffffffffffffffffffffffff -> 0xffffffffffffffffffffffffffffffffffffffff +// wrap_assembly(address): 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -> FAILURE diff --git a/test/libsolidity/semanticTests/userDefinedValueType/simple.sol b/test/libsolidity/semanticTests/userDefinedValueType/simple.sol new file mode 100644 index 000000000..fd5cdd07a --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/simple.sol @@ -0,0 +1,14 @@ +type MyInt is int; +contract C { + function f() external pure returns (MyInt a) { + } + function g() external pure returns (MyInt b, MyInt c) { + b = MyInt.wrap(int(1)); + c = MyInt.wrap(1); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 0 +// g() -> 1, 1 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/wrap_unwrap.sol b/test/libsolidity/semanticTests/userDefinedValueType/wrap_unwrap.sol new file mode 100644 index 000000000..c3b68e7c3 --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/wrap_unwrap.sol @@ -0,0 +1,11 @@ +type MyAddress is address; +contract C { + function f() pure public { + MyAddress.wrap; + MyAddress.unwrap; + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> From d67391531e7a67ad6b51771d20c8b977fc35daee Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Tue, 17 Aug 2021 17:34:23 +0200 Subject: [PATCH 045/232] Implemented ASTJson import export for UserDefinedValueType Also added a test. --- libsolidity/ast/ASTJsonConverter.cpp | 14 + libsolidity/ast/ASTJsonConverter.h | 1 + libsolidity/ast/ASTJsonImporter.cpp | 12 + libsolidity/ast/ASTJsonImporter.h | 1 + .../ABIJson/user_defined_value_type.sol | 173 ++++++++++++ .../ASTJSON/userDefinedValueType.json | 264 ++++++++++++++++++ .../ASTJSON/userDefinedValueType.sol | 12 + .../userDefinedValueType_parseOnly.json | 200 +++++++++++++ 8 files changed, 677 insertions(+) create mode 100644 test/libsolidity/ABIJson/user_defined_value_type.sol create mode 100644 test/libsolidity/ASTJSON/userDefinedValueType.json create mode 100644 test/libsolidity/ASTJSON/userDefinedValueType.sol create mode 100644 test/libsolidity/ASTJSON/userDefinedValueType_parseOnly.json diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index e009bc8cb..f8c284483 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -354,6 +354,20 @@ bool ASTJsonConverter::visit(EnumValue const& _node) return false; } +bool ASTJsonConverter::visit(UserDefinedValueTypeDefinition const& _node) +{ + solAssert(_node.underlyingType(), ""); + std::vector> attributes = { + make_pair("name", _node.name()), + make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), + make_pair("underlyingType", toJson(*_node.underlyingType())) + }; + + setJsonNode(_node, "UserDefinedValueTypeDefinition", std::move(attributes)); + + return false; +} + bool ASTJsonConverter::visit(ParameterList const& _node) { setJsonNode(_node, "ParameterList", { diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index 34903c7a1..56fdb1304 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -81,6 +81,7 @@ public: bool visit(StructDefinition const& _node) override; bool visit(EnumDefinition const& _node) override; bool visit(EnumValue const& _node) override; + bool visit(UserDefinedValueTypeDefinition const& _node) override; bool visit(ParameterList const& _node) override; bool visit(OverrideSpecifier const& _node) override; bool visit(FunctionDefinition const& _node) override; diff --git a/libsolidity/ast/ASTJsonImporter.cpp b/libsolidity/ast/ASTJsonImporter.cpp index 5d7ba1211..dd928cc03 100644 --- a/libsolidity/ast/ASTJsonImporter.cpp +++ b/libsolidity/ast/ASTJsonImporter.cpp @@ -133,6 +133,8 @@ ASTPointer ASTJsonImporter::convertJsonToASTNode(Json::Value const& _js return createEnumDefinition(_json); if (nodeType == "EnumValue") return createEnumValue(_json); + if (nodeType == "UserDefinedValueTypeDefinition") + return createUserDefinedValueTypeDefinition(_json); if (nodeType == "ParameterList") return createParameterList(_json); if (nodeType == "OverrideSpecifier") @@ -387,6 +389,16 @@ ASTPointer ASTJsonImporter::createEnumValue(Json::Value const& _node) ); } +ASTPointer ASTJsonImporter::createUserDefinedValueTypeDefinition(Json::Value const& _node) +{ + return createASTNode( + _node, + memberAsASTString(_node, "name"), + createNameSourceLocation(_node), + convertJsonToASTNode(member(_node, "underlyingType")) + ); +} + ASTPointer ASTJsonImporter::createParameterList(Json::Value const& _node) { std::vector> parameters; diff --git a/libsolidity/ast/ASTJsonImporter.h b/libsolidity/ast/ASTJsonImporter.h index 3f1f5265c..4566a58a4 100644 --- a/libsolidity/ast/ASTJsonImporter.h +++ b/libsolidity/ast/ASTJsonImporter.h @@ -81,6 +81,7 @@ private: ASTPointer createStructDefinition(Json::Value const& _node); ASTPointer createEnumDefinition(Json::Value const& _node); ASTPointer createEnumValue(Json::Value const& _node); + ASTPointer createUserDefinedValueTypeDefinition(Json::Value const& _node); ASTPointer createParameterList(Json::Value const& _node); ASTPointer createOverrideSpecifier(Json::Value const& _node); ASTPointer createFunctionDefinition(Json::Value const& _node); diff --git a/test/libsolidity/ABIJson/user_defined_value_type.sol b/test/libsolidity/ABIJson/user_defined_value_type.sol new file mode 100644 index 000000000..da10f7c44 --- /dev/null +++ b/test/libsolidity/ABIJson/user_defined_value_type.sol @@ -0,0 +1,173 @@ +type MyInt is int; +type MyByte1 is bytes1; +contract C { + type MyAddress is address; + type MyUInt8 is uint8; + type MyBytes32 is bytes32; + + MyInt public myInt; + MyByte1 public myByte1; + MyAddress public myAddress; + MyUInt8 public myUInt8; + MyBytes32 public myBytes32; + + function setMyInt(MyInt a) external { + myInt = a; + } + function setMyByte1(MyByte1 a) external { + myByte1 = a; + } + function setMyAddress(MyAddress a) external { + myAddress = a; + } + function setMyUInt8(MyUInt8 a) external { + myUInt8 = a; + } + function setMyBytes32(MyBytes32 a) external { + myBytes32 = a; + } +} +// ---- +// :C +// [ +// { +// "inputs": [], +// "name": "myAddress", +// "outputs": +// [ +// { +// "internalType": "user defined type MyAddress", +// "name": "", +// "type": "address" +// } +// ], +// "stateMutability": "view", +// "type": "function" +// }, +// { +// "inputs": [], +// "name": "myByte1", +// "outputs": +// [ +// { +// "internalType": "user defined type MyByte1", +// "name": "", +// "type": "bytes1" +// } +// ], +// "stateMutability": "view", +// "type": "function" +// }, +// { +// "inputs": [], +// "name": "myBytes32", +// "outputs": +// [ +// { +// "internalType": "user defined type MyBytes32", +// "name": "", +// "type": "bytes32" +// } +// ], +// "stateMutability": "view", +// "type": "function" +// }, +// { +// "inputs": [], +// "name": "myInt", +// "outputs": +// [ +// { +// "internalType": "user defined type MyInt", +// "name": "", +// "type": "int256" +// } +// ], +// "stateMutability": "view", +// "type": "function" +// }, +// { +// "inputs": [], +// "name": "myUInt8", +// "outputs": +// [ +// { +// "internalType": "user defined type MyUInt8", +// "name": "", +// "type": "uint8" +// } +// ], +// "stateMutability": "view", +// "type": "function" +// }, +// { +// "inputs": +// [ +// { +// "internalType": "user defined type MyAddress", +// "name": "a", +// "type": "address" +// } +// ], +// "name": "setMyAddress", +// "outputs": [], +// "stateMutability": "nonpayable", +// "type": "function" +// }, +// { +// "inputs": +// [ +// { +// "internalType": "user defined type MyByte1", +// "name": "a", +// "type": "bytes1" +// } +// ], +// "name": "setMyByte1", +// "outputs": [], +// "stateMutability": "nonpayable", +// "type": "function" +// }, +// { +// "inputs": +// [ +// { +// "internalType": "user defined type MyBytes32", +// "name": "a", +// "type": "bytes32" +// } +// ], +// "name": "setMyBytes32", +// "outputs": [], +// "stateMutability": "nonpayable", +// "type": "function" +// }, +// { +// "inputs": +// [ +// { +// "internalType": "user defined type MyInt", +// "name": "a", +// "type": "int256" +// } +// ], +// "name": "setMyInt", +// "outputs": [], +// "stateMutability": "nonpayable", +// "type": "function" +// }, +// { +// "inputs": +// [ +// { +// "internalType": "user defined type MyUInt8", +// "name": "a", +// "type": "uint8" +// } +// ], +// "name": "setMyUInt8", +// "outputs": [], +// "stateMutability": "nonpayable", +// "type": "function" +// } +// ] diff --git a/test/libsolidity/ASTJSON/userDefinedValueType.json b/test/libsolidity/ASTJSON/userDefinedValueType.json new file mode 100644 index 000000000..09b81a4d4 --- /dev/null +++ b/test/libsolidity/ASTJSON/userDefinedValueType.json @@ -0,0 +1,264 @@ +{ + "absolutePath": "a", + "exportedSymbols": + { + "C": + [ + 21 + ], + "MyAddress": + [ + 2 + ], + "MyUInt": + [ + 4 + ], + "f": + [ + 16 + ] + }, + "id": 22, + "nodeType": "SourceUnit", + "nodes": + [ + { + "id": 2, + "name": "MyAddress", + "nameLocation": "5:9:1", + "nodeType": "UserDefinedValueTypeDefinition", + "src": "0:26:1", + "underlyingType": + { + "id": 1, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "18:7:1", + "stateMutability": "nonpayable", + "typeDescriptions": + { + "typeIdentifier": "t_address", + "typeString": "address" + } + } + }, + { + "id": 4, + "name": "MyUInt", + "nameLocation": "32:6:1", + "nodeType": "UserDefinedValueTypeDefinition", + "src": "27:20:1", + "underlyingType": + { + "id": 3, + "name": "uint", + "nodeType": "ElementaryTypeName", + "src": "42:4:1", + "typeDescriptions": + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + } + }, + { + "body": + { + "id": 15, + "nodeType": "Block", + "src": "61:34:1", + "statements": + [ + { + "assignments": + [ + 9 + ], + "declarations": + [ + { + "constant": false, + "id": 9, + "mutability": "mutable", + "name": "a", + "nameLocation": "77:1:1", + "nodeType": "VariableDeclaration", + "scope": 15, + "src": "67:11:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": + { + "typeIdentifier": "t_userDefinedValueType$_MyAddress_$2", + "typeString": "user defined type MyAddress" + }, + "typeName": + { + "id": 8, + "nodeType": "UserDefinedTypeName", + "pathNode": + { + "id": 7, + "name": "MyAddress", + "nodeType": "IdentifierPath", + "referencedDeclaration": 2, + "src": "67:9:1" + }, + "referencedDeclaration": 2, + "src": "67:9:1", + "typeDescriptions": + { + "typeIdentifier": "t_userDefinedValueType$_MyAddress_$2", + "typeString": "user defined type MyAddress" + } + }, + "visibility": "internal" + } + ], + "id": 10, + "nodeType": "VariableDeclarationStatement", + "src": "67:11:1" + }, + { + "assignments": + [ + 13 + ], + "declarations": + [ + { + "constant": false, + "id": 13, + "mutability": "mutable", + "name": "b", + "nameLocation": "91:1:1", + "nodeType": "VariableDeclaration", + "scope": 15, + "src": "84:8:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": + { + "typeIdentifier": "t_userDefinedValueType$_MyUInt_$4", + "typeString": "user defined type MyUInt" + }, + "typeName": + { + "id": 12, + "nodeType": "UserDefinedTypeName", + "pathNode": + { + "id": 11, + "name": "MyUInt", + "nodeType": "IdentifierPath", + "referencedDeclaration": 4, + "src": "84:6:1" + }, + "referencedDeclaration": 4, + "src": "84:6:1", + "typeDescriptions": + { + "typeIdentifier": "t_userDefinedValueType$_MyUInt_$4", + "typeString": "user defined type MyUInt" + } + }, + "visibility": "internal" + } + ], + "id": 14, + "nodeType": "VariableDeclarationStatement", + "src": "84:8:1" + } + ] + }, + "id": 16, + "implemented": true, + "kind": "freeFunction", + "modifiers": [], + "name": "f", + "nameLocation": "57:1:1", + "nodeType": "FunctionDefinition", + "parameters": + { + "id": 5, + "nodeType": "ParameterList", + "parameters": [], + "src": "58:2:1" + }, + "returnParameters": + { + "id": 6, + "nodeType": "ParameterList", + "parameters": [], + "src": "61:0:1" + }, + "scope": 22, + "src": "48:47:1", + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "internal" + }, + { + "abstract": false, + "baseContracts": [], + "contractDependencies": [], + "contractKind": "contract", + "fullyImplemented": true, + "id": 21, + "linearizedBaseContracts": + [ + 21 + ], + "name": "C", + "nameLocation": "105:1:1", + "nodeType": "ContractDefinition", + "nodes": + [ + { + "id": 18, + "name": "MyAddress", + "nameLocation": "118:9:1", + "nodeType": "UserDefinedValueTypeDefinition", + "src": "113:26:1", + "underlyingType": + { + "id": 17, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "131:7:1", + "stateMutability": "nonpayable", + "typeDescriptions": + { + "typeIdentifier": "t_address", + "typeString": "address" + } + } + }, + { + "id": 20, + "name": "MyUInt", + "nameLocation": "149:6:1", + "nodeType": "UserDefinedValueTypeDefinition", + "src": "144:20:1", + "underlyingType": + { + "id": 19, + "name": "uint", + "nodeType": "ElementaryTypeName", + "src": "159:4:1", + "typeDescriptions": + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + } + } + ], + "scope": 22, + "src": "96:70:1", + "usedErrors": [] + } + ], + "src": "0:167:1" +} diff --git a/test/libsolidity/ASTJSON/userDefinedValueType.sol b/test/libsolidity/ASTJSON/userDefinedValueType.sol new file mode 100644 index 000000000..cc179b118 --- /dev/null +++ b/test/libsolidity/ASTJSON/userDefinedValueType.sol @@ -0,0 +1,12 @@ +type MyAddress is address; +type MyUInt is uint; +function f() { + MyAddress a; + MyUInt b; +} +contract C { + type MyAddress is address; + type MyUInt is uint; +} + +// ---- diff --git a/test/libsolidity/ASTJSON/userDefinedValueType_parseOnly.json b/test/libsolidity/ASTJSON/userDefinedValueType_parseOnly.json new file mode 100644 index 000000000..1dd4b0edd --- /dev/null +++ b/test/libsolidity/ASTJSON/userDefinedValueType_parseOnly.json @@ -0,0 +1,200 @@ +{ + "absolutePath": "a", + "id": 22, + "nodeType": "SourceUnit", + "nodes": + [ + { + "id": 2, + "name": "MyAddress", + "nameLocation": "5:9:1", + "nodeType": "UserDefinedValueTypeDefinition", + "src": "0:26:1", + "underlyingType": + { + "id": 1, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "18:7:1", + "stateMutability": "nonpayable", + "typeDescriptions": {} + } + }, + { + "id": 4, + "name": "MyUInt", + "nameLocation": "32:6:1", + "nodeType": "UserDefinedValueTypeDefinition", + "src": "27:20:1", + "underlyingType": + { + "id": 3, + "name": "uint", + "nodeType": "ElementaryTypeName", + "src": "42:4:1", + "typeDescriptions": {} + } + }, + { + "body": + { + "id": 15, + "nodeType": "Block", + "src": "61:34:1", + "statements": + [ + { + "assignments": + [ + 9 + ], + "declarations": + [ + { + "constant": false, + "id": 9, + "mutability": "mutable", + "name": "a", + "nameLocation": "77:1:1", + "nodeType": "VariableDeclaration", + "src": "67:11:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": {}, + "typeName": + { + "id": 8, + "nodeType": "UserDefinedTypeName", + "pathNode": + { + "id": 7, + "name": "MyAddress", + "nodeType": "IdentifierPath", + "src": "67:9:1" + }, + "src": "67:9:1", + "typeDescriptions": {} + }, + "visibility": "internal" + } + ], + "id": 10, + "nodeType": "VariableDeclarationStatement", + "src": "67:11:1" + }, + { + "assignments": + [ + 13 + ], + "declarations": + [ + { + "constant": false, + "id": 13, + "mutability": "mutable", + "name": "b", + "nameLocation": "91:1:1", + "nodeType": "VariableDeclaration", + "src": "84:8:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": {}, + "typeName": + { + "id": 12, + "nodeType": "UserDefinedTypeName", + "pathNode": + { + "id": 11, + "name": "MyUInt", + "nodeType": "IdentifierPath", + "src": "84:6:1" + }, + "src": "84:6:1", + "typeDescriptions": {} + }, + "visibility": "internal" + } + ], + "id": 14, + "nodeType": "VariableDeclarationStatement", + "src": "84:8:1" + } + ] + }, + "id": 16, + "implemented": true, + "kind": "freeFunction", + "modifiers": [], + "name": "f", + "nameLocation": "57:1:1", + "nodeType": "FunctionDefinition", + "parameters": + { + "id": 5, + "nodeType": "ParameterList", + "parameters": [], + "src": "58:2:1" + }, + "returnParameters": + { + "id": 6, + "nodeType": "ParameterList", + "parameters": [], + "src": "61:0:1" + }, + "src": "48:47:1", + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "internal" + }, + { + "abstract": false, + "baseContracts": [], + "contractDependencies": [], + "contractKind": "contract", + "id": 21, + "name": "C", + "nameLocation": "105:1:1", + "nodeType": "ContractDefinition", + "nodes": + [ + { + "id": 18, + "name": "MyAddress", + "nameLocation": "118:9:1", + "nodeType": "UserDefinedValueTypeDefinition", + "src": "113:26:1", + "underlyingType": + { + "id": 17, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "131:7:1", + "stateMutability": "nonpayable", + "typeDescriptions": {} + } + }, + { + "id": 20, + "name": "MyUInt", + "nameLocation": "149:6:1", + "nodeType": "UserDefinedValueTypeDefinition", + "src": "144:20:1", + "underlyingType": + { + "id": 19, + "name": "uint", + "nodeType": "ElementaryTypeName", + "src": "159:4:1", + "typeDescriptions": {} + } + } + ], + "src": "96:70:1", + "usedErrors": [] + } + ], + "src": "0:167:1" +} From fbb1b884b2565b079118adf9e830dfd4a8aee119 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Tue, 17 Aug 2021 18:08:05 +0200 Subject: [PATCH 046/232] Documentation and Changelog --- Changelog.md | 1 + docs/abi-spec.rst | 3 ++ docs/types/value-types.rst | 63 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/Changelog.md b/Changelog.md index fc61a1b19..d13bc1332 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,6 +3,7 @@ Language Features: * Inheritance: A function that overrides only a single interface function does not require the ``override`` specifier. * Type System: Support ``type().min`` and ``type().max`` for enums. + * User Defined Value Type: allows creating a zero cost abstraction over a value type with stricter type requirements. Compiler Features: diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index 1b61351fa..6f50c70d9 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -113,6 +113,9 @@ them. +-------------------------------+-----------------------------------------------------------------------------+ |:ref:`enum` |``uint8`` | +-------------------------------+-----------------------------------------------------------------------------+ +|:ref:`user defined value types |its underlying value type | +|` | | ++-------------------------------+-----------------------------------------------------------------------------+ |:ref:`struct` |``tuple`` | +-------------------------------+-----------------------------------------------------------------------------+ diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index e3d6ed0d7..c1ac3d264 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -628,6 +628,69 @@ smallest and respectively largest value of the given enum. .. note:: Enums can also be declared on the file level, outside of contract or library definitions. +.. index:: ! user defined value type, custom type + +.. _user-defined-value-types: + +User Defined Value Types +------------------------ + +A user defined value type allows creating a zero cost abstraction over an elementary value type. +This is similar to an alias, but with stricter type requirements. + +A user defined value type is defined using ``type C is V``, where ``C`` is the name of the newly +introduced type and ``V`` has to be a built-in value type (the "underlying type"). The function +``C.wrap`` is used to convert from the underlying type to the custom type. Similarly, the +function ``C.unwrap`` is used to convert from the custom type to the underlying type. + +The type ``C`` does not have any operators or bound member functions. In particular, even the +operator ``==`` is not defined. Explicit and implicit conversions to and from other types are +disallowed. + +The data-representation of values of such types are inherited from the underlying type +and the underlying type is also used in the ABI. + +The following example illustrates a custom type ``UFixed256x18`` representing a decimal fixed point +type with 18 decimals and a minimal library to do arithmetic operations on the type. + + +.. code-block:: solidity + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity ^0.8.8; + + // Represent a 18 decimal, 256 bit wide fixed point type using a user defined value type. + type UFixed256x18 is uint256; + + /// A minimal library to do fixed point operations on UFixed256x18. + library FixedMath { + uint constant multiplier = 10**18; + + /// Adds two UFixed256x18 numbers. Reverts on overflow, relying on checked + /// arithmetic on uint256. + function add(UFixed256x18 a, UFixed256x18 b) internal pure returns (UFixed256x18) { + return UFixed256x18.wrap(UFixed256x18.unwrap(a) + UFixed256x18.unwrap(b)); + } + /// Multiplies UFixed256x18 and uint256. Reverts on overflow, relying on checked + /// arithmetic on uint256. + function mul(UFixed256x18 a, uint256 b) internal pure returns (UFixed256x18) { + return UFixed256x18.wrap(UFixed256x18.unwrap(a) * b); + } + /// Truncates UFixed256x18 to the nearest uint256 number. + function truncate(UFixed256x18 a) internal pure returns (uint256) { + return UFixed256x18.unwrap(a) / multiplier; + } + /// Turns a uint256 into a UFixed256x18 of the same value. + /// Reverts if the integer is too large. + function toUFixed256x18(uint256 a) internal pure returns (UFixed256x18) { + return UFixed256x18.wrap(a * multiplier); + } + } + +Notice how ``UFixed256x18.wrap`` and ``FixedMath.toUFixed256x18`` have the same signature but +perform two very different operations: The ``UFixed256x18.wrap`` function returns a ``UFixed256x18`` +that has the same data representation as the input, whereas ``toUFixed256x18`` returns a +``UFixed256x18`` that has the same numerical value. .. index:: ! function type, ! type; function From 7e9555532571e725f8871bfb10a6c9f380671e8e Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 23 Aug 2021 14:20:03 +0200 Subject: [PATCH 047/232] Updated ANTLR grammar to include user defined value types. --- docs/grammar/SolidityParser.g4 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/grammar/SolidityParser.g4 b/docs/grammar/SolidityParser.g4 index 0dbc7339d..f7630c59e 100644 --- a/docs/grammar/SolidityParser.g4 +++ b/docs/grammar/SolidityParser.g4 @@ -19,6 +19,7 @@ sourceUnit: ( | constantVariableDeclaration | structDefinition | enumDefinition + | userDefinedValueTypeDefinition | errorDefinition )* EOF; @@ -89,6 +90,7 @@ contractBodyElement: | receiveFunctionDefinition | structDefinition | enumDefinition + | userDefinedValueTypeDefinition | stateVariableDeclaration | eventDefinition | errorDefinition @@ -247,6 +249,11 @@ structMember: type=typeName name=identifier Semicolon; * Definition of an enum. Can occur at top-level within a source unit or within a contract, library or interface. */ enumDefinition: Enum name=identifier LBrace enumValues+=identifier (Comma enumValues+=identifier)* RBrace; +/** + * Definition of a user defined value type. Can occur at top-level within a source unit or within a contract, library or interface. + */ +userDefinedValueTypeDefinition: + Type name=identifier Is elementaryTypeName[true] Semicolon; /** * The declaration of a state variable. From a03fbf7061fe7c43007def1fd307bfc598ababab Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Thu, 9 Sep 2021 12:07:51 +0200 Subject: [PATCH 048/232] User defined value types: moved a syntax test to semantic test. --- .../userDefinedValueType/in_parenthesis.sol | 13 +++++++++++++ .../userDefinedValueType/in_parenthesis.sol | 7 ------- 2 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/in_parenthesis.sol delete mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/in_parenthesis.sol diff --git a/test/libsolidity/semanticTests/userDefinedValueType/in_parenthesis.sol b/test/libsolidity/semanticTests/userDefinedValueType/in_parenthesis.sol new file mode 100644 index 000000000..0691a4c3a --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/in_parenthesis.sol @@ -0,0 +1,13 @@ +type MyInt is int; +contract C { + function f() public returns (MyInt a, int b) { + (MyInt).wrap; + a = (MyInt).wrap(5); + (MyInt).unwrap; + b = (MyInt).unwrap((MyInt).wrap(10)); + } +} +// ==== +// compileViaYul: also +// ---- +// f() -> 5, 10 diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/in_parenthesis.sol b/test/libsolidity/syntaxTests/userDefinedValueType/in_parenthesis.sol deleted file mode 100644 index 403ceaa7a..000000000 --- a/test/libsolidity/syntaxTests/userDefinedValueType/in_parenthesis.sol +++ /dev/null @@ -1,7 +0,0 @@ -type MyInt is int; -function f() pure { - (MyInt).wrap; - (MyInt).wrap(5); - (MyInt).unwrap; - (MyInt).unwrap(MyInt.wrap(5)); -} From f6eecb8c6f4f46a51dddbdb4eceb129c4693867a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 9 Sep 2021 13:26:45 +0200 Subject: [PATCH 049/232] Fix gas costs that went out of sync in some tests due to a recent merge --- test/libsolidity/gasTests/abiv2_optimised.sol | 4 ++-- .../semanticTests/userDefinedValueType/calldata.sol | 4 ++-- .../semanticTests/userDefinedValueType/erc20.sol | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/libsolidity/gasTests/abiv2_optimised.sol b/test/libsolidity/gasTests/abiv2_optimised.sol index 074e75f1b..093acf49a 100644 --- a/test/libsolidity/gasTests/abiv2_optimised.sol +++ b/test/libsolidity/gasTests/abiv2_optimised.sol @@ -17,9 +17,9 @@ contract C { // optimize-yul: true // ---- // creation: -// codeDepositCost: 681000 +// codeDepositCost: 680600 // executionCost: 715 -// totalCost: 681715 +// totalCost: 681315 // external: // a(): 2285 // b(uint256): 4652 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol b/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol index 68164f180..3dc662947 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol @@ -51,11 +51,11 @@ contract C { // compileViaYul: also // ---- // test_f() -> true -// gas irOptimized: 122655 +// gas irOptimized: 122656 // gas legacy: 125037 // gas legacyOptimized: 122605 // test_g() -> true -// gas irOptimized: 95940 +// gas irOptimized: 95969 // gas legacy: 100656 // gas legacyOptimized: 96057 // addresses(uint256): 0 -> 0x18 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol b/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol index 57826ebe4..155a4bd87 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/erc20.sol @@ -115,7 +115,7 @@ contract ERC20 { // ---- // constructor() // ~ emit Transfer(address,address,uint256): #0x00, #0x1212121212121212121212121212120000000012, 0x14 -// gas irOptimized: 460447 +// gas irOptimized: 462361 // gas legacy: 861547 // gas legacyOptimized: 420959 // totalSupply() -> 20 @@ -124,12 +124,12 @@ contract ERC20 { // gas legacyOptimized: 23368 // transfer(address,uint256): 2, 5 -> true // ~ emit Transfer(address,address,uint256): #0x1212121212121212121212121212120000000012, #0x02, 0x05 -// gas irOptimized: 48514 +// gas irOptimized: 48503 // gas legacy: 49572 // gas legacyOptimized: 48575 // decreaseAllowance(address,uint256): 2, 0 -> true // ~ emit Approval(address,address,uint256): #0x1212121212121212121212121212120000000012, #0x02, 0x00 -// gas irOptimized: 26316 +// gas irOptimized: 26327 // gas legacy: 27204 // gas legacyOptimized: 26317 // decreaseAllowance(address,uint256): 2, 1 -> FAILURE, hex"4e487b71", 0x11 @@ -138,7 +138,7 @@ contract ERC20 { // gas legacyOptimized: 24077 // transfer(address,uint256): 2, 14 -> true // ~ emit Transfer(address,address,uint256): #0x1212121212121212121212121212120000000012, #0x02, 0x0e -// gas irOptimized: 28614 +// gas irOptimized: 28603 // gas legacy: 29672 // gas legacyOptimized: 28675 // transfer(address,uint256): 2, 2 -> FAILURE, hex"4e487b71", 0x11 From d91f75deb89bfb1b4edeb2cb267cad775587d01e Mon Sep 17 00:00:00 2001 From: Leo Alt Date: Mon, 6 Sep 2021 22:23:24 +0200 Subject: [PATCH 050/232] Fix ICE on unique errors --- liblangutil/UniqueErrorReporter.h | 10 +++----- test/libsolidity/SMTCheckerTest.cpp | 1 + .../imports/duplicated_errors_1.sol | 24 +++++++++++++++++++ 3 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 test/libsolidity/smtCheckerTests/imports/duplicated_errors_1.sol diff --git a/liblangutil/UniqueErrorReporter.h b/liblangutil/UniqueErrorReporter.h index d0f6dc4e2..886720568 100644 --- a/liblangutil/UniqueErrorReporter.h +++ b/liblangutil/UniqueErrorReporter.h @@ -58,11 +58,7 @@ public: void warning(ErrorId _error, std::string const& _description) { - if (!seen(_error, {}, _description)) - { - m_errorReporter.warning(_error, _description); - markAsSeen(_error, {}, _description); - } + m_errorReporter.warning(_error, _description); } bool seen(ErrorId _error, SourceLocation const& _location, std::string const& _description) const @@ -77,8 +73,8 @@ public: void markAsSeen(ErrorId _error, SourceLocation const& _location, std::string const& _description) { - solAssert(!seen(_error, _location, _description), ""); - m_seenErrors[{_error, _location}] = _description; + if (_location != SourceLocation{}) + m_seenErrors[{_error, _location}] = _description; } ErrorList const& errors() const { return m_errorReporter.errors(); } diff --git a/test/libsolidity/SMTCheckerTest.cpp b/test/libsolidity/SMTCheckerTest.cpp index 67a2f7919..8235ffe2c 100644 --- a/test/libsolidity/SMTCheckerTest.cpp +++ b/test/libsolidity/SMTCheckerTest.cpp @@ -35,6 +35,7 @@ SMTCheckerTest::SMTCheckerTest(string const& _filename): SyntaxTest(_filename, E else BOOST_THROW_EXCEPTION(runtime_error("Invalid SMT \"show unproved\" choice.")); + m_modelCheckerSettings.solvers = smtutil::SMTSolverChoice::None(); auto const& choice = m_reader.stringSetting("SMTSolvers", "any"); if (choice == "any") m_modelCheckerSettings.solvers = smtutil::SMTSolverChoice::All(); diff --git a/test/libsolidity/smtCheckerTests/imports/duplicated_errors_1.sol b/test/libsolidity/smtCheckerTests/imports/duplicated_errors_1.sol new file mode 100644 index 000000000..c8285a0bc --- /dev/null +++ b/test/libsolidity/smtCheckerTests/imports/duplicated_errors_1.sol @@ -0,0 +1,24 @@ +==== Source: a.sol ==== +contract A { + uint x; +} +==== Source: b.sol ==== +import "a.sol"; +contract B is A { + function g() public view { assert(x > x); } +} +==== Source: c.sol ==== +import "b.sol"; +contract C is B { + function h(uint x) public pure { assert(x < x); } +} +// ==== +// SMTEngine: all +// SMTSolvers: smtlib2 +// ---- +// Warning 6328: (b.sol:62-75): CHC: Assertion violation might happen here. +// Warning 3996: CHC analysis was not possible. No Horn solver was available. None of the installed solvers was enabled. +// Warning 7812: (b.sol:62-75): BMC: Assertion violation might happen here. +// Warning 8084: BMC analysis was not possible. No SMT solver (Z3 or CVC4) was available. None of the installed solvers was enabled. +// Warning 6328: (c.sol:68-81): CHC: Assertion violation might happen here. +// Warning 7812: (c.sol:68-81): BMC: Assertion violation might happen here. From 952540c3b5b7961c02ab8f1bd6717ef01641dd6b Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Thu, 9 Sep 2021 16:11:59 +0200 Subject: [PATCH 051/232] User defined value type: changes in documentation and test case Changed the name of a function from `truncate` to `floor`, since that is more appropriate; updated the inaccurate description on the rounding behaviour. Also modified the respective semantic test. --- docs/types/value-types.rst | 5 ++-- .../userDefinedValueType/fixedpoint.sol | 28 ++++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index c1ac3d264..c1b439c7e 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -676,8 +676,9 @@ type with 18 decimals and a minimal library to do arithmetic operations on the t function mul(UFixed256x18 a, uint256 b) internal pure returns (UFixed256x18) { return UFixed256x18.wrap(UFixed256x18.unwrap(a) * b); } - /// Truncates UFixed256x18 to the nearest uint256 number. - function truncate(UFixed256x18 a) internal pure returns (uint256) { + /// Take the floor of a UFixed256x18 number. + /// @return the largest integer that does not exceed `a`. + function floor(UFixed256x18 a) internal pure returns (uint256) { return UFixed256x18.unwrap(a) / multiplier; } /// Turns a uint256 into a UFixed256x18 of the same value. diff --git a/test/libsolidity/semanticTests/userDefinedValueType/fixedpoint.sol b/test/libsolidity/semanticTests/userDefinedValueType/fixedpoint.sol index 38a27e7be..47140a773 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/fixedpoint.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/fixedpoint.sol @@ -3,6 +3,7 @@ type UFixed256x18 is uint256; /// A minimal library to do fixed point operations on UFixed256x18. library FixedMath { + uint constant multiplier = 10**18; /// Adds two UFixed256x18 numbers. Reverts on overflow, relying on checked arithmetic on /// uint256. function add(UFixed256x18 a, UFixed256x18 b) internal returns (UFixed256x18) { @@ -13,9 +14,15 @@ library FixedMath { function mul(UFixed256x18 a, uint256 b) internal returns (UFixed256x18) { return UFixed256x18.wrap(UFixed256x18.unwrap(a) * b); } - /// Truncates UFixed256x18 to the nearest uint256 number. - function truncate(UFixed256x18 a) internal returns (uint256) { - return UFixed256x18.unwrap(a) / 10**18; + /// Take the floor of a UFixed256x18 number. + /// @return the largest integer that does not exceed `a`. + function floor(UFixed256x18 a) internal returns (uint256) { + return UFixed256x18.unwrap(a) / multiplier; + } + /// Turns a uint256 into a UFixed256x18 of the same value. + /// Reverts if the integer is too large. + function toUFixed256x18(uint256 a) internal pure returns (UFixed256x18) { + return UFixed256x18.wrap(a * multiplier); } } @@ -26,8 +33,11 @@ contract TestFixedMath { function mul(UFixed256x18 a, uint256 b) external returns (UFixed256x18) { return FixedMath.mul(a, b); } - function truncate(UFixed256x18 a) external returns (uint256) { - return FixedMath.truncate(a); + function floor(UFixed256x18 a) external returns (uint256) { + return FixedMath.floor(a); + } + function toUFixed256x18(uint256 a) external returns (UFixed256x18) { + return FixedMath.toUFixed256x18(a); } } // ==== @@ -38,5 +48,9 @@ contract TestFixedMath { // add(uint256,uint256): 115792089237316195423570985008687907853269984665640564039457584007913129639935, 10 -> FAILURE, hex"4e487b71", 0x11 // mul(uint256,uint256): 340282366920938463463374607431768211456, 45671926166590716193865151022383844364247891968 -> FAILURE, hex"4e487b71", 0x11 // mul(uint256,uint256): 340282366920938463463374607431768211456, 20 -> 6805647338418769269267492148635364229120 -// truncate(uint256): 11579208923731619542357098500868790785326998665640564039457584007913129639930 -> 11579208923731619542357098500868790785326998665640564039457 -// truncate(uint256): 115792089237316195423570985008687907853269984665640564039457584007913129639935 -> 115792089237316195423570985008687907853269984665640564039457 +// floor(uint256): 11579208923731619542357098500868790785326998665640564039457584007913129639930 -> 11579208923731619542357098500868790785326998665640564039457 +// floor(uint256): 115792089237316195423570985008687907853269984665640564039457584007913129639935 -> 115792089237316195423570985008687907853269984665640564039457 +// toUFixed256x18(uint256): 0 -> 0 +// toUFixed256x18(uint256): 5 -> 5000000000000000000 +// toUFixed256x18(uint256): 115792089237316195423570985008687907853269984665640564039457 -> 115792089237316195423570985008687907853269984665640564039457000000000000000000 +// toUFixed256x18(uint256): 115792089237316195423570985008687907853269984665640564039458 -> FAILURE, hex"4e487b71", 0x11 From 066c2a4699801ff973d9dc7ae29166ee93863966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 8 Sep 2021 18:47:57 +0200 Subject: [PATCH 052/232] Check expected errors in existing AsmParser tests --- test/libyul/Parser.cpp | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index 4a95f625e..08da8fdcb 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -44,6 +44,9 @@ using namespace solidity; using namespace solidity::util; using namespace solidity::langutil; +BOOST_TEST_DONT_PRINT_LOG_VALUE(ErrorId) +BOOST_TEST_DONT_PRINT_LOG_VALUE(Error::Type) + namespace solidity::yul::test { @@ -165,7 +168,7 @@ BOOST_AUTO_TEST_CASE(default_types_set) EVMDialectTyped::instance(EVMVersion{}), reporter ); - BOOST_REQUIRE(!!result); + BOOST_REQUIRE(!!result && errorList.size() == 0); // Use no dialect so that all types are printed. // This tests that the default types are properly assigned. @@ -210,7 +213,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_empty_block) "{}\n"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result); + BOOST_REQUIRE(!!result && errorList.size() == 0); CHECK_LOCATION(result->debugData->location, "source0", 234, 543); } @@ -251,7 +254,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_block_different_sources) "}\n"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result); + BOOST_REQUIRE(!!result && errorList.size() == 0); CHECK_LOCATION(result->debugData->location, "source0", 234, 543); BOOST_REQUIRE_EQUAL(3, result->statements.size()); CHECK_LOCATION(locationOf(result->statements.at(0)), "source0", 234, 543); @@ -273,7 +276,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_block_nested) "}\n"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result); + BOOST_REQUIRE(!!result && errorList.size() == 0); CHECK_LOCATION(result->debugData->location, "source0", 234, 543); BOOST_REQUIRE_EQUAL(2, result->statements.size()); CHECK_LOCATION(locationOf(result->statements.at(1)), "source0", 343, 434); @@ -297,7 +300,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_block_switch_case) "}\n"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result); + BOOST_REQUIRE(!!result && errorList.size() == 0); CHECK_LOCATION(result->debugData->location, "source0", 234, 543); BOOST_REQUIRE_EQUAL(2, result->statements.size()); @@ -329,7 +332,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_inherit_into_outer_scope) "}\n"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result); + BOOST_REQUIRE(!!result && errorList.size() == 0); CHECK_LOCATION(result->debugData->location, "source0", 1, 100); @@ -360,7 +363,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_assign_empty) "}\n"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result); // should still parse + BOOST_REQUIRE(!!result && errorList.size() == 0); // should still parse BOOST_REQUIRE_EQUAL(2, result->statements.size()); CHECK_LOCATION(locationOf(result->statements.at(0)), "source0", 123, 432); CHECK_LOCATION(locationOf(result->statements.at(1)), "source1", 1, 10); @@ -382,6 +385,9 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_source_index) EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result); // should still parse + BOOST_REQUIRE(errorList.size() == 1); + BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); + BOOST_TEST(errorList[0]->errorId() == 2674_error); } BOOST_AUTO_TEST_CASE(customSourceLocations_mixed_locations_1) @@ -398,7 +404,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_mixed_locations_1) "}\n"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result); + BOOST_REQUIRE(!!result && errorList.size() == 0); BOOST_REQUIRE_EQUAL(1, result->statements.size()); CHECK_LOCATION(locationOf(result->statements.at(0)), "source0", 123, 432); @@ -421,7 +427,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_mixed_locations_2) )"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result); + BOOST_REQUIRE(!!result && errorList.size() == 0); BOOST_REQUIRE_EQUAL(1, result->statements.size()); CHECK_LOCATION(result->debugData->location, "source0", 0, 5); @@ -455,7 +461,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_mixed_locations_3) )"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result); + BOOST_REQUIRE(!!result && errorList.size() == 0); BOOST_REQUIRE_EQUAL(2, result->statements.size()); CHECK_LOCATION(result->debugData->location, "source1", 23, 45); @@ -491,7 +497,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_comments_after_valid) )"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result); + BOOST_REQUIRE(!!result && errorList.size() == 0); BOOST_REQUIRE_EQUAL(1, result->statements.size()); CHECK_LOCATION(result->debugData->location, "source1", 23, 45); @@ -510,7 +516,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_suffix) )"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result); + BOOST_REQUIRE(!!result && errorList.size() == 0); CHECK_LOCATION(result->debugData->location, "", -1, -1); } @@ -524,7 +530,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_unspecified) )"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result); + BOOST_REQUIRE(!!result && errorList.size() == 0); CHECK_LOCATION(result->debugData->location, "", -1, -1); } @@ -542,7 +548,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_ensure_last_match) )"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result); + BOOST_REQUIRE(!!result && errorList.size() == 0); BOOST_REQUIRE(holds_alternative(result->statements.at(0))); VariableDeclaration const& varDecl = get(result->statements.at(0)); @@ -563,7 +569,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_reference_original_sloc) )"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result); + BOOST_REQUIRE(!!result && errorList.size() == 0); BOOST_REQUIRE(holds_alternative(result->statements.at(0))); VariableDeclaration const& varDecl = get(result->statements.at(0)); From 33ac5478de009ce68463759ce52554c01b84e239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 8 Sep 2021 18:50:16 +0200 Subject: [PATCH 053/232] More tests for @src in AsmParser --- test/libyul/Parser.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index 08da8fdcb..e1ed28a52 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -520,6 +520,20 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_suffix) CHECK_LOCATION(result->debugData->location, "", -1, -1); } +BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_prefix) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// abc@src 0:111:222 + {} + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result && errorList.size() == 0); + CHECK_LOCATION(result->debugData->location, "source0", 111, 222); +} + BOOST_AUTO_TEST_CASE(customSourceLocations_unspecified) { ErrorList errorList; @@ -534,6 +548,37 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_unspecified) CHECK_LOCATION(result->debugData->location, "", -1, -1); } +BOOST_AUTO_TEST_CASE(customSourceLocations_non_integer) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// @src a:b:c + {} + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result && errorList.size() == 0); + CHECK_LOCATION(result->debugData->location, "", -1, -1); +} + +BOOST_AUTO_TEST_CASE(customSourceLocations_bad_integer) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// @src 111111111111111111111:222222222222222222222:333333333333333333333 + {} + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result); + BOOST_REQUIRE(errorList.size() == 1); + BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); + BOOST_TEST(errorList[0]->errorId() == 6367_error); + CHECK_LOCATION(result->debugData->location, "", -1, -1); +} + BOOST_AUTO_TEST_CASE(customSourceLocations_ensure_last_match) { ErrorList errorList; @@ -556,6 +601,31 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_ensure_last_match) CHECK_LOCATION(varDecl.debugData->location, "source0", 30, 40); } +BOOST_AUTO_TEST_CASE(customSourceLocations_two_locations_no_whitespace) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// @src 0:111:222@src 1:333:444 + {} + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result && errorList.size() == 0); + CHECK_LOCATION(result->debugData->location, "source1", 333, 444); +} + +BOOST_AUTO_TEST_CASE(customSourceLocations_leading_trailing_whitespace) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = "/// @src 0:111:222 \n{}"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result && errorList.size() == 0); + CHECK_LOCATION(result->debugData->location, "source0", 111, 222); +} + BOOST_AUTO_TEST_CASE(customSourceLocations_reference_original_sloc) { ErrorList errorList; From e3a5f923eb71f221cd26c5881b0c330159b86177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 2 Sep 2021 15:08:47 +0200 Subject: [PATCH 054/232] AsmParser: Refactor the @src regex --- libyul/AsmParser.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index d1465c737..9d1395585 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -131,7 +131,8 @@ void Parser::fetchSourceLocationFromComment() return; static regex const lineRE = std::regex( - R"~~~((^|\s*)@src\s+(-1|\d+):(-1|\d+):(-1|\d+)(\s+|$))~~~", + R"~~(\s*@src\s+)~~" // tag: @src + R"~~((-1|\d+):(-1|\d+):(-1|\d+)(?:\s+|$))~~", // index and location, e.g.: 1:234:-1 std::regex_constants::ECMAScript | std::regex_constants::optimize ); @@ -141,11 +142,11 @@ void Parser::fetchSourceLocationFromComment() for (auto const& matchResult: ranges::make_subrange(from, to)) { - solAssert(matchResult.size() == 6, ""); + solAssert(matchResult.size() == 4, ""); - auto const sourceIndex = toInt(matchResult[2].str()); - auto const start = toInt(matchResult[3].str()); - auto const end = toInt(matchResult[4].str()); + auto const sourceIndex = toInt(matchResult[1].str()); + auto const start = toInt(matchResult[2].str()); + auto const end = toInt(matchResult[3].str()); auto const commentLocation = m_scanner->currentCommentLocation(); m_debugDataOverride = DebugData::create(); From aa156ab6c7c03ffacfa9c24071a67bc5e02f5683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 8 Sep 2021 16:04:45 +0200 Subject: [PATCH 055/232] Parser::fetchSourceLocationFromComment(): Some general cleanup (renaming, wrapping, etc.) --- libyul/AsmParser.cpp | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 9d1395585..4e82fe9b9 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -130,37 +130,46 @@ void Parser::fetchSourceLocationFromComment() if (m_scanner->currentCommentLiteral().empty()) return; - static regex const lineRE = std::regex( + static regex const tagRegex = regex( R"~~(\s*@src\s+)~~" // tag: @src R"~~((-1|\d+):(-1|\d+):(-1|\d+)(?:\s+|$))~~", // index and location, e.g.: 1:234:-1 - std::regex_constants::ECMAScript | std::regex_constants::optimize + regex_constants::ECMAScript | regex_constants::optimize ); - string const text = m_scanner->currentCommentLiteral(); - auto from = sregex_iterator(text.begin(), text.end(), lineRE); + string const commentLiteral = m_scanner->currentCommentLiteral(); + SourceLocation const commentLocation = m_scanner->currentCommentLocation(); + auto from = sregex_iterator(commentLiteral.begin(), commentLiteral.end(), tagRegex); auto to = sregex_iterator(); - for (auto const& matchResult: ranges::make_subrange(from, to)) + for (auto const& tagMatch: ranges::make_subrange(from, to)) { - solAssert(matchResult.size() == 4, ""); + solAssert(tagMatch.size() == 4, ""); - auto const sourceIndex = toInt(matchResult[1].str()); - auto const start = toInt(matchResult[2].str()); - auto const end = toInt(matchResult[3].str()); + optional const sourceIndex = toInt(tagMatch[1].str()); + optional const start = toInt(tagMatch[2].str()); + optional const end = toInt(tagMatch[3].str()); auto const commentLocation = m_scanner->currentCommentLocation(); m_debugDataOverride = DebugData::create(); - if (!sourceIndex || !start || !end) - m_errorReporter.syntaxError(6367_error, commentLocation, "Invalid value in source location mapping. Could not parse location specification."); + if (!sourceIndex.has_value() || !start.has_value() || !end.has_value()) + m_errorReporter.syntaxError( + 6367_error, + commentLocation, + "Invalid value in source location mapping. Could not parse location specification." + ); else if (sourceIndex == -1) - m_debugDataOverride = DebugData::create(SourceLocation{*start, *end, nullptr}); - else if (!(sourceIndex >= 0 && m_sourceNames->count(static_cast(*sourceIndex)))) - m_errorReporter.syntaxError(2674_error, commentLocation, "Invalid source mapping. Source index not defined via @use-src."); + m_debugDataOverride = DebugData::create(SourceLocation{start.value(), end.value(), nullptr}); + else if (!(sourceIndex >= 0 && m_sourceNames->count(static_cast(sourceIndex.value())))) + m_errorReporter.syntaxError( + 2674_error, + commentLocation, + "Invalid source mapping. Source index not defined via @use-src." + ); else { - shared_ptr sourceName = m_sourceNames->at(static_cast(*sourceIndex)); + shared_ptr sourceName = m_sourceNames->at(static_cast(sourceIndex.value())); solAssert(sourceName, ""); - m_debugDataOverride = DebugData::create(SourceLocation{*start, *end, move(sourceName)}); + m_debugDataOverride = DebugData::create(SourceLocation{start.value(), end.value(), move(sourceName)}); } } } From 14396c207cf6e0513b5fbfae3eb33fd4c1eb186b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 8 Sep 2021 16:08:05 +0200 Subject: [PATCH 056/232] AsmParser: Generalize location comment parsing to make it easier to add support for more tags --- libyul/AsmParser.cpp | 86 +++++++++++++++++++++++++++--------------- scripts/error_codes.py | 1 + test/libyul/Parser.cpp | 17 +++++++-- 3 files changed, 70 insertions(+), 34 deletions(-) diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 4e82fe9b9..382cc72aa 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -131,46 +131,72 @@ void Parser::fetchSourceLocationFromComment() return; static regex const tagRegex = regex( - R"~~(\s*@src\s+)~~" // tag: @src - R"~~((-1|\d+):(-1|\d+):(-1|\d+)(?:\s+|$))~~", // index and location, e.g.: 1:234:-1 + R"~~(\s*(@[a-zA-Z0-9\-_]+)(?:\s+|$))~~", // tag, e.g: @src + regex_constants::ECMAScript | regex_constants::optimize + ); + static regex const srcTagArgsRegex = regex( + R"~~(^(-1|\d+):(-1|\d+):(-1|\d+)(?:\s+|$))~~", // index and location, e.g.: 1:234:-1 regex_constants::ECMAScript | regex_constants::optimize ); string const commentLiteral = m_scanner->currentCommentLiteral(); SourceLocation const commentLocation = m_scanner->currentCommentLocation(); - auto from = sregex_iterator(commentLiteral.begin(), commentLiteral.end(), tagRegex); - auto to = sregex_iterator(); + smatch tagMatch; + string::const_iterator position = commentLiteral.begin(); - for (auto const& tagMatch: ranges::make_subrange(from, to)) + while (regex_search(position, commentLiteral.end(), tagMatch, tagRegex)) { - solAssert(tagMatch.size() == 4, ""); + solAssert(tagMatch.size() == 2, ""); + position += tagMatch.position() + tagMatch.length(); - optional const sourceIndex = toInt(tagMatch[1].str()); - optional const start = toInt(tagMatch[2].str()); - optional const end = toInt(tagMatch[3].str()); - - auto const commentLocation = m_scanner->currentCommentLocation(); - m_debugDataOverride = DebugData::create(); - if (!sourceIndex.has_value() || !start.has_value() || !end.has_value()) - m_errorReporter.syntaxError( - 6367_error, - commentLocation, - "Invalid value in source location mapping. Could not parse location specification." - ); - else if (sourceIndex == -1) - m_debugDataOverride = DebugData::create(SourceLocation{start.value(), end.value(), nullptr}); - else if (!(sourceIndex >= 0 && m_sourceNames->count(static_cast(sourceIndex.value())))) - m_errorReporter.syntaxError( - 2674_error, - commentLocation, - "Invalid source mapping. Source index not defined via @use-src." - ); - else + if (tagMatch[1] == "@src") { - shared_ptr sourceName = m_sourceNames->at(static_cast(sourceIndex.value())); - solAssert(sourceName, ""); - m_debugDataOverride = DebugData::create(SourceLocation{start.value(), end.value(), move(sourceName)}); + smatch srcTagArgsMatch; + if (!regex_search(position, commentLiteral.end(), srcTagArgsMatch, srcTagArgsRegex)) + { + m_errorReporter.syntaxError( + 8387_error, + commentLocation, + "Invalid values in source location mapping. Could not parse location specification." + ); + + // If the arguments to @src are malformed, we don't know where they end so we can't continue. + return; + } + + solAssert(srcTagArgsMatch.size() == 4, ""); + position += srcTagArgsMatch.position() + srcTagArgsMatch.length(); + + optional const sourceIndex = toInt(srcTagArgsMatch[1].str()); + optional const start = toInt(srcTagArgsMatch[2].str()); + optional const end = toInt(srcTagArgsMatch[3].str()); + + m_debugDataOverride = DebugData::create(); + if (!sourceIndex.has_value() || !start.has_value() || !end.has_value()) + m_errorReporter.syntaxError( + 6367_error, + commentLocation, + "Invalid value in source location mapping. " + "Expected non-negative integer values or -1 for source index and location." + ); + else if (sourceIndex == -1) + m_debugDataOverride = DebugData::create(SourceLocation{start.value(), end.value(), nullptr}); + else if (!(sourceIndex >= 0 && m_sourceNames->count(static_cast(sourceIndex.value())))) + m_errorReporter.syntaxError( + 2674_error, + commentLocation, + "Invalid source mapping. Source index not defined via @use-src." + ); + else + { + shared_ptr sourceName = m_sourceNames->at(static_cast(sourceIndex.value())); + solAssert(sourceName, ""); + m_debugDataOverride = DebugData::create(SourceLocation{start.value(), end.value(), move(sourceName)}); + } } + else + // Ignore unrecognized tags. + continue; } } diff --git a/scripts/error_codes.py b/scripts/error_codes.py index 320074ff1..6f3f9ce95 100755 --- a/scripts/error_codes.py +++ b/scripts/error_codes.py @@ -194,6 +194,7 @@ def examine_id_coverage(top_dir, source_id_to_file_names, new_ids_only=False): "9804", # Tested in test/libyul/ObjectParser.cpp. "2674", "6367", + "8387", "3805", # "This is a pre-release compiler version, please do not use it in production." # The warning may or may not exist in a compiler build. "4591", # "There are more than 256 warnings. Ignoring the rest." diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index e1ed28a52..67196ffc8 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -516,7 +516,10 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_suffix) )"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result && errorList.size() == 0); + BOOST_REQUIRE(!!result); + BOOST_REQUIRE(errorList.size() == 1); + BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); + BOOST_TEST(errorList[0]->errorId() == 8387_error); CHECK_LOCATION(result->debugData->location, "", -1, -1); } @@ -558,7 +561,10 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_non_integer) )"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result && errorList.size() == 0); + BOOST_REQUIRE(!!result); + BOOST_REQUIRE(errorList.size() == 1); + BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); + BOOST_TEST(errorList[0]->errorId() == 8387_error); CHECK_LOCATION(result->debugData->location, "", -1, -1); } @@ -611,8 +617,11 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_two_locations_no_whitespace) )"; EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); - BOOST_REQUIRE(!!result && errorList.size() == 0); - CHECK_LOCATION(result->debugData->location, "source1", 333, 444); + BOOST_REQUIRE(!!result); + BOOST_REQUIRE(errorList.size() == 1); + BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); + BOOST_TEST(errorList[0]->errorId() == 8387_error); + CHECK_LOCATION(result->debugData->location, "", -1, -1); } BOOST_AUTO_TEST_CASE(customSourceLocations_leading_trailing_whitespace) From fbdfc6bb7a64a792249bc24bab5f6555f22352d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 9 Sep 2021 18:27:29 +0200 Subject: [PATCH 057/232] AsmParser: Require whitespace before tags in location comments --- libyul/AsmParser.cpp | 2 +- test/libyul/Parser.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 382cc72aa..ca2864a5c 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -131,7 +131,7 @@ void Parser::fetchSourceLocationFromComment() return; static regex const tagRegex = regex( - R"~~(\s*(@[a-zA-Z0-9\-_]+)(?:\s+|$))~~", // tag, e.g: @src + R"~~((?:^|\s+)(@[a-zA-Z0-9\-_]+)(?:\s+|$))~~", // tag, e.g: @src regex_constants::ECMAScript | regex_constants::optimize ); static regex const srcTagArgsRegex = regex( diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index 67196ffc8..4168b23a3 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -534,7 +534,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_prefix) EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); - CHECK_LOCATION(result->debugData->location, "source0", 111, 222); + CHECK_LOCATION(result->debugData->location, "", -1, -1); } BOOST_AUTO_TEST_CASE(customSourceLocations_unspecified) From aedf29b9dd42d5d5882a9e2f3598dc32ee5826fc Mon Sep 17 00:00:00 2001 From: Nikita Stupin <18281368+nikitastupin@users.noreply.github.com> Date: Fri, 10 Sep 2021 11:27:55 +0300 Subject: [PATCH 058/232] Add sections for state mutability and special functions --- docs/contracts/functions.rst | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst index 93283e62c..7d1ce7256 100644 --- a/docs/contracts/functions.rst +++ b/docs/contracts/functions.rst @@ -155,12 +155,17 @@ When a function has multiple return types, the statement ``return (v0, v1, ..., The number of components must be the same as the number of return variables and their types have to match, potentially after an :ref:`implicit conversion `. +.. _state-mutability: + +State Mutability +================ + .. index:: ! view function, function;view .. _view-functions: View Functions -============== +-------------- Functions can be declared ``view`` in which case they promise not to modify the state. @@ -214,7 +219,7 @@ The following statements are considered modifying the state: .. _pure-functions: Pure Functions -============== +-------------- Functions can be declared ``pure`` in which case they promise not to read from or modify the state. @@ -270,12 +275,17 @@ This behaviour is also in line with the ``STATICCALL`` opcode. not do state-changing operations, but it cannot check that the contract that will be called at runtime is actually of that type. +.. _special-functions: + +Special Functions +================= + .. index:: ! receive ether function, function;receive ! receive .. _receive-ether-function: Receive Ether Function -====================== +---------------------- A contract can have at most one ``receive`` function, declared using ``receive() external payable { ... }`` @@ -346,7 +356,7 @@ Below you can see an example of a Sink contract that uses function ``receive``. .. _fallback-function: Fallback Function -================= +----------------- A contract can have at most one ``fallback`` function, declared using either ``fallback () external [payable]`` or ``fallback (bytes calldata _input) external [payable] returns (bytes memory _output)`` From b934ef6c6e40cf9005d4d336f56d1709cfec8062 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Fri, 3 Sep 2021 16:50:29 +0200 Subject: [PATCH 059/232] Only run evm bytecode generation if required. --- Changelog.md | 1 + solc/CommandLineInterface.cpp | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/Changelog.md b/Changelog.md index b1a350350..8ea1a2167 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,6 +6,7 @@ Language Features: Compiler Features: + * Commandline Interface: Do not implicitly run evm bytecode generation unless needed for the requested output. * Commandline Interface: Normalize paths specified on the command line and make them relative for files located inside base path. * Immutable variables can be read at construction time once they are initialized. * SMTChecker: Support low level ``call`` as external calls to unknown code. diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 549991d61..75b317654 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -594,6 +594,26 @@ bool CommandLineInterface::compile() m_compiler->enableIRGeneration(m_options.compiler.outputs.ir || m_options.compiler.outputs.irOptimized); m_compiler->enableEwasmGeneration(m_options.compiler.outputs.ewasm); + m_compiler->enableEvmBytecodeGeneration( + m_options.compiler.estimateGas || + m_options.compiler.outputs.asm_ || + m_options.compiler.outputs.asmJson || + m_options.compiler.outputs.opcodes || + m_options.compiler.outputs.binary || + m_options.compiler.outputs.binaryRuntime || + (m_options.compiler.combinedJsonRequests && ( + m_options.compiler.combinedJsonRequests->binary || + m_options.compiler.combinedJsonRequests->binaryRuntime || + m_options.compiler.combinedJsonRequests->opcodes || + m_options.compiler.combinedJsonRequests->asm_ || + m_options.compiler.combinedJsonRequests->generatedSources || + m_options.compiler.combinedJsonRequests->generatedSourcesRuntime || + m_options.compiler.combinedJsonRequests->srcMap || + m_options.compiler.combinedJsonRequests->srcMapRuntime || + m_options.compiler.combinedJsonRequests->funDebug || + m_options.compiler.combinedJsonRequests->funDebugRuntime + )) + ); OptimiserSettings settings = m_options.optimizer.enabled ? OptimiserSettings::standard() : OptimiserSettings::minimal(); if (m_options.optimizer.expectedExecutionsPerDeployment.has_value()) From f5e8f5246ccd14860763a8760d7c20a6e713e5ac Mon Sep 17 00:00:00 2001 From: soroosh-sdi Date: Fri, 10 Sep 2021 23:35:17 +0430 Subject: [PATCH 060/232] Add switch for command line & test.sh to skip smt - add --no-smt in scripts/tests.sh and test/cmdlineTests.sh Signed-off-by: soroosh-sdi --- scripts/tests.sh | 39 +++++++++++++++++++++++++++------------ test/cmdlineTests.sh | 44 +++++++++++++++++++++++++++++++------------- 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/scripts/tests.sh b/scripts/tests.sh index 1dcf2ae01..964d00668 100755 --- a/scripts/tests.sh +++ b/scripts/tests.sh @@ -52,17 +52,32 @@ cleanup() { } trap cleanup INT TERM -if [ "$1" = --junit_report ] -then - if [ -z "$2" ] - then - echo "Usage: $0 [--junit_report ]" - exit 1 - fi - log_directory="$2" -else - log_directory="" -fi +log_directory="" +no_smt="" +while [[ $# -gt 0 ]] +do + case "$1" in + --junit_report) + if [ -z "$2" ] + then + echo "Usage: $0 [--junit_report ] [--no-smt]" + exit 1 + else + log_directory="$2" + fi + shift + shift + ;; + --no-smt) + no_smt="--no-smt" + SMT_FLAGS+=(--no-smt) + shift + ;; + *) + echo "Usage: $0 [--junit_report ] [--no-smt]" + exit 1 + esac +done printTask "Testing Python scripts..." "$REPO_ROOT/test/pyscriptTests.py" @@ -74,7 +89,7 @@ then "$REPO_ROOT/test/cmdlineTests.sh" & CMDLINE_PID=$! else - if ! "$REPO_ROOT/test/cmdlineTests.sh" + if ! "$REPO_ROOT/test/cmdlineTests.sh" "$no_smt" then printError "Commandline tests FAILED" exit 1 diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 5d87357f0..4d72040a6 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -37,8 +37,26 @@ source "${REPO_ROOT}/scripts/common.sh" # shellcheck source=scripts/common_cmdline.sh source "${REPO_ROOT}/scripts/common_cmdline.sh" -AUTOUPDATE=false -[[ $1 == --update ]] && AUTOUPDATE=true && shift +autoupdate=false +no_smt=false +declare -a selected_tests +while [[ $# -gt 0 ]] +do + case "$1" in + --update) + autoupdate=true + shift + ;; + --no-smt) + no_smt=true + shift + ;; + *) + selected_tests+=("$1") + shift + ;; + esac +done case "$OSTYPE" in msys) @@ -91,7 +109,7 @@ function ask_expectation_update local newExpectation="${1}" local expectationFile="${2}" - if [[ $AUTOUPDATE == true ]] + if [[ $autoupdate == true ]] then update_expectation "$newExpectation" "$expectationFile" else @@ -302,18 +320,11 @@ test_solc_behaviour "${0}" "ctx:=/some/remapping/target" "" "" 1 "" "Invalid rem printTask "Running general commandline tests..." ( cd "$REPO_ROOT"/test/cmdlineTests/ - for tdir in ${*:-*/} + (( ${#selected_tests[@]} > 0 )) || selected_tests=(*) + for tdir in "${selected_tests[@]}" do if ! [[ -d $tdir ]]; then - if [[ $tdir =~ ^--.*$ ]]; then - if [[ $tdir == "--update" ]]; then - printError "The --update option must be given before any positional arguments." - else - printError "Invalid option: $tdir." - fi - else - printError "Test directory not found: $tdir" - fi + printError "Test directory not found: $tdir" exit 1 fi @@ -321,6 +332,13 @@ printTask "Running general commandline tests..." # Strip trailing slash from $tdir. tdir=$(basename "${tdir}") + if [[ $no_smt == true ]] + then + if [[ $tdir =~ .*model_checker_.* ]]; then + printWarning " --- > skipped" + continue + fi + fi inputFiles="$(ls -1 "${tdir}/input."* 2> /dev/null || true)" inputCount="$(echo "${inputFiles}" | wc -w)" From 1fa6c71bd0f1de88d9b157f2d2a19bf7985272c8 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 13 Sep 2021 10:02:27 +0200 Subject: [PATCH 061/232] Allow Mapping keys to have type UserDefinedValueType. Also added syntax and semantic test. --- .../analysis/DeclarationTypeChecker.cpp | 3 ++- .../userDefinedValueType/mapping_key.sol | 18 ++++++++++++++++++ .../parsing/mapping_nonelementary_key_2.sol | 2 +- .../parsing/mapping_nonelementary_key_3.sol | 2 +- .../types/struct_mapping_recursion.sol | 2 +- .../userDefinedValueType/mapping_key.sol | 4 ++++ 6 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/mapping_key.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/mapping_key.sol diff --git a/libsolidity/analysis/DeclarationTypeChecker.cpp b/libsolidity/analysis/DeclarationTypeChecker.cpp index f67d7d501..b015939e2 100644 --- a/libsolidity/analysis/DeclarationTypeChecker.cpp +++ b/libsolidity/analysis/DeclarationTypeChecker.cpp @@ -253,12 +253,13 @@ void DeclarationTypeChecker::endVisit(Mapping const& _mapping) { case Type::Category::Enum: case Type::Category::Contract: + case Type::Category::UserDefinedValueType: break; default: m_errorReporter.fatalTypeError( 7804_error, typeName->location(), - "Only elementary types, contract types or enums are allowed as mapping keys." + "Only elementary types, user defined value types, contract types or enums are allowed as mapping keys." ); break; } diff --git a/test/libsolidity/semanticTests/userDefinedValueType/mapping_key.sol b/test/libsolidity/semanticTests/userDefinedValueType/mapping_key.sol new file mode 100644 index 000000000..e698308b4 --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/mapping_key.sol @@ -0,0 +1,18 @@ +type MyInt is int; +contract C { + mapping(MyInt => int) public m; + function set(MyInt key, int value) external { + m[key] = value; + } + function set_unwrapped(int key, int value) external { + m[MyInt.wrap(key)] = value; + } +} +// ==== +// compileViaYul: also +// ---- +// set(int256,int256): 1, 1 -> +// m(int256): 1 -> 1 +// set_unwrapped(int256,int256): 1, 2 -> +// m(int256): 1 -> 2 +// m(int256): 2 -> 0 diff --git a/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_2.sol b/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_2.sol index 71063e34e..68aa61a41 100644 --- a/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_2.sol +++ b/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_2.sol @@ -5,4 +5,4 @@ contract c { mapping(S => uint) data; } // ---- -// TypeError 7804: (47-48): Only elementary types, contract types or enums are allowed as mapping keys. +// TypeError 7804: (47-48): Only elementary types, user defined value types, contract types or enums are allowed as mapping keys. diff --git a/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_3.sol b/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_3.sol index 34f0e82b3..991f2b622 100644 --- a/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_3.sol +++ b/test/libsolidity/syntaxTests/parsing/mapping_nonelementary_key_3.sol @@ -5,4 +5,4 @@ contract c { mapping(S => uint) data; } // ---- -// TypeError 7804: (49-50): Only elementary types, contract types or enums are allowed as mapping keys. +// TypeError 7804: (49-50): Only elementary types, user defined value types, contract types or enums are allowed as mapping keys. diff --git a/test/libsolidity/syntaxTests/types/struct_mapping_recursion.sol b/test/libsolidity/syntaxTests/types/struct_mapping_recursion.sol index 5dc39266f..be4e1dde0 100644 --- a/test/libsolidity/syntaxTests/types/struct_mapping_recursion.sol +++ b/test/libsolidity/syntaxTests/types/struct_mapping_recursion.sol @@ -6,4 +6,4 @@ contract C { function g (S calldata) external view {} } // ---- -// TypeError 7804: (56-57): Only elementary types, contract types or enums are allowed as mapping keys. +// TypeError 7804: (56-57): Only elementary types, user defined value types, contract types or enums are allowed as mapping keys. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/mapping_key.sol b/test/libsolidity/syntaxTests/userDefinedValueType/mapping_key.sol new file mode 100644 index 000000000..ae83ae4c7 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/mapping_key.sol @@ -0,0 +1,4 @@ +type MyInt is int; +contract C { + mapping(MyInt => int) m; +} From a1d4d0125d0c9aa57b270f6b172cc93c9dc9d3a7 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 13 Sep 2021 11:07:44 +0200 Subject: [PATCH 062/232] Allow UserDefinedValueType.uwrap (and wrap) as RHS of constant decl Needed to make `MyType.unwrap` and `MyType.unwrap` as pure in the process. This change affected some existing tests ("statement has no effect"). --- libsolidity/analysis/TypeChecker.cpp | 5 ++++- libsolidity/ast/Types.cpp | 4 +++- .../semanticTests/userDefinedValueType/constant.sol | 13 +++++++++++++ .../syntaxTests/userDefinedValueType/constant.sol | 8 ++++++++ .../explicit_conversions_wrap.sol | 2 ++ .../explicit_literal_conversion_wrap.sol | 3 +++ 6 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/constant.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/constant.sol diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 30159e9e5..369e04bc9 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -2916,7 +2916,10 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) // TODO some members might be pure, but for example `address(0x123).balance` is not pure // although every subexpression is, so leaving this limited for now. if (auto tt = dynamic_cast(exprType)) - if (tt->actualType()->category() == Type::Category::Enum) + if ( + tt->actualType()->category() == Type::Category::Enum || + tt->actualType()->category() == Type::Category::UserDefinedValueType + ) annotation.isPure = true; if ( auto const* functionType = dynamic_cast(exprType); diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index c1163156a..da6f7d196 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -3499,7 +3499,9 @@ bool FunctionType::isPure() const m_kind == Kind::ABIEncodeWithSelector || m_kind == Kind::ABIEncodeWithSignature || m_kind == Kind::ABIDecode || - m_kind == Kind::MetaType; + m_kind == Kind::MetaType || + m_kind == Kind::Wrap || + m_kind == Kind::Unwrap; } TypePointers FunctionType::parseElementaryTypeVector(strings const& _types) diff --git a/test/libsolidity/semanticTests/userDefinedValueType/constant.sol b/test/libsolidity/semanticTests/userDefinedValueType/constant.sol new file mode 100644 index 000000000..9559c3d7a --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/constant.sol @@ -0,0 +1,13 @@ +type T is int224; +pragma solidity >= 0.0.0; +contract C { + T constant public s = T.wrap(int224(165521356710917456517261742455526507355687727119203895813322792776)); + T constant public t = s; + int224 constant public u = T.unwrap(t); +} +// ==== +// compileViaYul: also +// ---- +// s() -> 165521356710917456517261742455526507355687727119203895813322792776 +// t() -> 165521356710917456517261742455526507355687727119203895813322792776 +// u() -> 165521356710917456517261742455526507355687727119203895813322792776 diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/constant.sol b/test/libsolidity/syntaxTests/userDefinedValueType/constant.sol new file mode 100644 index 000000000..febe08193 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/constant.sol @@ -0,0 +1,8 @@ +contract C { + type MyInt is int; + MyInt constant mi = MyInt.wrap(5); + // This is currently unsupported. + uint[MyInt.unwrap(mi)] arr; +} +// ---- +// TypeError 5462: (122-138): Invalid array length, expected integer literal or constant expression. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversions_wrap.sol b/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversions_wrap.sol index fa343572d..6d10e8b20 100644 --- a/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversions_wrap.sol +++ b/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversions_wrap.sol @@ -6,3 +6,5 @@ function f() pure { MyAddress.wrap(address(5)); } // ---- +// Warning 6133: (73-87): Statement has no effect. +// Warning 6133: (93-119): Statement has no effect. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/explicit_literal_conversion_wrap.sol b/test/libsolidity/syntaxTests/userDefinedValueType/explicit_literal_conversion_wrap.sol index 7bca6f27b..0fb851196 100644 --- a/test/libsolidity/syntaxTests/userDefinedValueType/explicit_literal_conversion_wrap.sol +++ b/test/libsolidity/syntaxTests/userDefinedValueType/explicit_literal_conversion_wrap.sol @@ -7,3 +7,6 @@ function f() pure { MyUInt8.wrap(50); } // ---- +// Warning 6133: (75-101): Statement has no effect. +// Warning 6133: (107-122): Statement has no effect. +// Warning 6133: (128-144): Statement has no effect. From b5f5e85a12275dc60604bdd9065644f4295aba74 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Mon, 13 Sep 2021 11:27:37 +0200 Subject: [PATCH 063/232] cmake: Remove stdlib compile option for Solidity build. --- cmake/EthCompilerSettings.cmake | 8 -------- 1 file changed, 8 deletions(-) diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index 44268e699..0695c56a3 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -102,14 +102,6 @@ if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MA # Some Linux-specific Clang settings. We don't want these for OS X. if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") - - # TODO - Is this even necessary? Why? - # See http://stackoverflow.com/questions/19774778/when-is-it-necessary-to-use-use-the-flag-stdlib-libstdc. - add_compile_options(-stdlib=libstdc++) - - # Tell Boost that we're using Clang's libc++. Not sure exactly why we need to do. - add_definitions(-DBOOST_ASIO_HAS_CLANG_LIBCXX) - # Use fancy colors in the compiler diagnostics add_compile_options(-fcolor-diagnostics) From 2ead3f469e63523347d9f6b606374f68dd6ad663 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 13 Sep 2021 11:47:32 +0200 Subject: [PATCH 064/232] Added a user defined type mapping into the ASTJSON test. --- .../ASTJSON/userDefinedValueType.json | 86 +++++++++++++++++-- .../ASTJSON/userDefinedValueType.sol | 1 + .../userDefinedValueType_parseOnly.json | 56 +++++++++++- 3 files changed, 131 insertions(+), 12 deletions(-) diff --git a/test/libsolidity/ASTJSON/userDefinedValueType.json b/test/libsolidity/ASTJSON/userDefinedValueType.json index 09b81a4d4..f929122b1 100644 --- a/test/libsolidity/ASTJSON/userDefinedValueType.json +++ b/test/libsolidity/ASTJSON/userDefinedValueType.json @@ -4,7 +4,7 @@ { "C": [ - 21 + 27 ], "MyAddress": [ @@ -19,7 +19,7 @@ 16 ] }, - "id": 22, + "id": 28, "nodeType": "SourceUnit", "nodes": [ @@ -193,7 +193,7 @@ "parameters": [], "src": "61:0:1" }, - "scope": 22, + "scope": 28, "src": "48:47:1", "stateMutability": "nonpayable", "virtual": false, @@ -205,10 +205,10 @@ "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, - "id": 21, + "id": 27, "linearizedBaseContracts": [ - 21 + 27 ], "name": "C", "nameLocation": "105:1:1", @@ -253,12 +253,82 @@ "typeString": "uint256" } } + }, + { + "constant": false, + "functionSelector": "97682884", + "id": 26, + "mutability": "mutable", + "name": "m", + "nameLocation": "205:1:1", + "nodeType": "VariableDeclaration", + "scope": 27, + "src": "169:37:1", + "stateVariable": true, + "storageLocation": "default", + "typeDescriptions": + { + "typeIdentifier": "t_mapping$_t_userDefinedValueType$_MyAddress_$18_$_t_userDefinedValueType$_MyUInt_$20_$", + "typeString": "mapping(user defined type MyAddress => user defined type MyUInt)" + }, + "typeName": + { + "id": 25, + "keyType": + { + "id": 22, + "nodeType": "UserDefinedTypeName", + "pathNode": + { + "id": 21, + "name": "MyAddress", + "nodeType": "IdentifierPath", + "referencedDeclaration": 18, + "src": "177:9:1" + }, + "referencedDeclaration": 18, + "src": "177:9:1", + "typeDescriptions": + { + "typeIdentifier": "t_userDefinedValueType$_MyAddress_$18", + "typeString": "user defined type MyAddress" + } + }, + "nodeType": "Mapping", + "src": "169:28:1", + "typeDescriptions": + { + "typeIdentifier": "t_mapping$_t_userDefinedValueType$_MyAddress_$18_$_t_userDefinedValueType$_MyUInt_$20_$", + "typeString": "mapping(user defined type MyAddress => user defined type MyUInt)" + }, + "valueType": + { + "id": 24, + "nodeType": "UserDefinedTypeName", + "pathNode": + { + "id": 23, + "name": "MyUInt", + "nodeType": "IdentifierPath", + "referencedDeclaration": 20, + "src": "190:6:1" + }, + "referencedDeclaration": 20, + "src": "190:6:1", + "typeDescriptions": + { + "typeIdentifier": "t_userDefinedValueType$_MyUInt_$20", + "typeString": "user defined type MyUInt" + } + } + }, + "visibility": "public" } ], - "scope": 22, - "src": "96:70:1", + "scope": 28, + "src": "96:113:1", "usedErrors": [] } ], - "src": "0:167:1" + "src": "0:210:1" } diff --git a/test/libsolidity/ASTJSON/userDefinedValueType.sol b/test/libsolidity/ASTJSON/userDefinedValueType.sol index cc179b118..f1124f8cd 100644 --- a/test/libsolidity/ASTJSON/userDefinedValueType.sol +++ b/test/libsolidity/ASTJSON/userDefinedValueType.sol @@ -7,6 +7,7 @@ function f() { contract C { type MyAddress is address; type MyUInt is uint; + mapping(MyAddress => MyUInt) public m; } // ---- diff --git a/test/libsolidity/ASTJSON/userDefinedValueType_parseOnly.json b/test/libsolidity/ASTJSON/userDefinedValueType_parseOnly.json index 1dd4b0edd..36315b443 100644 --- a/test/libsolidity/ASTJSON/userDefinedValueType_parseOnly.json +++ b/test/libsolidity/ASTJSON/userDefinedValueType_parseOnly.json @@ -1,6 +1,6 @@ { "absolutePath": "a", - "id": 22, + "id": 28, "nodeType": "SourceUnit", "nodes": [ @@ -154,7 +154,7 @@ "baseContracts": [], "contractDependencies": [], "contractKind": "contract", - "id": 21, + "id": 27, "name": "C", "nameLocation": "105:1:1", "nodeType": "ContractDefinition", @@ -190,11 +190,59 @@ "src": "159:4:1", "typeDescriptions": {} } + }, + { + "constant": false, + "id": 26, + "mutability": "mutable", + "name": "m", + "nameLocation": "205:1:1", + "nodeType": "VariableDeclaration", + "src": "169:37:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": {}, + "typeName": + { + "id": 25, + "keyType": + { + "id": 22, + "nodeType": "UserDefinedTypeName", + "pathNode": + { + "id": 21, + "name": "MyAddress", + "nodeType": "IdentifierPath", + "src": "177:9:1" + }, + "src": "177:9:1", + "typeDescriptions": {} + }, + "nodeType": "Mapping", + "src": "169:28:1", + "typeDescriptions": {}, + "valueType": + { + "id": 24, + "nodeType": "UserDefinedTypeName", + "pathNode": + { + "id": 23, + "name": "MyUInt", + "nodeType": "IdentifierPath", + "src": "190:6:1" + }, + "src": "190:6:1", + "typeDescriptions": {} + } + }, + "visibility": "public" } ], - "src": "96:70:1", + "src": "96:113:1", "usedErrors": [] } ], - "src": "0:167:1" + "src": "0:210:1" } From fc37b18e884af0ebc245a7a905012a22fb7904a9 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Fri, 10 Sep 2021 16:04:49 +0200 Subject: [PATCH 065/232] Fix inline assembly assignments to calldata structs and statically-sized arrays. --- Changelog.md | 1 + libsolidity/codegen/ContractCompiler.cpp | 31 +++++++++++++------ ....sol => calldata_array_assign_dynamic.sol} | 0 .../calldata_array_assign_static.sol | 10 ++++++ .../inlineAssembly/calldata_struct_assign.sol | 18 +++++++++++ .../calldata_struct_assign_and_return.sol | 23 ++++++++++++++ 6 files changed, 74 insertions(+), 9 deletions(-) rename test/libsolidity/semanticTests/inlineAssembly/{calldata_array_assign.sol => calldata_array_assign_dynamic.sol} (100%) create mode 100644 test/libsolidity/semanticTests/inlineAssembly/calldata_array_assign_static.sol create mode 100644 test/libsolidity/semanticTests/inlineAssembly/calldata_struct_assign.sol create mode 100644 test/libsolidity/semanticTests/inlineAssembly/calldata_struct_assign_and_return.sol diff --git a/Changelog.md b/Changelog.md index 04e443d62..03057b6da 100644 --- a/Changelog.md +++ b/Changelog.md @@ -16,6 +16,7 @@ Compiler Features: Bugfixes: + * Code Generator: Fix ICE on assigning to calldata structs and statically-sized calldata arrays in inline assembly. * Code Generator: Use stable source order for ABI functions. * Opcode Optimizer: Prevent the optimizer from running multiple times to avoid potential bytecode differences for referenced code. * Name Resolver: Fix that when importing an aliased symbol using ``import {AliasedName} from "a.sol"`` it would use the original name of the symbol and not the aliased one. diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 6c5a0abe0..5c51a9bb9 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -860,15 +860,28 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) } else if (variable->type()->dataStoredIn(DataLocation::CallData)) { - auto const* arrayType = dynamic_cast(variable->type()); - solAssert( - arrayType && arrayType->isDynamicallySized() && arrayType->dataStoredIn(DataLocation::CallData), - "" - ); - solAssert(suffix == "offset" || suffix == "length", ""); - solAssert(variable->type()->sizeOnStack() == 2, ""); - if (suffix == "length") - stackDiff--; + if (auto const* arrayType = dynamic_cast(variable->type())) + { + if (arrayType->isDynamicallySized()) + { + solAssert(suffix == "offset" || suffix == "length", ""); + solAssert(variable->type()->sizeOnStack() == 2, ""); + if (suffix == "length") + stackDiff--; + } + else + { + solAssert(variable->type()->sizeOnStack() == 1, ""); + solAssert(suffix.empty(), ""); + } + } + else + { + auto const* structType = dynamic_cast(variable->type()); + solAssert(structType, ""); + solAssert(variable->type()->sizeOnStack() == 1, ""); + solAssert(suffix.empty(), ""); + } } else solAssert(suffix.empty(), ""); diff --git a/test/libsolidity/semanticTests/inlineAssembly/calldata_array_assign.sol b/test/libsolidity/semanticTests/inlineAssembly/calldata_array_assign_dynamic.sol similarity index 100% rename from test/libsolidity/semanticTests/inlineAssembly/calldata_array_assign.sol rename to test/libsolidity/semanticTests/inlineAssembly/calldata_array_assign_dynamic.sol diff --git a/test/libsolidity/semanticTests/inlineAssembly/calldata_array_assign_static.sol b/test/libsolidity/semanticTests/inlineAssembly/calldata_array_assign_static.sol new file mode 100644 index 000000000..3c0437819 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/calldata_array_assign_static.sol @@ -0,0 +1,10 @@ +contract C { + function f(uint[2][2] calldata x) public returns (uint[2][2] memory r) { + assembly { x := 0x24 } + r = x; + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256[2][2]): 0x0, 8, 7, 6, 5 -> 8, 7, 6, 5 diff --git a/test/libsolidity/semanticTests/inlineAssembly/calldata_struct_assign.sol b/test/libsolidity/semanticTests/inlineAssembly/calldata_struct_assign.sol new file mode 100644 index 000000000..bc8f9ffb7 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/calldata_struct_assign.sol @@ -0,0 +1,18 @@ +pragma abicoder v2; + +contract C { + struct S { uint256 x; } + struct S2 { uint256 x; uint256 y; } + function f(S calldata s, S2 calldata s2) public pure returns (uint256 r, uint256 r2) { + assembly { + s := s2 + s2 := 4 + } + r = s.x; + r2 = s2.x; + } +} +// ==== +// compileViaYul: also +// ---- +// f((uint256),(uint256,uint256)): 0x42, 0x07, 0x77 -> 0x07, 0x42 diff --git a/test/libsolidity/semanticTests/inlineAssembly/calldata_struct_assign_and_return.sol b/test/libsolidity/semanticTests/inlineAssembly/calldata_struct_assign_and_return.sol new file mode 100644 index 000000000..56a67f383 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/calldata_struct_assign_and_return.sol @@ -0,0 +1,23 @@ +pragma abicoder v2; +contract C { + struct S { int8 x; int8 y; } + function f() internal pure returns(S calldata s) { + assembly { + s := 0x24 + } + } + function g() public pure returns(int8, int8) { + S calldata s = f(); + return (s.x, s.y); + } + function h() public pure returns(uint256) { f(); return 0x42; } + function i() public pure returns(uint256) { abi.decode(msg.data[4:], (S)); return 0x42; } +} +// ==== +// compileViaYul: also +// ---- +// g(): 0xCAFFEE, 0x42, 0x21 -> 0x42, 0x21 +// g(): 0xCAFFEE, 0x4242, 0x2121 -> FAILURE +// g(): 0xCAFFEE, 0x42 -> 0x42, 0 +// h() -> 0x42 +// i() -> FAILURE From ab7b1625accac7b00621e9c0cb7ddee61a197e9f Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 13 Sep 2021 13:52:33 +0200 Subject: [PATCH 066/232] Tests for unassigned calldata returns. --- .../calldataReturn/calldata_return_dynamic_array.sol | 5 +++++ .../calldataReturn/calldata_return_static_array.sol | 5 +++++ .../controlFlow/calldataReturn/calldata_return_struct.sol | 6 ++++++ 3 files changed, 16 insertions(+) create mode 100644 test/libsolidity/syntaxTests/controlFlow/calldataReturn/calldata_return_dynamic_array.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/calldataReturn/calldata_return_static_array.sol create mode 100644 test/libsolidity/syntaxTests/controlFlow/calldataReturn/calldata_return_struct.sol diff --git a/test/libsolidity/syntaxTests/controlFlow/calldataReturn/calldata_return_dynamic_array.sol b/test/libsolidity/syntaxTests/controlFlow/calldataReturn/calldata_return_dynamic_array.sol new file mode 100644 index 000000000..2baadc8d0 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/calldataReturn/calldata_return_dynamic_array.sol @@ -0,0 +1,5 @@ +contract C { + function f() internal returns (uint256[] calldata) {} +} +// ---- +// TypeError 3464: (48-66): This variable is of calldata pointer type and can be returned without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/controlFlow/calldataReturn/calldata_return_static_array.sol b/test/libsolidity/syntaxTests/controlFlow/calldataReturn/calldata_return_static_array.sol new file mode 100644 index 000000000..0adfc86fe --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/calldataReturn/calldata_return_static_array.sol @@ -0,0 +1,5 @@ +contract C { + function f() internal returns (uint256[1] calldata) {} +} +// ---- +// TypeError 3464: (48-67): This variable is of calldata pointer type and can be returned without prior assignment, which would lead to undefined behaviour. diff --git a/test/libsolidity/syntaxTests/controlFlow/calldataReturn/calldata_return_struct.sol b/test/libsolidity/syntaxTests/controlFlow/calldataReturn/calldata_return_struct.sol new file mode 100644 index 000000000..fd682b090 --- /dev/null +++ b/test/libsolidity/syntaxTests/controlFlow/calldataReturn/calldata_return_struct.sol @@ -0,0 +1,6 @@ +contract C { + struct S { uint256 x; } + function f() internal returns (S calldata) {} +} +// ---- +// TypeError 3464: (76-86): This variable is of calldata pointer type and can be returned without prior assignment, which would lead to undefined behaviour. From 9ff0cc0b8bca1ce73ead8590c1de998c1dddff17 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 13 Sep 2021 14:00:24 +0200 Subject: [PATCH 067/232] Update docs. --- docs/assembly.rst | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/docs/assembly.rst b/docs/assembly.rst index 7edffca81..232e77777 100644 --- a/docs/assembly.rst +++ b/docs/assembly.rst @@ -124,9 +124,22 @@ Access to External Variables, Functions and Libraries You can access Solidity variables and other identifiers by using their name. Local variables of value type are directly usable in inline assembly. +They can both be read and assigned to. -Local variables that refer to memory or calldata evaluate to the -address of the variable in memory, resp. calldata, not the value itself. +Local variables that refer to memory evaluate to the address of the variable in memory not the value itself. +Such variables can also be assigned to, but note that an assignment will only change the pointer and not the data +and that it is your responsibility to respect Solidity's memory management. +See :ref:`Conventions in Solidity `. + +Similarly, local variables that refer to statically-sized calldata arrays or calldata structs +evaluate to the address of the variable in calldata, not the value itself. +The variable can also be assigned a new offset, but note that no validation to ensure that +the variable will not point beyond ``calldatasize()`` is performed. + +For dynamic calldata arrays, you can access +their calldata offset (in bytes) and length (number of elements) using ``x.offset`` and ``x.length``. +Both expressions can also be assigned to, but as for the static case, no validation will be performed +to ensure that the resulting data area is within the bounds of ``calldatasize()``. For local storage variables or state variables, a single Yul identifier is not sufficient, since they do not necessarily occupy a single full storage slot. @@ -135,9 +148,10 @@ inside that slot. To retrieve the slot pointed to by the variable ``x``, you use ``x.slot``, and to retrieve the byte-offset you use ``x.offset``. Using ``x`` itself will result in an error. -For dynamic calldata arrays, you can access -their calldata offset (in bytes) and length (number of elements) using ``x.offset`` and ``x.length``. -Both expressions can also be assigned to. +You can also assign to the ``.slot`` part of a local storage variable pointer. +For these (structs, arrays or mappings), the ``.offset`` part is always zero. +It is not possible to assign to the ``.slot`` or ``.offset`` part of a state variable, +though. Local Solidity variables are available for assignments, for example: @@ -178,17 +192,6 @@ Since Solidity 0.7.0, variables and functions declared inside the inline assembly block may not contain ``.``, but using ``.`` is valid to access Solidity variables from outside the inline assembly block. -Assignments are possible to assembly-local variables and to function-local -variables. Take care that when you assign to variables that point to -memory or storage, you will only change the pointer and not the data. - -You can assign to the ``.slot`` part of a local storage variable pointer. -For these (structs, arrays or mappings), the ``.offset`` part is always zero. -It is not possible to assign to the ``.slot`` or ``.offset`` part of a state variable, -though. - - - Things to Avoid --------------- @@ -199,6 +202,8 @@ functional-style opcodes, counting stack height for variable access and removing stack slots for assembly-local variables when the end of their block is reached. +.. _conventions-in-solidity: + Conventions in Solidity ----------------------- From b7c124911a953b611fde05927361024ea43290b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 3 Aug 2021 15:50:02 +0200 Subject: [PATCH 068/232] CommandLineParser: Process linker mode before assembly mode --- solc/CommandLineParser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 8ce0dfcfe..f2ffa8a0a 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -948,6 +948,9 @@ General Information)").c_str(), if (!parseLibraryOption(library)) return false; + if (m_options.input.mode == InputMode::Linker) + return true; + if (m_args.count(g_strEVMVersion)) { string versionOptionStr = m_args[g_strEVMVersion].as(); @@ -1078,9 +1081,6 @@ General Information)").c_str(), return false; } - if (m_options.input.mode == InputMode::Linker) - return true; - if (m_args.count(g_strMetadataHash)) { string hashStr = m_args[g_strMetadataHash].as(); From 7a36a1d1db7cb4400330c14cf3cbce4c22a99b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 3 Aug 2021 17:16:41 +0200 Subject: [PATCH 069/232] Reject optimizer options as invalid in linker and Standard JSON modes --- Changelog.md | 3 ++- solc/CommandLineParser.cpp | 20 +++++++++++++++++++ .../args | 1 + .../err | 1 + .../exit | 1 + .../input.bin | 0 .../linker_mode_invalid_option_optimize/args | 1 + .../linker_mode_invalid_option_optimize/err | 1 + .../linker_mode_invalid_option_optimize/exit | 1 + .../input.bin | 0 .../args | 1 + .../err | 1 + .../exit | 1 + .../input.bin | 0 .../args | 1 + .../err | 1 + .../exit | 1 + .../input.bin | 0 .../args | 1 + .../err | 1 + .../exit | 1 + .../input.bin | 0 .../args | 1 + .../err | 1 + .../exit | 1 + .../input.json | 0 .../standard_invalid_option_optimize/args | 1 + .../standard_invalid_option_optimize/err | 1 + .../standard_invalid_option_optimize/exit | 1 + .../input.json | 0 .../args | 1 + .../standard_invalid_option_optimize_runs/err | 1 + .../exit | 1 + .../input.json | 0 .../standard_invalid_option_optimize_yul/args | 1 + .../standard_invalid_option_optimize_yul/err | 1 + .../standard_invalid_option_optimize_yul/exit | 1 + .../input.json | 0 .../args | 1 + .../err | 1 + .../exit | 1 + .../input.json | 0 test/solc/CommandLineParser.cpp | 3 --- 43 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 test/cmdlineTests/linker_mode_invalid_option_no_optimize_yul/args create mode 100644 test/cmdlineTests/linker_mode_invalid_option_no_optimize_yul/err create mode 100644 test/cmdlineTests/linker_mode_invalid_option_no_optimize_yul/exit create mode 100644 test/cmdlineTests/linker_mode_invalid_option_no_optimize_yul/input.bin create mode 100644 test/cmdlineTests/linker_mode_invalid_option_optimize/args create mode 100644 test/cmdlineTests/linker_mode_invalid_option_optimize/err create mode 100644 test/cmdlineTests/linker_mode_invalid_option_optimize/exit create mode 100644 test/cmdlineTests/linker_mode_invalid_option_optimize/input.bin create mode 100644 test/cmdlineTests/linker_mode_invalid_option_optimize_runs/args create mode 100644 test/cmdlineTests/linker_mode_invalid_option_optimize_runs/err create mode 100644 test/cmdlineTests/linker_mode_invalid_option_optimize_runs/exit create mode 100644 test/cmdlineTests/linker_mode_invalid_option_optimize_runs/input.bin create mode 100644 test/cmdlineTests/linker_mode_invalid_option_optimize_yul/args create mode 100644 test/cmdlineTests/linker_mode_invalid_option_optimize_yul/err create mode 100644 test/cmdlineTests/linker_mode_invalid_option_optimize_yul/exit create mode 100644 test/cmdlineTests/linker_mode_invalid_option_optimize_yul/input.bin create mode 100644 test/cmdlineTests/linker_mode_invalid_option_yul_optimizations/args create mode 100644 test/cmdlineTests/linker_mode_invalid_option_yul_optimizations/err create mode 100644 test/cmdlineTests/linker_mode_invalid_option_yul_optimizations/exit create mode 100644 test/cmdlineTests/linker_mode_invalid_option_yul_optimizations/input.bin create mode 100644 test/cmdlineTests/standard_invalid_option_no_optimize_yul/args create mode 100644 test/cmdlineTests/standard_invalid_option_no_optimize_yul/err create mode 100644 test/cmdlineTests/standard_invalid_option_no_optimize_yul/exit create mode 100644 test/cmdlineTests/standard_invalid_option_no_optimize_yul/input.json create mode 100644 test/cmdlineTests/standard_invalid_option_optimize/args create mode 100644 test/cmdlineTests/standard_invalid_option_optimize/err create mode 100644 test/cmdlineTests/standard_invalid_option_optimize/exit create mode 100644 test/cmdlineTests/standard_invalid_option_optimize/input.json create mode 100644 test/cmdlineTests/standard_invalid_option_optimize_runs/args create mode 100644 test/cmdlineTests/standard_invalid_option_optimize_runs/err create mode 100644 test/cmdlineTests/standard_invalid_option_optimize_runs/exit create mode 100644 test/cmdlineTests/standard_invalid_option_optimize_runs/input.json create mode 100644 test/cmdlineTests/standard_invalid_option_optimize_yul/args create mode 100644 test/cmdlineTests/standard_invalid_option_optimize_yul/err create mode 100644 test/cmdlineTests/standard_invalid_option_optimize_yul/exit create mode 100644 test/cmdlineTests/standard_invalid_option_optimize_yul/input.json create mode 100644 test/cmdlineTests/standard_invalid_option_yul_optimizations/args create mode 100644 test/cmdlineTests/standard_invalid_option_yul_optimizations/err create mode 100644 test/cmdlineTests/standard_invalid_option_yul_optimizations/exit create mode 100644 test/cmdlineTests/standard_invalid_option_yul_optimizations/input.json diff --git a/Changelog.md b/Changelog.md index 04e443d62..679433724 100644 --- a/Changelog.md +++ b/Changelog.md @@ -12,11 +12,12 @@ Compiler Features: * SMTChecker: Support low level ``call`` as external calls to unknown code. * SMTChecker: Add constraints to better correlate ``address(this).balance`` and ``msg.value``. * SMTChecker: Support the ``value`` option for external function calls. - * Commandline Interface: Disallowed the ``--experimental-via-ir`` option to be used with Standard Json, Assembler and Linker modes. Bugfixes: * Code Generator: Use stable source order for ABI functions. + * Commandline Interface: Report optimizer options as invalid in Standard JSON and linker modes instead of ignoring them. + * Commandline Interface: Disallow the ``--experimental-via-ir`` option in Standard JSON, Assembler and Linker modes. * Opcode Optimizer: Prevent the optimizer from running multiple times to avoid potential bytecode differences for referenced code. * Name Resolver: Fix that when importing an aliased symbol using ``import {AliasedName} from "a.sol"`` it would use the original name of the symbol and not the aliased one. * SMTChecker: Fix false negative caused by ``push`` on storage array references returned by internal functions. diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index f2ffa8a0a..2d881c826 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -940,6 +940,26 @@ General Information)").c_str(), if (!parseInputPathsAndRemappings()) return false; + if ( + m_options.input.mode != InputMode::Compiler && + m_options.input.mode != InputMode::CompilerWithASTImport && + m_options.input.mode != InputMode::Assembler + ) + { + if (!m_args[g_strOptimizeRuns].defaulted()) + { + serr() << "Option --" << g_strOptimizeRuns << " is only valid in compiler and assembler modes." << endl; + return false; + } + + for (string const& option: {g_strOptimize, g_strNoOptimizeYul, g_strOptimizeYul, g_strYulOptimizations}) + if (m_args.count(option) > 0) + { + serr() << "Option --" << option << " is only valid in compiler and assembler modes." << endl; + return false; + } + } + if (m_options.input.mode == InputMode::StandardJson) return true; diff --git a/test/cmdlineTests/linker_mode_invalid_option_no_optimize_yul/args b/test/cmdlineTests/linker_mode_invalid_option_no_optimize_yul/args new file mode 100644 index 000000000..fbab96f26 --- /dev/null +++ b/test/cmdlineTests/linker_mode_invalid_option_no_optimize_yul/args @@ -0,0 +1 @@ +--no-optimize-yul --link --libraries input.sol:L=0x1234567890123456789012345678901234567890 diff --git a/test/cmdlineTests/linker_mode_invalid_option_no_optimize_yul/err b/test/cmdlineTests/linker_mode_invalid_option_no_optimize_yul/err new file mode 100644 index 000000000..7493f5926 --- /dev/null +++ b/test/cmdlineTests/linker_mode_invalid_option_no_optimize_yul/err @@ -0,0 +1 @@ +Option --no-optimize-yul is only valid in compiler and assembler modes. diff --git a/test/cmdlineTests/linker_mode_invalid_option_no_optimize_yul/exit b/test/cmdlineTests/linker_mode_invalid_option_no_optimize_yul/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/linker_mode_invalid_option_no_optimize_yul/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/linker_mode_invalid_option_no_optimize_yul/input.bin b/test/cmdlineTests/linker_mode_invalid_option_no_optimize_yul/input.bin new file mode 100644 index 000000000..e69de29bb diff --git a/test/cmdlineTests/linker_mode_invalid_option_optimize/args b/test/cmdlineTests/linker_mode_invalid_option_optimize/args new file mode 100644 index 000000000..bddcf43f6 --- /dev/null +++ b/test/cmdlineTests/linker_mode_invalid_option_optimize/args @@ -0,0 +1 @@ +--optimize --link --libraries input.sol:L=0x1234567890123456789012345678901234567890 diff --git a/test/cmdlineTests/linker_mode_invalid_option_optimize/err b/test/cmdlineTests/linker_mode_invalid_option_optimize/err new file mode 100644 index 000000000..4b86fcfcd --- /dev/null +++ b/test/cmdlineTests/linker_mode_invalid_option_optimize/err @@ -0,0 +1 @@ +Option --optimize is only valid in compiler and assembler modes. diff --git a/test/cmdlineTests/linker_mode_invalid_option_optimize/exit b/test/cmdlineTests/linker_mode_invalid_option_optimize/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/linker_mode_invalid_option_optimize/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/linker_mode_invalid_option_optimize/input.bin b/test/cmdlineTests/linker_mode_invalid_option_optimize/input.bin new file mode 100644 index 000000000..e69de29bb diff --git a/test/cmdlineTests/linker_mode_invalid_option_optimize_runs/args b/test/cmdlineTests/linker_mode_invalid_option_optimize_runs/args new file mode 100644 index 000000000..a6de8f8c4 --- /dev/null +++ b/test/cmdlineTests/linker_mode_invalid_option_optimize_runs/args @@ -0,0 +1 @@ +--optimize-runs 1000 --link --libraries input.sol:L=0x1234567890123456789012345678901234567890 diff --git a/test/cmdlineTests/linker_mode_invalid_option_optimize_runs/err b/test/cmdlineTests/linker_mode_invalid_option_optimize_runs/err new file mode 100644 index 000000000..624b8f62e --- /dev/null +++ b/test/cmdlineTests/linker_mode_invalid_option_optimize_runs/err @@ -0,0 +1 @@ +Option --optimize-runs is only valid in compiler and assembler modes. diff --git a/test/cmdlineTests/linker_mode_invalid_option_optimize_runs/exit b/test/cmdlineTests/linker_mode_invalid_option_optimize_runs/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/linker_mode_invalid_option_optimize_runs/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/linker_mode_invalid_option_optimize_runs/input.bin b/test/cmdlineTests/linker_mode_invalid_option_optimize_runs/input.bin new file mode 100644 index 000000000..e69de29bb diff --git a/test/cmdlineTests/linker_mode_invalid_option_optimize_yul/args b/test/cmdlineTests/linker_mode_invalid_option_optimize_yul/args new file mode 100644 index 000000000..50eac8159 --- /dev/null +++ b/test/cmdlineTests/linker_mode_invalid_option_optimize_yul/args @@ -0,0 +1 @@ +--optimize-yul --link --libraries input.sol:L=0x1234567890123456789012345678901234567890 diff --git a/test/cmdlineTests/linker_mode_invalid_option_optimize_yul/err b/test/cmdlineTests/linker_mode_invalid_option_optimize_yul/err new file mode 100644 index 000000000..5efb6abf8 --- /dev/null +++ b/test/cmdlineTests/linker_mode_invalid_option_optimize_yul/err @@ -0,0 +1 @@ +Option --optimize-yul is only valid in compiler and assembler modes. diff --git a/test/cmdlineTests/linker_mode_invalid_option_optimize_yul/exit b/test/cmdlineTests/linker_mode_invalid_option_optimize_yul/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/linker_mode_invalid_option_optimize_yul/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/linker_mode_invalid_option_optimize_yul/input.bin b/test/cmdlineTests/linker_mode_invalid_option_optimize_yul/input.bin new file mode 100644 index 000000000..e69de29bb diff --git a/test/cmdlineTests/linker_mode_invalid_option_yul_optimizations/args b/test/cmdlineTests/linker_mode_invalid_option_yul_optimizations/args new file mode 100644 index 000000000..1dc92992b --- /dev/null +++ b/test/cmdlineTests/linker_mode_invalid_option_yul_optimizations/args @@ -0,0 +1 @@ +--yul-optimizations a --link --libraries input.sol:L=0x1234567890123456789012345678901234567890 diff --git a/test/cmdlineTests/linker_mode_invalid_option_yul_optimizations/err b/test/cmdlineTests/linker_mode_invalid_option_yul_optimizations/err new file mode 100644 index 000000000..779736122 --- /dev/null +++ b/test/cmdlineTests/linker_mode_invalid_option_yul_optimizations/err @@ -0,0 +1 @@ +Option --yul-optimizations is only valid in compiler and assembler modes. diff --git a/test/cmdlineTests/linker_mode_invalid_option_yul_optimizations/exit b/test/cmdlineTests/linker_mode_invalid_option_yul_optimizations/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/linker_mode_invalid_option_yul_optimizations/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/linker_mode_invalid_option_yul_optimizations/input.bin b/test/cmdlineTests/linker_mode_invalid_option_yul_optimizations/input.bin new file mode 100644 index 000000000..e69de29bb diff --git a/test/cmdlineTests/standard_invalid_option_no_optimize_yul/args b/test/cmdlineTests/standard_invalid_option_no_optimize_yul/args new file mode 100644 index 000000000..de395419b --- /dev/null +++ b/test/cmdlineTests/standard_invalid_option_no_optimize_yul/args @@ -0,0 +1 @@ +--no-optimize-yul diff --git a/test/cmdlineTests/standard_invalid_option_no_optimize_yul/err b/test/cmdlineTests/standard_invalid_option_no_optimize_yul/err new file mode 100644 index 000000000..7493f5926 --- /dev/null +++ b/test/cmdlineTests/standard_invalid_option_no_optimize_yul/err @@ -0,0 +1 @@ +Option --no-optimize-yul is only valid in compiler and assembler modes. diff --git a/test/cmdlineTests/standard_invalid_option_no_optimize_yul/exit b/test/cmdlineTests/standard_invalid_option_no_optimize_yul/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/standard_invalid_option_no_optimize_yul/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/standard_invalid_option_no_optimize_yul/input.json b/test/cmdlineTests/standard_invalid_option_no_optimize_yul/input.json new file mode 100644 index 000000000..e69de29bb diff --git a/test/cmdlineTests/standard_invalid_option_optimize/args b/test/cmdlineTests/standard_invalid_option_optimize/args new file mode 100644 index 000000000..0ba259dbf --- /dev/null +++ b/test/cmdlineTests/standard_invalid_option_optimize/args @@ -0,0 +1 @@ +--optimize diff --git a/test/cmdlineTests/standard_invalid_option_optimize/err b/test/cmdlineTests/standard_invalid_option_optimize/err new file mode 100644 index 000000000..4b86fcfcd --- /dev/null +++ b/test/cmdlineTests/standard_invalid_option_optimize/err @@ -0,0 +1 @@ +Option --optimize is only valid in compiler and assembler modes. diff --git a/test/cmdlineTests/standard_invalid_option_optimize/exit b/test/cmdlineTests/standard_invalid_option_optimize/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/standard_invalid_option_optimize/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/standard_invalid_option_optimize/input.json b/test/cmdlineTests/standard_invalid_option_optimize/input.json new file mode 100644 index 000000000..e69de29bb diff --git a/test/cmdlineTests/standard_invalid_option_optimize_runs/args b/test/cmdlineTests/standard_invalid_option_optimize_runs/args new file mode 100644 index 000000000..c9d29f534 --- /dev/null +++ b/test/cmdlineTests/standard_invalid_option_optimize_runs/args @@ -0,0 +1 @@ +--optimize-runs 1000 diff --git a/test/cmdlineTests/standard_invalid_option_optimize_runs/err b/test/cmdlineTests/standard_invalid_option_optimize_runs/err new file mode 100644 index 000000000..624b8f62e --- /dev/null +++ b/test/cmdlineTests/standard_invalid_option_optimize_runs/err @@ -0,0 +1 @@ +Option --optimize-runs is only valid in compiler and assembler modes. diff --git a/test/cmdlineTests/standard_invalid_option_optimize_runs/exit b/test/cmdlineTests/standard_invalid_option_optimize_runs/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/standard_invalid_option_optimize_runs/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/standard_invalid_option_optimize_runs/input.json b/test/cmdlineTests/standard_invalid_option_optimize_runs/input.json new file mode 100644 index 000000000..e69de29bb diff --git a/test/cmdlineTests/standard_invalid_option_optimize_yul/args b/test/cmdlineTests/standard_invalid_option_optimize_yul/args new file mode 100644 index 000000000..9625ac425 --- /dev/null +++ b/test/cmdlineTests/standard_invalid_option_optimize_yul/args @@ -0,0 +1 @@ +--optimize-yul diff --git a/test/cmdlineTests/standard_invalid_option_optimize_yul/err b/test/cmdlineTests/standard_invalid_option_optimize_yul/err new file mode 100644 index 000000000..5efb6abf8 --- /dev/null +++ b/test/cmdlineTests/standard_invalid_option_optimize_yul/err @@ -0,0 +1 @@ +Option --optimize-yul is only valid in compiler and assembler modes. diff --git a/test/cmdlineTests/standard_invalid_option_optimize_yul/exit b/test/cmdlineTests/standard_invalid_option_optimize_yul/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/standard_invalid_option_optimize_yul/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/standard_invalid_option_optimize_yul/input.json b/test/cmdlineTests/standard_invalid_option_optimize_yul/input.json new file mode 100644 index 000000000..e69de29bb diff --git a/test/cmdlineTests/standard_invalid_option_yul_optimizations/args b/test/cmdlineTests/standard_invalid_option_yul_optimizations/args new file mode 100644 index 000000000..f72079a37 --- /dev/null +++ b/test/cmdlineTests/standard_invalid_option_yul_optimizations/args @@ -0,0 +1 @@ +--yul-optimizations a diff --git a/test/cmdlineTests/standard_invalid_option_yul_optimizations/err b/test/cmdlineTests/standard_invalid_option_yul_optimizations/err new file mode 100644 index 000000000..779736122 --- /dev/null +++ b/test/cmdlineTests/standard_invalid_option_yul_optimizations/err @@ -0,0 +1 @@ +Option --yul-optimizations is only valid in compiler and assembler modes. diff --git a/test/cmdlineTests/standard_invalid_option_yul_optimizations/exit b/test/cmdlineTests/standard_invalid_option_yul_optimizations/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/standard_invalid_option_yul_optimizations/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/standard_invalid_option_yul_optimizations/input.json b/test/cmdlineTests/standard_invalid_option_yul_optimizations/input.json new file mode 100644 index 000000000..e69de29bb diff --git a/test/solc/CommandLineParser.cpp b/test/solc/CommandLineParser.cpp index 1e3a53162..26c620f03 100644 --- a/test/solc/CommandLineParser.cpp +++ b/test/solc/CommandLineParser.cpp @@ -368,9 +368,6 @@ BOOST_AUTO_TEST_CASE(standard_json_mode_options) "--combined-json=abi,bin", // Accepted but has no effect in Standard JSON mode "--metadata-hash=swarm", // Ignored in Standard JSON mode "--metadata-literal", // Ignored in Standard JSON mode - "--optimize", // Ignored in Standard JSON mode - "--optimize-runs=1000", // Ignored in Standard JSON mode - "--yul-optimizations=agf", "--model-checker-contracts=" // Ignored in Standard JSON mode "contract1.yul:A," "contract2.yul:B", From 2f663c5f36c9d6e95c5fb8f7a99db2d655d26bfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 3 Aug 2021 16:20:44 +0200 Subject: [PATCH 070/232] Common processing of optimization options in compiler and assembly modes --- solc/CommandLineParser.cpp | 93 +++++++++++++++----------------------- 1 file changed, 37 insertions(+), 56 deletions(-) diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 2d881c826..547bba399 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -983,6 +983,43 @@ General Information)").c_str(), m_options.output.evmVersion = *versionOption; } + m_options.optimizer.enabled = (m_args.count(g_strOptimize) > 0); + m_options.optimizer.noOptimizeYul = (m_args.count(g_strNoOptimizeYul) > 0); + if (!m_args[g_strOptimizeRuns].defaulted()) + m_options.optimizer.expectedExecutionsPerDeployment = m_args.at(g_strOptimizeRuns).as(); + + OptimiserSettings optimiserSettings; + if (m_options.optimizer.enabled && m_options.input.mode == InputMode::Assembler) + optimiserSettings = OptimiserSettings::full(); + else if (m_options.optimizer.enabled) + optimiserSettings = OptimiserSettings::standard(); + else + optimiserSettings = OptimiserSettings::minimal(); + + if (m_options.optimizer.noOptimizeYul) + optimiserSettings.runYulOptimiser = false; + + if (m_args.count(g_strYulOptimizations)) + { + if (!optimiserSettings.runYulOptimiser) + { + serr() << "--" << g_strYulOptimizations << " is invalid if Yul optimizer is disabled" << endl; + return false; + } + + try + { + yul::OptimiserSuite::validateSequence(m_args[g_strYulOptimizations].as()); + } + catch (yul::OptimizerException const& _exception) + { + serr() << "Invalid optimizer step sequence in --" << g_strYulOptimizations << ": " << _exception.what() << endl; + return false; + } + + m_options.optimizer.yulSteps = m_args[g_strYulOptimizations].as(); + } + if (m_options.input.mode == InputMode::Assembler) { vector const nonAssemblyModeOptions = { @@ -1010,32 +1047,6 @@ General Information)").c_str(), using Input = yul::AssemblyStack::Language; using Machine = yul::AssemblyStack::Machine; m_options.assembly.inputLanguage = m_args.count(g_strYul) ? Input::Yul : (m_args.count(g_strStrictAssembly) ? Input::StrictAssembly : Input::Assembly); - m_options.optimizer.enabled = (m_args.count(g_strOptimize) > 0); - m_options.optimizer.noOptimizeYul = (m_args.count(g_strNoOptimizeYul) > 0); - - if (!m_args[g_strOptimizeRuns].defaulted()) - m_options.optimizer.expectedExecutionsPerDeployment = m_args.at(g_strOptimizeRuns).as(); - - if (m_args.count(g_strYulOptimizations)) - { - if (!m_options.optimizer.enabled) - { - serr() << "--" << g_strYulOptimizations << " is invalid if Yul optimizer is disabled" << endl; - return false; - } - - try - { - yul::OptimiserSuite::validateSequence(m_args[g_strYulOptimizations].as()); - } - catch (yul::OptimizerException const& _exception) - { - serr() << "Invalid optimizer step sequence in --" << g_strYulOptimizations << ": " << _exception.what() << endl; - return false; - } - - m_options.optimizer.yulSteps = m_args[g_strYulOptimizations].as(); - } if (m_args.count(g_strMachine)) { @@ -1184,36 +1195,6 @@ General Information)").c_str(), m_args.count(g_strModelCheckerTargets) || m_args.count(g_strModelCheckerTimeout); m_options.output.experimentalViaIR = (m_args.count(g_strExperimentalViaIR) > 0); - if (!m_args[g_strOptimizeRuns].defaulted()) - m_options.optimizer.expectedExecutionsPerDeployment = m_args.at(g_strOptimizeRuns).as(); - - m_options.optimizer.enabled = (m_args.count(g_strOptimize) > 0); - m_options.optimizer.noOptimizeYul = (m_args.count(g_strNoOptimizeYul) > 0); - - OptimiserSettings settings = m_options.optimizer.enabled ? OptimiserSettings::standard() : OptimiserSettings::minimal(); - if (m_options.optimizer.noOptimizeYul) - settings.runYulOptimiser = false; - if (m_args.count(g_strYulOptimizations)) - { - if (!settings.runYulOptimiser) - { - serr() << "--" << g_strYulOptimizations << " is invalid if Yul optimizer is disabled" << endl; - return false; - } - - try - { - yul::OptimiserSuite::validateSequence(m_args[g_strYulOptimizations].as()); - } - catch (yul::OptimizerException const& _exception) - { - serr() << "Invalid optimizer step sequence in --" << g_strYulOptimizations << ": " << _exception.what() << endl; - return false; - } - - m_options.optimizer.yulSteps = m_args[g_strYulOptimizations].as(); - } - if (m_options.input.mode == InputMode::Compiler) m_options.input.errorRecovery = (m_args.count(g_strErrorRecovery) > 0); From 6b46d4fdbeaa08bae27f7bff42c72983bd7f37d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 3 Aug 2021 17:11:17 +0200 Subject: [PATCH 071/232] Extract duplicated code for initializing OptimiserSettings from CommandLineOptions into a common function --- solc/CommandLineInterface.cpp | 43 +++++++++-------------------------- solc/CommandLineInterface.h | 8 +------ solc/CommandLineParser.cpp | 35 +++++++++++++++++++--------- solc/CommandLineParser.h | 2 +- 4 files changed, 37 insertions(+), 51 deletions(-) diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 549991d61..275451114 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -551,13 +551,7 @@ bool CommandLineInterface::processInput() } case InputMode::Assembler: { - return assemble( - m_options.assembly.inputLanguage, - m_options.assembly.targetMachine, - m_options.optimizer.enabled, - m_options.optimizer.expectedExecutionsPerDeployment, - m_options.optimizer.yulSteps - ); + return assemble(m_options.assembly.inputLanguage, m_options.assembly.targetMachine); } case InputMode::Linker: return link(); @@ -595,16 +589,7 @@ bool CommandLineInterface::compile() m_compiler->enableIRGeneration(m_options.compiler.outputs.ir || m_options.compiler.outputs.irOptimized); m_compiler->enableEwasmGeneration(m_options.compiler.outputs.ewasm); - OptimiserSettings settings = m_options.optimizer.enabled ? OptimiserSettings::standard() : OptimiserSettings::minimal(); - if (m_options.optimizer.expectedExecutionsPerDeployment.has_value()) - settings.expectedExecutionsPerDeployment = m_options.optimizer.expectedExecutionsPerDeployment.value(); - if (m_options.optimizer.noOptimizeYul) - settings.runYulOptimiser = false; - - if (m_options.optimizer.yulSteps.has_value()) - settings.yulOptimiserSteps = m_options.optimizer.yulSteps.value(); - settings.optimizeStackAllocation = settings.runYulOptimiser; - m_compiler->setOptimiserSettings(settings); + m_compiler->setOptimiserSettings(m_options.optimiserSettings()); if (m_options.input.mode == InputMode::CompilerWithASTImport) { @@ -939,27 +924,21 @@ string CommandLineInterface::objectWithLinkRefsHex(evmasm::LinkerObject const& _ return out; } -bool CommandLineInterface::assemble( - yul::AssemblyStack::Language _language, - yul::AssemblyStack::Machine _targetMachine, - bool _optimize, - optional _expectedExecutionsPerDeployment, - optional _yulOptimiserSteps -) +bool CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul::AssemblyStack::Machine _targetMachine) { - solAssert(_optimize || !_yulOptimiserSteps.has_value(), ""); - bool successful = true; map assemblyStacks; for (auto const& src: m_fileReader.sourceCodes()) { - OptimiserSettings settings = _optimize ? OptimiserSettings::full() : OptimiserSettings::minimal(); - if (_expectedExecutionsPerDeployment.has_value()) - settings.expectedExecutionsPerDeployment = _expectedExecutionsPerDeployment.value(); - if (_yulOptimiserSteps.has_value()) - settings.yulOptimiserSteps = _yulOptimiserSteps.value(); + // --no-optimize-yul option is not accepted in assembly mode. + solAssert(!m_options.optimizer.noOptimizeYul, ""); + + auto& stack = assemblyStacks[src.first] = yul::AssemblyStack( + m_options.output.evmVersion, + _language, + m_options.optimiserSettings() + ); - auto& stack = assemblyStacks[src.first] = yul::AssemblyStack(m_options.output.evmVersion, _language, settings); try { if (!stack.parseAndAnalyze(src.first, src.second)) diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 488ec1d71..582b8f2a4 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -74,13 +74,7 @@ private: /// @returns the full object with library placeholder hints in hex. static std::string objectWithLinkRefsHex(evmasm::LinkerObject const& _obj); - bool assemble( - yul::AssemblyStack::Language _language, - yul::AssemblyStack::Machine _targetMachine, - bool _optimize, - std::optional _expectedExecutionsPerDeployment = std::nullopt, - std::optional _yulOptimiserSteps = std::nullopt - ); + bool assemble(yul::AssemblyStack::Language _language, yul::AssemblyStack::Machine _targetMachine); void outputCompilationResults(); diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 547bba399..bccd95a0b 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -302,6 +302,29 @@ bool CommandLineOptions::operator==(CommandLineOptions const& _other) const noex modelChecker.settings == _other.modelChecker.settings; } +OptimiserSettings CommandLineOptions::optimiserSettings() const +{ + OptimiserSettings settings; + + if (optimizer.enabled && input.mode == InputMode::Assembler) + settings = OptimiserSettings::full(); + else if (optimizer.enabled) + settings = OptimiserSettings::standard(); + else + settings = OptimiserSettings::minimal(); + + if (optimizer.noOptimizeYul) + settings.runYulOptimiser = false; + + if (optimizer.expectedExecutionsPerDeployment.has_value()) + settings.expectedExecutionsPerDeployment = optimizer.expectedExecutionsPerDeployment.value(); + + if (optimizer.yulSteps.has_value()) + settings.yulOptimiserSteps = optimizer.yulSteps.value(); + + return settings; +} + bool CommandLineParser::parseInputPathsAndRemappings() { m_options.input.ignoreMissingFiles = (m_args.count(g_strIgnoreMissingFiles) > 0); @@ -988,19 +1011,9 @@ General Information)").c_str(), if (!m_args[g_strOptimizeRuns].defaulted()) m_options.optimizer.expectedExecutionsPerDeployment = m_args.at(g_strOptimizeRuns).as(); - OptimiserSettings optimiserSettings; - if (m_options.optimizer.enabled && m_options.input.mode == InputMode::Assembler) - optimiserSettings = OptimiserSettings::full(); - else if (m_options.optimizer.enabled) - optimiserSettings = OptimiserSettings::standard(); - else - optimiserSettings = OptimiserSettings::minimal(); - - if (m_options.optimizer.noOptimizeYul) - optimiserSettings.runYulOptimiser = false; - if (m_args.count(g_strYulOptimizations)) { + OptimiserSettings optimiserSettings = m_options.optimiserSettings(); if (!optimiserSettings.runYulOptimiser) { serr() << "--" << g_strYulOptimizations << " is invalid if Yul optimizer is disabled" << endl; diff --git a/solc/CommandLineParser.h b/solc/CommandLineParser.h index 423dacb5f..ac80f6f0d 100644 --- a/solc/CommandLineParser.h +++ b/solc/CommandLineParser.h @@ -102,6 +102,7 @@ struct CommandLineOptions bool operator==(CommandLineOptions const& _other) const noexcept; bool operator!=(CommandLineOptions const& _other) const noexcept { return !(*this == _other); } + OptimiserSettings optimiserSettings() const; struct { @@ -169,7 +170,6 @@ struct CommandLineOptions bool initialize = false; ModelCheckerSettings settings; } modelChecker; - }; /// Parses the command-line arguments and produces a filled-out CommandLineOptions structure. From 1e4cef84058e81bb45be7e533c810492f70e9537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 17 Aug 2021 12:50:48 +0200 Subject: [PATCH 072/232] Switch from full() to standard() optimizer settings in assembly mode on the CLI --- solc/CommandLineParser.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index bccd95a0b..220f0e393 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -306,9 +306,7 @@ OptimiserSettings CommandLineOptions::optimiserSettings() const { OptimiserSettings settings; - if (optimizer.enabled && input.mode == InputMode::Assembler) - settings = OptimiserSettings::full(); - else if (optimizer.enabled) + if (optimizer.enabled) settings = OptimiserSettings::standard(); else settings = OptimiserSettings::minimal(); From 00bfed4d8bfcae9de01db1d520c00e5f28c543ab Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 13 Sep 2021 16:49:52 +0200 Subject: [PATCH 073/232] UserDefinedValueType: test to validate zero-cost-abstraction claim. Seems that the optimizer can indeed make it a zero-cost-abstraction! --- ...cost_abstraction_comparison_elementary.sol | 37 ++++++++++++++++++ ...ost_abstraction_comparison_userdefined.sol | 38 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/zero_cost_abstraction_comparison_elementary.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/zero_cost_abstraction_comparison_userdefined.sol diff --git a/test/libsolidity/semanticTests/userDefinedValueType/zero_cost_abstraction_comparison_elementary.sol b/test/libsolidity/semanticTests/userDefinedValueType/zero_cost_abstraction_comparison_elementary.sol new file mode 100644 index 000000000..d7b9db30b --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/zero_cost_abstraction_comparison_elementary.sol @@ -0,0 +1,37 @@ +// a test to compare the cost between using user defined value types and elementary type. See the +// test zero_cost_abstraction_userdefined.sol for a comparison. + +pragma abicoder v2; + +contract C { + int x; + function setX(int _x) external { + x = _x; + } + function getX() view external returns (int) { + return x; + } + function add(int a, int b) view external returns (int) { + return a + b; + } +} + +// ==== +// compileViaYul: also +// ---- +// getX() -> 0 +// gas irOptimized: 23353 +// gas legacy: 23479 +// gas legacyOptimized: 23311 +// setX(int256): 5 -> +// gas irOptimized: 43511 +// gas legacy: 43724 +// gas legacyOptimized: 43516 +// getX() -> 5 +// gas irOptimized: 23353 +// gas legacy: 23479 +// gas legacyOptimized: 23311 +// add(int256,int256): 200, 99 -> 299 +// gas irOptimized: 21794 +// gas legacy: 22394 +// gas legacyOptimized: 21813 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/zero_cost_abstraction_comparison_userdefined.sol b/test/libsolidity/semanticTests/userDefinedValueType/zero_cost_abstraction_comparison_userdefined.sol new file mode 100644 index 000000000..29038a861 --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/zero_cost_abstraction_comparison_userdefined.sol @@ -0,0 +1,38 @@ +// a test to compare the cost between using user defined value types and elementary type. See the +// test zero_cost_abstraction_elementary.sol for comparison. + +pragma abicoder v2; + +type MyInt is int; +contract C { + int x; + function setX(MyInt _x) external { + x = MyInt.unwrap(_x); + } + function getX() view external returns (MyInt) { + return MyInt.wrap(x); + } + function add(MyInt a, MyInt b) pure external returns(MyInt) { + return MyInt.wrap(MyInt.unwrap(a) + MyInt.unwrap(b)); + } +} + +// ==== +// compileViaYul: also +// ---- +// getX() -> 0 +// gas irOptimized: 23353 +// gas legacy: 23608 +// gas legacyOptimized: 23311 +// setX(int256): 5 -> +// gas irOptimized: 43511 +// gas legacy: 43724 +// gas legacyOptimized: 43516 +// getX() -> 5 +// gas irOptimized: 23353 +// gas legacy: 23608 +// gas legacyOptimized: 23311 +// add(int256,int256): 200, 99 -> 299 +// gas irOptimized: 21794 +// gas legacy: 22523 +// gas legacyOptimized: 21813 From 4871017aae6b9ee37a6bf938227ca8a21bb46ff8 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Mon, 13 Sep 2021 17:12:50 +0200 Subject: [PATCH 074/232] Added an abi function test for UserDefinedValueType A test to see if `abi.encode*(..., (CustomType))` and `abi.decode(..., (CustomType))` works as intended. --- .../userDefinedValueType/abicodec.sol | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/abicodec.sol diff --git a/test/libsolidity/semanticTests/userDefinedValueType/abicodec.sol b/test/libsolidity/semanticTests/userDefinedValueType/abicodec.sol new file mode 100644 index 000000000..65c604d1b --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/abicodec.sol @@ -0,0 +1,36 @@ +// A test to see if `abi.encodeWithSelector(..., (CustomType))` works as intended. +contract C { + type MyInt is int; + function f(MyInt x) external returns(MyInt a, MyInt b, MyInt c, MyInt d) { + a = MyInt.wrap(-1); + b = MyInt.wrap(0); + c = MyInt.wrap(1); + d = x; + } + function g() external returns(bool) { + (bool success1, bytes memory ret1) = address(this).call(abi.encodeWithSelector(this.f.selector, MyInt.wrap(5))); + assert(success1); + + (MyInt a1, MyInt b1, MyInt c1, MyInt d1) = abi.decode(ret1, (MyInt, MyInt, MyInt, MyInt)); + assert(MyInt.unwrap(a1) == -1); + assert(MyInt.unwrap(b1) == 0); + assert(MyInt.unwrap(c1) == 1); + assert(MyInt.unwrap(d1) == 5); + + (bool success2, bytes memory ret2) = address(this).call(abi.encodeWithSelector(this.f.selector, int(-5))); + assert(success2); + + (int a2, int b2, int c2, int d2) = abi.decode(ret2, (int, int, int, int)); + assert(a2 == -1); + assert(b2 == 0); + assert(c2 == 1); + assert(d2 == -5); + + return true; + } +} +// ==== +// compileViaYul: also +// EVMVersion: >=byzantium +// ---- +// g() -> true From 7fcf888fbfd625b1576e30ce9c80b8b8221cbdaf Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Mon, 13 Sep 2021 18:59:18 +0200 Subject: [PATCH 075/232] Remove unused AssemblyItemType::PushString. --- libevmasm/Assembly.cpp | 17 ----------------- libevmasm/AssemblyItem.cpp | 10 ---------- libevmasm/AssemblyItem.h | 1 - libevmasm/GasMeter.cpp | 1 - libevmasm/PeepholeOptimiser.cpp | 2 +- libevmasm/SemanticInformation.cpp | 1 - 6 files changed, 1 insertion(+), 31 deletions(-) diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 1e05cd82e..acf655c82 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -250,10 +250,6 @@ Json::Value Assembly::assemblyJSON(map const& _sourceIndices) collection.append( createJsonValue("PUSH", sourceIndex, i.location().start, i.location().end, toStringInHex(i.data()), i.getJumpTypeAsString())); break; - case PushString: - collection.append( - createJsonValue("PUSH tag", sourceIndex, i.location().start, i.location().end, m_strings.at(h256(i.data())))); - break; case PushTag: if (i.data() == 0) collection.append( @@ -621,19 +617,6 @@ LinkerObject const& Assembly::assemble() const case Operation: ret.bytecode.push_back(static_cast(i.instruction())); break; - case PushString: - { - ret.bytecode.push_back(static_cast(Instruction::PUSH32)); - unsigned ii = 0; - for (auto j: m_strings.at(h256(i.data()))) - if (++ii > 32) - break; - else - ret.bytecode.push_back(uint8_t(j)); - while (ii++ < 32) - ret.bytecode.push_back(0); - break; - } case Push: { unsigned b = max(1, util::bytesRequired(i.data())); diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index 75c0e4dca..462199ba4 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -70,8 +70,6 @@ size_t AssemblyItem::bytesRequired(size_t _addressLength) const case Operation: case Tag: // 1 byte for the JUMPDEST return 1; - case PushString: - return 1 + 32; case Push: return 1 + max(1, util::bytesRequired(data())); case PushSubSize: @@ -118,7 +116,6 @@ size_t AssemblyItem::returnValues() const case Operation: return static_cast(instructionInfo(instruction()).ret); case Push: - case PushString: case PushTag: case PushData: case PushSub: @@ -147,7 +144,6 @@ bool AssemblyItem::canBeFunctional() const case Operation: return !isDupInstruction(instruction()) && !isSwapInstruction(instruction()); case Push: - case PushString: case PushTag: case PushData: case PushSub: @@ -195,9 +191,6 @@ string AssemblyItem::toAssemblyText(Assembly const& _assembly) const case Push: text = toHex(util::toCompactBigEndian(data(), 1), util::HexPrefix::Add); break; - case PushString: - text = string("data_") + util::toHex(data()); - break; case PushTag: { size_t sub{0}; @@ -276,9 +269,6 @@ ostream& solidity::evmasm::operator<<(ostream& _out, AssemblyItem const& _item) case Push: _out << " PUSH " << hex << _item.data() << dec; break; - case PushString: - _out << " PushString" << hex << (unsigned)_item.data() << dec; - break; case PushTag: { size_t subId = _item.splitForeignPushTag().first; diff --git a/libevmasm/AssemblyItem.h b/libevmasm/AssemblyItem.h index 5d810c02c..f1b2b5043 100644 --- a/libevmasm/AssemblyItem.h +++ b/libevmasm/AssemblyItem.h @@ -38,7 +38,6 @@ enum AssemblyItemType UndefinedItem, Operation, Push, - PushString, PushTag, PushSub, PushSubSize, diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp index 57a898f65..3ad9ba084 100644 --- a/libevmasm/GasMeter.cpp +++ b/libevmasm/GasMeter.cpp @@ -47,7 +47,6 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _ case Push: case PushTag: case PushData: - case PushString: case PushSub: case PushSubSize: case PushProgramSize: diff --git a/libevmasm/PeepholeOptimiser.cpp b/libevmasm/PeepholeOptimiser.cpp index 6df80dac8..0ee0b5efd 100644 --- a/libevmasm/PeepholeOptimiser.cpp +++ b/libevmasm/PeepholeOptimiser.cpp @@ -112,7 +112,7 @@ struct PushPop: SimplePeepholeOptimizerMethod auto t = _push.type(); return _pop == Instruction::POP && ( SemanticInformation::isDupInstruction(_push) || - t == Push || t == PushString || t == PushTag || t == PushSub || + t == Push || t == PushTag || t == PushSub || t == PushSubSize || t == PushProgramSize || t == PushData || t == PushLibraryAddress ); } diff --git a/libevmasm/SemanticInformation.cpp b/libevmasm/SemanticInformation.cpp index d3359c4f7..41dc07fcf 100644 --- a/libevmasm/SemanticInformation.cpp +++ b/libevmasm/SemanticInformation.cpp @@ -41,7 +41,6 @@ bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item, bool case VerbatimBytecode: return true; case Push: - case PushString: case PushTag: case PushSub: case PushSubSize: From e72fa7fc10f951d94310383deb9d11845928ceee Mon Sep 17 00:00:00 2001 From: Leo Alt Date: Wed, 30 Jun 2021 14:48:45 +0200 Subject: [PATCH 076/232] Add new info severity --- docs/security-considerations.rst | 4 ++ docs/using-the-compiler.rst | 5 +- liblangutil/ErrorReporter.cpp | 19 ++++++ liblangutil/ErrorReporter.h | 8 ++- liblangutil/Exceptions.cpp | 3 + liblangutil/Exceptions.h | 68 ++++++++++++++++--- liblangutil/ParserBase.h | 2 +- liblangutil/SourceReferenceExtractor.cpp | 8 +-- liblangutil/SourceReferenceExtractor.h | 6 +- liblangutil/SourceReferenceFormatter.cpp | 6 +- liblangutil/SourceReferenceFormatter.h | 4 +- libsolidity/analysis/ContractLevelChecker.cpp | 4 +- libsolidity/analysis/ControlFlowAnalyzer.cpp | 2 +- libsolidity/analysis/ControlFlowGraph.cpp | 2 +- libsolidity/analysis/PostTypeChecker.cpp | 4 +- .../analysis/PostTypeContractLevelChecker.cpp | 2 +- libsolidity/analysis/StaticAnalyzer.cpp | 2 +- libsolidity/analysis/SyntaxChecker.cpp | 2 +- libsolidity/analysis/TypeChecker.cpp | 2 +- libsolidity/interface/CompilerStack.cpp | 4 +- libsolidity/interface/StandardCompiler.cpp | 42 ++++++------ scripts/error_codes.py | 2 +- solc/CommandLineInterface.cpp | 2 +- test/libsolidity/AnalysisFramework.cpp | 12 ++-- test/libsolidity/AnalysisFramework.h | 4 +- test/libsolidity/Assembly.cpp | 8 +-- test/libsolidity/InlineAssembly.cpp | 2 +- test/libsolidity/SolidityParser.cpp | 2 +- test/libsolidity/StandardCompiler.cpp | 15 +++- test/libsolidity/SyntaxTest.cpp | 2 +- test/libyul/ControlFlowGraphTest.cpp | 2 +- test/libyul/ObjectParser.cpp | 14 ++-- test/libyul/Parser.cpp | 14 ++-- test/libyul/StackLayoutGeneratorTest.cpp | 2 +- test/libyul/YulOptimizerTest.cpp | 2 +- test/tools/ossfuzz/YulEvmoneInterface.cpp | 2 +- test/tools/ossfuzz/yulProtoFuzzer.cpp | 2 +- test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp | 2 +- 38 files changed, 191 insertions(+), 97 deletions(-) diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index 0fab056ff..09770c570 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -389,6 +389,10 @@ code. Always use the latest version of the compiler to be notified about all recently introduced warnings. +Messages of type ``info`` issued by the compiler are not dangerous, and simply +represent extra suggestions and optional information that the compiler thinks +might be useful to the user. + Restrict the Amount of Ether ============================ diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 2ca338041..5245991fd 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -437,7 +437,7 @@ Output Description .. code-block:: javascript { - // Optional: not present if no errors/warnings were encountered + // Optional: not present if no errors/warnings/infos were encountered "errors": [ { // Optional: Location within the source file. @@ -460,7 +460,7 @@ Output Description "type": "TypeError", // Mandatory: Component where the error originated, such as "general", "ewasm", etc. "component": "general", - // Mandatory ("error" or "warning") + // Mandatory ("error", "warning" or "info", but please note that this may be extended in the future) "severity": "error", // Optional: unique code for the cause of the error "errorCode": "3141", @@ -604,6 +604,7 @@ Error Types 11. ``CompilerError``: Invalid use of the compiler stack - this should be reported as an issue. 12. ``FatalError``: Fatal error not processed correctly - this should be reported as an issue. 13. ``Warning``: A warning, which didn't stop the compilation, but should be addressed if possible. +14. ``Info``: Information that the compiler thinks the user might find useful, but is not dangerous and does not necessarily need to be addressed. .. _compiler-tools: diff --git a/liblangutil/ErrorReporter.cpp b/liblangutil/ErrorReporter.cpp index 728c9dad9..02487034a 100644 --- a/liblangutil/ErrorReporter.cpp +++ b/liblangutil/ErrorReporter.cpp @@ -94,6 +94,16 @@ bool ErrorReporter::checkForExcessiveErrors(Error::Type _type) if (m_warningCount >= c_maxWarningsAllowed) return true; } + else if (_type == Error::Type::Info) + { + m_infoCount++; + + if (m_infoCount == c_maxInfosAllowed) + m_errorList.push_back(make_shared(2833_error, Error::Type::Info, "There are more than 256 infos. Ignoring the rest.")); + + if (m_infoCount >= c_maxInfosAllowed) + return true; + } else { m_errorCount++; @@ -242,3 +252,12 @@ void ErrorReporter::docstringParsingError(ErrorId _error, SourceLocation const& _description ); } + +void ErrorReporter::info( + ErrorId _error, + SourceLocation const& _location, + string const& _description +) +{ + error(_error, Error::Type::Info, _location, _description); +} diff --git a/liblangutil/ErrorReporter.h b/liblangutil/ErrorReporter.h index 7cdce0caa..6f91f0713 100644 --- a/liblangutil/ErrorReporter.h +++ b/liblangutil/ErrorReporter.h @@ -63,6 +63,8 @@ public: SecondarySourceLocation const& _secondaryLocation ); + void info(ErrorId _error, SourceLocation const& _location, std::string const& _description); + void error( ErrorId _error, Error::Type _type, @@ -118,13 +120,13 @@ public: void clear(); - /// @returns true iff there is any error (ignores warnings). + /// @returns true iff there is any error (ignores warnings and infos). bool hasErrors() const { return m_errorCount > 0; } - /// @returns the number of errors (ignores warnings). + /// @returns the number of errors (ignores warnings and infos). unsigned errorCount() const { return m_errorCount; @@ -183,9 +185,11 @@ private: unsigned m_errorCount = 0; unsigned m_warningCount = 0; + unsigned m_infoCount = 0; unsigned const c_maxWarningsAllowed = 256; unsigned const c_maxErrorsAllowed = 256; + unsigned const c_maxInfosAllowed = 256; }; } diff --git a/liblangutil/Exceptions.cpp b/liblangutil/Exceptions.cpp index 3caa81b1d..34aa69803 100644 --- a/liblangutil/Exceptions.cpp +++ b/liblangutil/Exceptions.cpp @@ -47,6 +47,9 @@ Error::Error( case Type::DocstringParsingError: m_typeName = "DocstringParsingError"; break; + case Type::Info: + m_typeName = "Info"; + break; case Type::ParserError: m_typeName = "ParserError"; break; diff --git a/liblangutil/Exceptions.h b/liblangutil/Exceptions.h index c7385bac8..68f109717 100644 --- a/liblangutil/Exceptions.h +++ b/liblangutil/Exceptions.h @@ -120,7 +120,15 @@ public: ParserError, TypeError, SyntaxError, - Warning + Warning, + Info + }; + + enum class Severity + { + Error, + Warning, + Info }; Error( @@ -139,21 +147,63 @@ public: static Error const* containsErrorOfType(ErrorList const& _list, Error::Type _type) { for (auto e: _list) - { if (e->type() == _type) return e.get(); - } return nullptr; } - static bool containsOnlyWarnings(ErrorList const& _list) + + static Severity errorSeverity(Type _type) + { + if (_type == Type::Info) + return Severity::Info; + if (_type == Type::Warning) + return Severity::Warning; + return Severity::Error; + } + + static bool isError(Severity _severity) + { + return _severity == Severity::Error; + } + + static bool isError(Type _type) + { + return isError(errorSeverity(_type)); + } + + static bool containsErrors(ErrorList const& _list) { for (auto e: _list) - { - if (e->type() != Type::Warning) - return false; - } - return true; + if (isError(e->type())) + return true; + return false; } + + static std::string formatErrorSeverity(Severity _severity) + { + if (_severity == Severity::Info) + return "Info"; + if (_severity == Severity::Warning) + return "Warning"; + solAssert(isError(_severity), ""); + return "Error"; + } + + static std::string formatErrorSeverityLowercase(Severity _severity) + { + switch (_severity) + { + case Severity::Info: + return "info"; + case Severity::Warning: + return "warning"; + case Severity::Error: + solAssert(isError(_severity), ""); + return "error"; + } + solAssert(false, ""); + } + private: ErrorId m_errorId; Type m_type; diff --git a/liblangutil/ParserBase.h b/liblangutil/ParserBase.h index 6c5ce081b..f72400f6c 100644 --- a/liblangutil/ParserBase.h +++ b/liblangutil/ParserBase.h @@ -104,7 +104,7 @@ protected: void fatalParserError(ErrorId _error, SourceLocation const& _location, std::string const& _description); std::shared_ptr m_scanner; - /// The reference to the list of errors and warning to add errors/warnings during parsing + /// The reference to the list of errors, warnings and infos to add errors/warnings/infos during parsing ErrorReporter& m_errorReporter; /// Current recursion depth during parsing. size_t m_recursionDepth = 0; diff --git a/liblangutil/SourceReferenceExtractor.cpp b/liblangutil/SourceReferenceExtractor.cpp index 717e590df..373ad6b18 100644 --- a/liblangutil/SourceReferenceExtractor.cpp +++ b/liblangutil/SourceReferenceExtractor.cpp @@ -30,7 +30,7 @@ using namespace solidity::langutil; SourceReferenceExtractor::Message SourceReferenceExtractor::extract( CharStreamProvider const& _charStreamProvider, util::Exception const& _exception, - string _category + string _severity ) { SourceLocation const* location = boost::get_error_info(_exception); @@ -44,7 +44,7 @@ SourceReferenceExtractor::Message SourceReferenceExtractor::extract( for (auto const& info: secondaryLocation->infos) secondary.emplace_back(extract(_charStreamProvider, &info.second, info.first)); - return Message{std::move(primary), _category, std::move(secondary), nullopt}; + return Message{std::move(primary), _severity, std::move(secondary), nullopt}; } SourceReferenceExtractor::Message SourceReferenceExtractor::extract( @@ -52,8 +52,8 @@ SourceReferenceExtractor::Message SourceReferenceExtractor::extract( Error const& _error ) { - string category = (_error.type() == Error::Type::Warning) ? "Warning" : "Error"; - Message message = extract(_charStreamProvider, _error, category); + string severity = Error::formatErrorSeverity(Error::errorSeverity(_error.type())); + Message message = extract(_charStreamProvider, _error, severity); message.errorId = _error.errorId(); return message; } diff --git a/liblangutil/SourceReferenceExtractor.h b/liblangutil/SourceReferenceExtractor.h index d26a941f5..6aeb6065e 100644 --- a/liblangutil/SourceReferenceExtractor.h +++ b/liblangutil/SourceReferenceExtractor.h @@ -41,7 +41,7 @@ struct LineColumn struct SourceReference { - std::string message; ///< A message that relates to this source reference (such as a warning or an error message). + std::string message; ///< A message that relates to this source reference (such as a warning, info or an error message). std::string sourceName; ///< Underlying source name (for example the filename). LineColumn position; ///< Actual (error) position this source reference is surrounding. bool multiline = {false}; ///< Indicates whether the actual SourceReference is truncated to one line. @@ -64,12 +64,12 @@ namespace SourceReferenceExtractor struct Message { SourceReference primary; - std::string category; // "Error", "Warning", ... + std::string severity; // "Error", "Warning", "Info", ... std::vector secondary; std::optional errorId; }; - Message extract(CharStreamProvider const& _charStreamProvider, util::Exception const& _exception, std::string _category); + Message extract(CharStreamProvider const& _charStreamProvider, util::Exception const& _exception, std::string _severity); Message extract(CharStreamProvider const& _charStreamProvider, Error const& _error); SourceReference extract(CharStreamProvider const& _charStreamProvider, SourceLocation const* _location, std::string message = ""); } diff --git a/liblangutil/SourceReferenceFormatter.cpp b/liblangutil/SourceReferenceFormatter.cpp index 20d0f3306..623e13dd1 100644 --- a/liblangutil/SourceReferenceFormatter.cpp +++ b/liblangutil/SourceReferenceFormatter.cpp @@ -164,7 +164,7 @@ void SourceReferenceFormatter::printSourceLocation(SourceReference const& _ref) void SourceReferenceFormatter::printExceptionInformation(SourceReferenceExtractor::Message const& _msg) { // exception header line - errorColored() << _msg.category; + errorColored() << _msg.severity; if (m_withErrorIds && _msg.errorId.has_value()) errorColored() << " (" << _msg.errorId.value().error << ")"; messageColored() << ": " << _msg.primary.message << '\n'; @@ -181,9 +181,9 @@ void SourceReferenceFormatter::printExceptionInformation(SourceReferenceExtracto m_stream << '\n'; } -void SourceReferenceFormatter::printExceptionInformation(util::Exception const& _exception, std::string const& _category) +void SourceReferenceFormatter::printExceptionInformation(util::Exception const& _exception, std::string const& _severity) { - printExceptionInformation(SourceReferenceExtractor::extract(m_charStreamProvider, _exception, _category)); + printExceptionInformation(SourceReferenceExtractor::extract(m_charStreamProvider, _exception, _severity)); } void SourceReferenceFormatter::printErrorInformation(ErrorList const& _errors) diff --git a/liblangutil/SourceReferenceFormatter.h b/liblangutil/SourceReferenceFormatter.h index fc1f418a2..5bac03a9a 100644 --- a/liblangutil/SourceReferenceFormatter.h +++ b/liblangutil/SourceReferenceFormatter.h @@ -52,7 +52,7 @@ public: /// Prints source location if it is given. void printSourceLocation(SourceReference const& _ref); void printExceptionInformation(SourceReferenceExtractor::Message const& _msg); - void printExceptionInformation(util::Exception const& _exception, std::string const& _category); + void printExceptionInformation(util::Exception const& _exception, std::string const& _severity); void printErrorInformation(langutil::ErrorList const& _errors); void printErrorInformation(Error const& _error); @@ -77,7 +77,7 @@ public: { return formatExceptionInformation( _error, - (_error.type() == Error::Type::Warning) ? "Warning" : "Error", + Error::formatErrorSeverity(Error::errorSeverity(_error.type())), _charStreamProvider ); } diff --git a/libsolidity/analysis/ContractLevelChecker.cpp b/libsolidity/analysis/ContractLevelChecker.cpp index 631545569..c159b8357 100644 --- a/libsolidity/analysis/ContractLevelChecker.cpp +++ b/libsolidity/analysis/ContractLevelChecker.cpp @@ -71,7 +71,7 @@ bool ContractLevelChecker::check(SourceUnit const& _sourceUnit) findDuplicateDefinitions( filterDeclarations(*_sourceUnit.annotation().exportedSymbols) ); - if (!Error::containsOnlyWarnings(m_errorReporter.errors())) + if (Error::containsErrors(m_errorReporter.errors())) noErrors = false; for (ASTPointer const& node: _sourceUnit.nodes()) if (ContractDefinition* contract = dynamic_cast(node.get())) @@ -97,7 +97,7 @@ bool ContractLevelChecker::check(ContractDefinition const& _contract) checkPayableFallbackWithoutReceive(_contract); checkStorageSize(_contract); - return Error::containsOnlyWarnings(m_errorReporter.errors()); + return !Error::containsErrors(m_errorReporter.errors()); } void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _contract) diff --git a/libsolidity/analysis/ControlFlowAnalyzer.cpp b/libsolidity/analysis/ControlFlowAnalyzer.cpp index 181943032..0c64ac3b5 100644 --- a/libsolidity/analysis/ControlFlowAnalyzer.cpp +++ b/libsolidity/analysis/ControlFlowAnalyzer.cpp @@ -36,7 +36,7 @@ bool ControlFlowAnalyzer::run() for (auto& [pair, flow]: m_cfg.allFunctionFlows()) analyze(*pair.function, pair.contract, *flow); - return Error::containsOnlyWarnings(m_errorReporter.errors()); + return !Error::containsErrors(m_errorReporter.errors()); } void ControlFlowAnalyzer::analyze(FunctionDefinition const& _function, ContractDefinition const* _contract, FunctionFlow const& _flow) diff --git a/libsolidity/analysis/ControlFlowGraph.cpp b/libsolidity/analysis/ControlFlowGraph.cpp index 66ec552ca..f4afe0149 100644 --- a/libsolidity/analysis/ControlFlowGraph.cpp +++ b/libsolidity/analysis/ControlFlowGraph.cpp @@ -27,7 +27,7 @@ using namespace solidity::frontend; bool CFG::constructFlow(ASTNode const& _astRoot) { _astRoot.accept(*this); - return Error::containsOnlyWarnings(m_errorReporter.errors()); + return !Error::containsErrors(m_errorReporter.errors()); } diff --git a/libsolidity/analysis/PostTypeChecker.cpp b/libsolidity/analysis/PostTypeChecker.cpp index e5c3ec2f8..cdc8c8b7e 100644 --- a/libsolidity/analysis/PostTypeChecker.cpp +++ b/libsolidity/analysis/PostTypeChecker.cpp @@ -36,14 +36,14 @@ using namespace solidity::frontend; bool PostTypeChecker::check(ASTNode const& _astRoot) { _astRoot.accept(*this); - return Error::containsOnlyWarnings(m_errorReporter.errors()); + return !Error::containsErrors(m_errorReporter.errors()); } bool PostTypeChecker::finalize() { for (auto& checker: m_checkers) checker->finalize(); - return Error::containsOnlyWarnings(m_errorReporter.errors()); + return !Error::containsErrors(m_errorReporter.errors()); } bool PostTypeChecker::visit(ContractDefinition const& _contractDefinition) diff --git a/libsolidity/analysis/PostTypeContractLevelChecker.cpp b/libsolidity/analysis/PostTypeContractLevelChecker.cpp index cfc6f4f29..32927188f 100644 --- a/libsolidity/analysis/PostTypeContractLevelChecker.cpp +++ b/libsolidity/analysis/PostTypeContractLevelChecker.cpp @@ -68,5 +68,5 @@ bool PostTypeContractLevelChecker::check(ContractDefinition const& _contract) errorHashes[hash][signature] = error->location(); } - return Error::containsOnlyWarnings(m_errorReporter.errors()); + return !Error::containsErrors(m_errorReporter.errors()); } diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp index 4931401cb..01ca601f1 100644 --- a/libsolidity/analysis/StaticAnalyzer.cpp +++ b/libsolidity/analysis/StaticAnalyzer.cpp @@ -86,7 +86,7 @@ StaticAnalyzer::~StaticAnalyzer() bool StaticAnalyzer::analyze(SourceUnit const& _sourceUnit) { _sourceUnit.accept(*this); - return Error::containsOnlyWarnings(m_errorReporter.errors()); + return !Error::containsErrors(m_errorReporter.errors()); } bool StaticAnalyzer::visit(ContractDefinition const& _contract) diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp index 412ad1aa9..e47080cb4 100644 --- a/libsolidity/analysis/SyntaxChecker.cpp +++ b/libsolidity/analysis/SyntaxChecker.cpp @@ -41,7 +41,7 @@ using namespace solidity::util; bool SyntaxChecker::checkSyntax(ASTNode const& _astRoot) { _astRoot.accept(*this); - return Error::containsOnlyWarnings(m_errorReporter.errors()); + return !Error::containsErrors(m_errorReporter.errors()); } bool SyntaxChecker::visit(SourceUnit const& _sourceUnit) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 369e04bc9..afcf92525 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -73,7 +73,7 @@ bool TypeChecker::checkTypeRequirements(SourceUnit const& _source) m_currentSourceUnit = &_source; _source.accept(*this); m_currentSourceUnit = nullptr; - return Error::containsOnlyWarnings(m_errorReporter.errors()); + return !Error::containsErrors(m_errorReporter.errors()); } Type const* TypeChecker::type(Expression const& _expression) const diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index cbdfff454..722e76fe5 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -338,7 +338,7 @@ bool CompilerStack::parse() Source& source = m_sources[path]; source.ast = parser.parse(*source.charStream); if (!source.ast) - solAssert(!Error::containsOnlyWarnings(m_errorReporter.errors()), "Parser returned null but did not report error."); + solAssert(Error::containsErrors(m_errorReporter.errors()), "Parser returned null but did not report error."); else { source.ast->annotation().path = path; @@ -357,7 +357,7 @@ bool CompilerStack::parse() m_stackState = Parsed; else m_stackState = ParsedAndImported; - if (!Error::containsOnlyWarnings(m_errorReporter.errors())) + if (Error::containsErrors(m_errorReporter.errors())) m_hasError = true; storeContractDefinitions(); diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 4071a1fbe..4d4dba6ca 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -50,7 +50,7 @@ namespace { Json::Value formatError( - bool _warning, + Error::Severity _severity, string const& _type, string const& _component, string const& _message, @@ -62,7 +62,7 @@ Json::Value formatError( Json::Value error = Json::objectValue; error["type"] = _type; error["component"] = _component; - error["severity"] = _warning ? "warning" : "error"; + error["severity"] = Error::formatErrorSeverityLowercase(_severity); error["message"] = _message; error["formattedMessage"] = (_formattedMessage.length() > 0) ? _formattedMessage : _message; if (_sourceLocation.isObject()) @@ -76,7 +76,7 @@ Json::Value formatFatalError(string const& _type, string const& _message) { Json::Value output = Json::objectValue; output["errors"] = Json::arrayValue; - output["errors"].append(formatError(false, _type, "general", _message)); + output["errors"].append(formatError(Error::Severity::Error, _type, "general", _message)); return output; } @@ -111,7 +111,7 @@ Json::Value formatSecondarySourceLocation(SecondarySourceLocation const* _second Json::Value formatErrorWithException( CharStreamProvider const& _charStreamProvider, util::Exception const& _exception, - bool const& _warning, + Error::Severity _severity, string const& _type, string const& _component, string const& _message, @@ -132,7 +132,7 @@ Json::Value formatErrorWithException( message = _message; Json::Value error = formatError( - _warning, + _severity, _type, _component, message, @@ -660,7 +660,7 @@ std::variant StandardCompiler: string content = sources[sourceName]["content"].asString(); if (!hash.empty() && !hashMatchesContent(hash, content)) ret.errors.append(formatError( - false, + Error::Severity::Error, "IOError", "general", "Mismatch between content and supplied hash for \"" + sourceName + "\"" @@ -685,7 +685,7 @@ std::variant StandardCompiler: { if (!hash.empty() && !hashMatchesContent(hash, result.responseOrErrorMessage)) ret.errors.append(formatError( - false, + Error::Severity::Error, "IOError", "general", "Mismatch between content and supplied hash for \"" + sourceName + "\" at \"" + url.asString() + "\"" @@ -705,7 +705,7 @@ std::variant StandardCompiler: { /// If the import succeeded, let mark all the others as warnings, otherwise all of them are errors. ret.errors.append(formatError( - found ? true : false, + found ? Error::Severity::Warning : Error::Severity::Error, "IOError", "general", failure @@ -1058,7 +1058,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting errors.append(formatErrorWithException( compilerStack, *error, - err.type() == Error::Type::Warning, + Error::errorSeverity(err.type()), err.typeName(), "general", "", @@ -1072,7 +1072,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting errors.append(formatErrorWithException( compilerStack, _error, - false, + Error::Severity::Error, _error.typeName(), "general", "Uncaught error: " @@ -1082,7 +1082,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting catch (FatalError const& _exception) { errors.append(formatError( - false, + Error::Severity::Error, "FatalError", "general", "Uncaught fatal error: " + boost::diagnostic_information(_exception) @@ -1093,7 +1093,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting errors.append(formatErrorWithException( compilerStack, _exception, - false, + Error::Severity::Error, "CompilerError", "general", "Compiler error (" + _exception.lineInfo() + ")" @@ -1104,7 +1104,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting errors.append(formatErrorWithException( compilerStack, _exception, - false, + Error::Severity::Error, "InternalCompilerError", "general", "Internal compiler error (" + _exception.lineInfo() + ")" @@ -1115,7 +1115,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting errors.append(formatErrorWithException( compilerStack, _exception, - false, + Error::Severity::Error, "UnimplementedFeatureError", "general", "Unimplemented feature (" + _exception.lineInfo() + ")" @@ -1126,7 +1126,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting errors.append(formatErrorWithException( compilerStack, _exception, - false, + Error::Severity::Error, "YulException", "general", "Yul exception" @@ -1137,7 +1137,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting errors.append(formatErrorWithException( compilerStack, _exception, - false, + Error::Severity::Error, "SMTLogicException", "general", "SMT logic exception" @@ -1146,7 +1146,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting catch (util::Exception const& _exception) { errors.append(formatError( - false, + Error::Severity::Error, "Exception", "general", "Exception during compilation: " + boost::diagnostic_information(_exception) @@ -1155,7 +1155,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting catch (std::exception const& _e) { errors.append(formatError( - false, + Error::Severity::Error, "Exception", "general", "Unknown exception during compilation" + (_e.what() ? ": " + string(_e.what()) : ".") @@ -1164,7 +1164,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting catch (...) { errors.append(formatError( - false, + Error::Severity::Error, "Exception", "general", "Unknown exception during compilation." @@ -1345,7 +1345,7 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) errors.append(formatErrorWithException( stack, *error, - err->type() == Error::Type::Warning, + Error::errorSeverity(err->type()), err->typeName(), "general", "" @@ -1357,7 +1357,7 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) // TODO: move this warning to AssemblyStack output["errors"] = Json::arrayValue; - output["errors"].append(formatError(true, "Warning", "general", "Yul is still experimental. Please use the output with care.")); + output["errors"].append(formatError(Error::Severity::Warning, "Warning", "general", "Yul is still experimental. Please use the output with care.")); string contractName = stack.parserResult()->name.str(); diff --git a/scripts/error_codes.py b/scripts/error_codes.py index 6f3f9ce95..4167a00f5 100755 --- a/scripts/error_codes.py +++ b/scripts/error_codes.py @@ -226,7 +226,7 @@ def examine_id_coverage(top_dir, source_id_to_file_names, new_ids_only=False): old_source_only_ids = { "1584", "1823", - "1988", "2066", "3356", + "1988", "2066", "2833", "3356", "3893", "3996", "4010", "4802", "5272", "5622", "7128", "7400", "7589", "7593", "7649", "7710", diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 275451114..c7fb6258b 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -976,7 +976,7 @@ bool CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul: m_hasOutput = true; formatter.printErrorInformation(*error); } - if (!Error::containsOnlyWarnings(stack.errors())) + if (Error::containsErrors(stack.errors())) successful = false; } diff --git a/test/libsolidity/AnalysisFramework.cpp b/test/libsolidity/AnalysisFramework.cpp index bc1a5372d..84c7a5e0b 100644 --- a/test/libsolidity/AnalysisFramework.cpp +++ b/test/libsolidity/AnalysisFramework.cpp @@ -75,24 +75,24 @@ AnalysisFramework::parseAnalyseAndReturnError( return make_pair(&compiler().ast(""), std::move(errors)); } -ErrorList AnalysisFramework::filterErrors(ErrorList const& _errorList, bool _includeWarnings) const +ErrorList AnalysisFramework::filterErrors(ErrorList const& _errorList, bool _includeWarningsAndInfos) const { ErrorList errors; for (auto const& currentError: _errorList) { solAssert(currentError->comment(), ""); - if (currentError->type() == Error::Type::Warning) + if (!Error::isError(currentError->type())) { - if (!_includeWarnings) + if (!_includeWarningsAndInfos) continue; - bool ignoreWarning = false; + bool ignoreWarningsAndInfos = false; for (auto const& filter: m_warningsToFilter) if (currentError->comment()->find(filter) == 0) { - ignoreWarning = true; + ignoreWarningsAndInfos = true; break; } - if (ignoreWarning) + if (ignoreWarningsAndInfos) continue; } diff --git a/test/libsolidity/AnalysisFramework.h b/test/libsolidity/AnalysisFramework.h index 17554b9ac..c4b4eda33 100644 --- a/test/libsolidity/AnalysisFramework.h +++ b/test/libsolidity/AnalysisFramework.h @@ -66,8 +66,8 @@ protected: std::string const& _signature ); - // filter out the warnings in m_warningsToFilter or all warnings if _includeWarnings is false - langutil::ErrorList filterErrors(langutil::ErrorList const& _errorList, bool _includeWarnings) const; + // filter out the warnings in m_warningsToFilter or all warnings and infos if _includeWarningsAndInfos is false + langutil::ErrorList filterErrors(langutil::ErrorList const& _errorList, bool _includeWarningsAndInfos) const; std::vector m_warningsToFilter = {"This is a pre-release compiler version"}; std::vector m_messagesToCut = {"Source file requires different compiler version (current compiler is"}; diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp index 76b1ba2a6..f12c12ca9 100644 --- a/test/libsolidity/Assembly.cpp +++ b/test/libsolidity/Assembly.cpp @@ -67,20 +67,20 @@ evmasm::AssemblyItems compileContract(std::shared_ptr _sourceCode) GlobalContext globalContext; NameAndTypeResolver resolver(globalContext, solidity::test::CommonOptions::get().evmVersion(), errorReporter); DeclarationTypeChecker declarationTypeChecker(errorReporter, solidity::test::CommonOptions::get().evmVersion()); - solAssert(Error::containsOnlyWarnings(errorReporter.errors()), ""); + solAssert(!Error::containsErrors(errorReporter.errors()), ""); resolver.registerDeclarations(*sourceUnit); BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*sourceUnit)); - if (!Error::containsOnlyWarnings(errorReporter.errors())) + if (Error::containsErrors(errorReporter.errors())) return AssemblyItems(); for (ASTPointer const& node: sourceUnit->nodes()) { BOOST_REQUIRE_NO_THROW(declarationTypeChecker.check(*node)); - if (!Error::containsOnlyWarnings(errorReporter.errors())) + if (Error::containsErrors(errorReporter.errors())) return AssemblyItems(); } TypeChecker checker(solidity::test::CommonOptions::get().evmVersion(), errorReporter); BOOST_REQUIRE_NO_THROW(checker.checkTypeRequirements(*sourceUnit)); - if (!Error::containsOnlyWarnings(errorReporter.errors())) + if (Error::containsErrors(errorReporter.errors())) return AssemblyItems(); for (ASTPointer const& node: sourceUnit->nodes()) if (ContractDefinition* contract = dynamic_cast(node.get())) diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp index 19b2da3b3..0ec9b50a2 100644 --- a/test/libsolidity/InlineAssembly.cpp +++ b/test/libsolidity/InlineAssembly.cpp @@ -128,7 +128,7 @@ void parsePrintCompare(string const& _source, bool _canWarn = false) AssemblyStack stack(solidity::test::CommonOptions::get().evmVersion(), AssemblyStack::Language::Assembly, OptimiserSettings::none()); BOOST_REQUIRE(stack.parseAndAnalyze("", _source)); if (_canWarn) - BOOST_REQUIRE(Error::containsOnlyWarnings(stack.errors())); + BOOST_REQUIRE(!Error::containsErrors(stack.errors())); else BOOST_REQUIRE(stack.errors().empty()); string expectation = "object \"object\" {\n code " + boost::replace_all_copy(_source, "\n", "\n ") + "\n}\n"; diff --git a/test/libsolidity/SolidityParser.cpp b/test/libsolidity/SolidityParser.cpp index 58024d9a6..77c01f1ea 100644 --- a/test/libsolidity/SolidityParser.cpp +++ b/test/libsolidity/SolidityParser.cpp @@ -74,7 +74,7 @@ bool successParse(std::string const& _source) if (Error::containsErrorOfType(errors, Error::Type::ParserError)) return false; - BOOST_CHECK(Error::containsOnlyWarnings(errors)); + BOOST_CHECK(!Error::containsErrors(errors)); return true; } diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index 8787d1173..ec5166cb1 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -41,6 +41,19 @@ namespace solidity::frontend::test namespace { +langutil::Error::Severity str2Severity(string const& _cat) +{ + map cats{ + {"info", langutil::Error::Severity::Info}, + {"Info", langutil::Error::Severity::Info}, + {"warning", langutil::Error::Severity::Warning}, + {"Warning", langutil::Error::Severity::Warning}, + {"error", langutil::Error::Severity::Error}, + {"Error", langutil::Error::Severity::Error} + }; + return cats.at(_cat); +} + /// Helper to match a specific error type and message bool containsError(Json::Value const& _compilerResult, string const& _type, string const& _message) { @@ -68,7 +81,7 @@ bool containsAtMostWarnings(Json::Value const& _compilerResult) { BOOST_REQUIRE(error.isObject()); BOOST_REQUIRE(error["severity"].isString()); - if (error["severity"].asString() != "warning") + if (langutil::Error::isError(str2Severity(error["severity"].asString()))) return false; } diff --git a/test/libsolidity/SyntaxTest.cpp b/test/libsolidity/SyntaxTest.cpp index bc0f6a7d8..2a70c35ab 100644 --- a/test/libsolidity/SyntaxTest.cpp +++ b/test/libsolidity/SyntaxTest.cpp @@ -91,7 +91,7 @@ void SyntaxTest::parseAndAnalyze() return error->type() == Error::Type::CodeGenerationError; }); auto errorCount = count_if(errors.cbegin(), errors.cend(), [](auto const& error) { - return error->type() != Error::Type::Warning; + return Error::isError(error->type()); }); // failing compilation after successful analysis is a rare case, // it assumes that errors contain exactly one error, and the error is of type Error::Type::CodeGenerationError diff --git a/test/libyul/ControlFlowGraphTest.cpp b/test/libyul/ControlFlowGraphTest.cpp index c77c190d3..dffc7ecbf 100644 --- a/test/libyul/ControlFlowGraphTest.cpp +++ b/test/libyul/ControlFlowGraphTest.cpp @@ -200,7 +200,7 @@ TestCase::TestResult ControlFlowGraphTest::run(ostream& _stream, string const& _ { ErrorList errors; auto [object, analysisInfo] = parse(m_source, *m_dialect, errors); - if (!object || !analysisInfo || !Error::containsOnlyWarnings(errors)) + if (!object || !analysisInfo || Error::containsErrors(errors)) { AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl; return TestResult::FatalError; diff --git a/test/libyul/ObjectParser.cpp b/test/libyul/ObjectParser.cpp index 987933a9f..d70d2002c 100644 --- a/test/libyul/ObjectParser.cpp +++ b/test/libyul/ObjectParser.cpp @@ -72,7 +72,7 @@ pair parse(string const& _source) return {false, {}}; } -optional parseAndReturnFirstError(string const& _source, bool _allowWarnings = true) +optional parseAndReturnFirstError(string const& _source, bool _allowWarningsAndInfos = true) { bool success; ErrorList errors; @@ -85,11 +85,11 @@ optional parseAndReturnFirstError(string const& _source, bool _allowWarni else { // If success is true, there might still be an error in the assembly stage. - if (_allowWarnings && Error::containsOnlyWarnings(errors)) + if (_allowWarningsAndInfos && !Error::containsErrors(errors)) return {}; else if (!errors.empty()) { - if (!_allowWarnings) + if (!_allowWarningsAndInfos) BOOST_CHECK_EQUAL(errors.size(), 1); return *errors.front(); } @@ -97,15 +97,15 @@ optional parseAndReturnFirstError(string const& _source, bool _allowWarni return {}; } -bool successParse(string const& _source, bool _allowWarnings = true) +bool successParse(string const& _source, bool _allowWarningsAndInfos = true) { - return !parseAndReturnFirstError(_source, _allowWarnings); + return !parseAndReturnFirstError(_source, _allowWarningsAndInfos); } -Error expectError(string const& _source, bool _allowWarnings = false) +Error expectError(string const& _source, bool _allowWarningsAndInfos = false) { - auto error = parseAndReturnFirstError(_source, _allowWarnings); + auto error = parseAndReturnFirstError(_source, _allowWarningsAndInfos); BOOST_REQUIRE(error); return *error; } diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index 4168b23a3..0ac9e64c9 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -85,7 +85,7 @@ shared_ptr parse(string const& _source, Dialect const& _dialect, ErrorRep return {}; } -std::optional parseAndReturnFirstError(string const& _source, Dialect const& _dialect, bool _allowWarnings = true) +std::optional parseAndReturnFirstError(string const& _source, Dialect const& _dialect, bool _allowWarningsAndInfos = true) { ErrorList errors; ErrorReporter errorReporter(errors); @@ -98,11 +98,11 @@ std::optional parseAndReturnFirstError(string const& _source, Dialect con else { // If success is true, there might still be an error in the assembly stage. - if (_allowWarnings && Error::containsOnlyWarnings(errors)) + if (_allowWarningsAndInfos && !Error::containsErrors(errors)) return {}; else if (!errors.empty()) { - if (!_allowWarnings) + if (!_allowWarningsAndInfos) BOOST_CHECK_EQUAL(errors.size(), 1); return *errors.front(); } @@ -110,15 +110,15 @@ std::optional parseAndReturnFirstError(string const& _source, Dialect con return {}; } -bool successParse(std::string const& _source, Dialect const& _dialect = Dialect::yulDeprecated(), bool _allowWarnings = true) +bool successParse(std::string const& _source, Dialect const& _dialect = Dialect::yulDeprecated(), bool _allowWarningsAndInfos = true) { - return !parseAndReturnFirstError(_source, _dialect, _allowWarnings); + return !parseAndReturnFirstError(_source, _dialect, _allowWarningsAndInfos); } -Error expectError(std::string const& _source, Dialect const& _dialect = Dialect::yulDeprecated(), bool _allowWarnings = false) +Error expectError(std::string const& _source, Dialect const& _dialect = Dialect::yulDeprecated(), bool _allowWarningsAndInfos = false) { - auto error = parseAndReturnFirstError(_source, _dialect, _allowWarnings); + auto error = parseAndReturnFirstError(_source, _dialect, _allowWarningsAndInfos); BOOST_REQUIRE(error); return *error; } diff --git a/test/libyul/StackLayoutGeneratorTest.cpp b/test/libyul/StackLayoutGeneratorTest.cpp index 35d4c07ee..70fda680e 100644 --- a/test/libyul/StackLayoutGeneratorTest.cpp +++ b/test/libyul/StackLayoutGeneratorTest.cpp @@ -217,7 +217,7 @@ TestCase::TestResult StackLayoutGeneratorTest::run(ostream& _stream, string cons { ErrorList errors; auto [object, analysisInfo] = parse(m_source, *m_dialect, errors); - if (!object || !analysisInfo || !Error::containsOnlyWarnings(errors)) + if (!object || !analysisInfo || Error::containsErrors(errors)) { AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl; return TestResult::FatalError; diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index ada942152..6404fa7c6 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -114,7 +114,7 @@ std::pair, std::shared_ptr> YulOptimize shared_ptr object; shared_ptr analysisInfo; std::tie(object, analysisInfo) = yul::test::parse(_source, *m_dialect, errors); - if (!object || !analysisInfo || !Error::containsOnlyWarnings(errors)) + if (!object || !analysisInfo || Error::containsErrors(errors)) { AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl; CharStream charStream(_source, ""); diff --git a/test/tools/ossfuzz/YulEvmoneInterface.cpp b/test/tools/ossfuzz/YulEvmoneInterface.cpp index fe737993d..e21a881c6 100644 --- a/test/tools/ossfuzz/YulEvmoneInterface.cpp +++ b/test/tools/ossfuzz/YulEvmoneInterface.cpp @@ -29,7 +29,7 @@ bytes YulAssembler::assemble() !m_stack.parseAndAnalyze("source", m_yulProgram) || !m_stack.parserResult()->code || !m_stack.parserResult()->analysisInfo || - !langutil::Error::containsOnlyWarnings(m_stack.errors()) + langutil::Error::containsErrors(m_stack.errors()) ) yulAssert(false, "Yul program could not be parsed successfully."); diff --git a/test/tools/ossfuzz/yulProtoFuzzer.cpp b/test/tools/ossfuzz/yulProtoFuzzer.cpp index a3b4e14ee..7118a0596 100644 --- a/test/tools/ossfuzz/yulProtoFuzzer.cpp +++ b/test/tools/ossfuzz/yulProtoFuzzer.cpp @@ -72,7 +72,7 @@ DEFINE_PROTO_FUZZER(Program const& _input) !stack.parseAndAnalyze("source", yul_source) || !stack.parserResult()->code || !stack.parserResult()->analysisInfo || - !Error::containsOnlyWarnings(stack.errors()) + Error::containsErrors(stack.errors()) ) yulAssert(false, "Proto fuzzer generated malformed program"); diff --git a/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp b/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp index 1fe4e6eaa..abb0df82f 100644 --- a/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp +++ b/test/tools/ossfuzz/yulProto_diff_ossfuzz.cpp @@ -71,7 +71,7 @@ DEFINE_PROTO_FUZZER(Program const& _input) !stack.parseAndAnalyze("source", yul_source) || !stack.parserResult()->code || !stack.parserResult()->analysisInfo || - !Error::containsOnlyWarnings(stack.errors()) + Error::containsErrors(stack.errors()) ) { SourceReferenceFormatter formatter(std::cout, stack, false, false); From 7abc55d89aac406b8bea11e0e307fb5af0173df4 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 14 Sep 2021 09:49:12 +0200 Subject: [PATCH 077/232] Use locationOf helper instead of accessing debugData directly. --- libyul/AST.h | 30 +++++------ libyul/AsmAnalysis.cpp | 64 ++++++++++++------------ libyul/AsmJsonConverter.cpp | 32 ++++++------ libyul/AsmParser.cpp | 16 +++--- libyul/ScopeFiller.cpp | 6 +-- libyul/backends/evm/EVMCodeTransform.cpp | 64 ++++++++++-------------- 6 files changed, 99 insertions(+), 113 deletions(-) diff --git a/libyul/AST.h b/libyul/AST.h index 54d44f6ae..01eece34d 100644 --- a/libyul/AST.h +++ b/libyul/AST.h @@ -83,32 +83,28 @@ struct Continue { std::shared_ptr debugData; }; /// Leave statement (valid within function) struct Leave { std::shared_ptr debugData; }; -struct LocationExtractor -{ - template langutil::SourceLocation operator()(T const& _node) const - { - return _node.debugData ? _node.debugData->location : langutil::SourceLocation{}; - } -}; - /// Extracts the source location from a Yul node. template inline langutil::SourceLocation locationOf(T const& _node) { - return std::visit(LocationExtractor(), _node); + return _node.debugData ? _node.debugData->location : langutil::SourceLocation{}; } -struct DebugDataExtractor +/// Extracts the source location from a Yul node. +template inline langutil::SourceLocation locationOf(std::variant const& _node) { - template std::shared_ptr const& operator()(T const& _node) const - { - return _node.debugData; - } -}; + return std::visit([](auto const& _arg) { return locationOf(_arg); }, _node); +} /// Extracts the debug data from a Yul node. -template inline std::shared_ptr const& debugDataOf(T const& _node) +template inline std::shared_ptr debugDataOf(T const& _node) { - return std::visit(DebugDataExtractor(), _node); + return _node.debugData; +} + +/// Extracts the debug data from a Yul node. +template inline std::shared_ptr debugDataOf(std::variant const& _node) +{ + return std::visit([](auto const& _arg) { return debugDataOf(_arg); }, _node); } } diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index 1c0867568..c01d1929f 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -96,22 +96,22 @@ AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect, vector AsmAnalyzer::operator()(Literal const& _literal) { - expectValidType(_literal.type, _literal.debugData->location); + expectValidType(_literal.type, locationOf(_literal)); if (_literal.kind == LiteralKind::String && _literal.value.str().size() > 32) m_errorReporter.typeError( 3069_error, - _literal.debugData->location, + locationOf(_literal), "String literal too long (" + to_string(_literal.value.str().size()) + " > 32)" ); else if (_literal.kind == LiteralKind::Number && bigint(_literal.value.str()) > u256(-1)) - m_errorReporter.typeError(6708_error, _literal.debugData->location, "Number literal too large (> 256 bits)"); + m_errorReporter.typeError(6708_error, locationOf(_literal), "Number literal too large (> 256 bits)"); else if (_literal.kind == LiteralKind::Boolean) yulAssert(_literal.value == "true"_yulstring || _literal.value == "false"_yulstring, ""); if (!m_dialect.validTypeForLiteral(_literal.kind, _literal.value, _literal.type)) m_errorReporter.typeError( 5170_error, - _literal.debugData->location, + locationOf(_literal), "Invalid type \"" + _literal.type.str() + "\" for literal \"" + _literal.value.str() + "\"." ); @@ -131,7 +131,7 @@ vector AsmAnalyzer::operator()(Identifier const& _identifier) if (!m_activeVariables.count(&_var)) m_errorReporter.declarationError( 4990_error, - _identifier.debugData->location, + locationOf(_identifier), "Variable " + _identifier.name.str() + " used before it was declared." ); type = _var.type; @@ -140,7 +140,7 @@ vector AsmAnalyzer::operator()(Identifier const& _identifier) { m_errorReporter.typeError( 6041_error, - _identifier.debugData->location, + locationOf(_identifier), "Function " + _identifier.name.str() + " used without being called." ); } @@ -165,7 +165,7 @@ vector AsmAnalyzer::operator()(Identifier const& _identifier) // Only add an error message if the callback did not do it. m_errorReporter.declarationError( 8198_error, - _identifier.debugData->location, + locationOf(_identifier), "Identifier \"" + _identifier.name.str() + "\" not found." ); @@ -181,7 +181,7 @@ void AsmAnalyzer::operator()(ExpressionStatement const& _statement) if (watcher.ok() && !types.empty()) m_errorReporter.typeError( 3083_error, - _statement.debugData->location, + locationOf(_statement), "Top-level expressions are not supposed to return values (this expression returns " + to_string(types.size()) + " value" + @@ -201,7 +201,7 @@ void AsmAnalyzer::operator()(Assignment const& _assignment) if (!variables.insert(_variableName.name).second) m_errorReporter.declarationError( 9005_error, - _assignment.debugData->location, + locationOf(_assignment), "Variable " + _variableName.name.str() + " occurs multiple times on the left-hand side of the assignment." @@ -212,7 +212,7 @@ void AsmAnalyzer::operator()(Assignment const& _assignment) if (types.size() != numVariables) m_errorReporter.declarationError( 8678_error, - _assignment.debugData->location, + locationOf(_assignment), "Variable count for assignment to \"" + joinHumanReadable(applyMap(_assignment.variableNames, [](auto const& _identifier){ return _identifier.name.str(); })) + "\" does not match number of values (" + @@ -240,8 +240,8 @@ void AsmAnalyzer::operator()(VariableDeclaration const& _varDecl) ); for (auto const& variable: _varDecl.variables) { - expectValidIdentifier(variable.name, variable.debugData->location); - expectValidType(variable.type, variable.debugData->location); + expectValidIdentifier(variable.name, locationOf(variable)); + expectValidType(variable.type, locationOf(variable)); } if (_varDecl.value) @@ -250,7 +250,7 @@ void AsmAnalyzer::operator()(VariableDeclaration const& _varDecl) if (types.size() != numVariables) m_errorReporter.declarationError( 3812_error, - _varDecl.debugData->location, + locationOf(_varDecl), "Variable count mismatch for declaration of \"" + joinHumanReadable(applyMap(_varDecl.variables, [](auto const& _identifier){ return _identifier.name.str(); })) + + "\": " + @@ -269,7 +269,7 @@ void AsmAnalyzer::operator()(VariableDeclaration const& _varDecl) if (variable.type != givenType) m_errorReporter.typeError( 3947_error, - variable.debugData->location, + locationOf(variable), "Assigning value of type \"" + givenType.str() + "\" to variable of type \"" + variable.type.str() + "\"." ); } @@ -284,14 +284,14 @@ void AsmAnalyzer::operator()(VariableDeclaration const& _varDecl) void AsmAnalyzer::operator()(FunctionDefinition const& _funDef) { yulAssert(!_funDef.name.empty(), ""); - expectValidIdentifier(_funDef.name, _funDef.debugData->location); + expectValidIdentifier(_funDef.name, locationOf(_funDef)); Block const* virtualBlock = m_info.virtualBlocks.at(&_funDef).get(); yulAssert(virtualBlock, ""); Scope& varScope = scope(virtualBlock); for (auto const& var: _funDef.parameters + _funDef.returnVariables) { - expectValidIdentifier(var.name, var.debugData->location); - expectValidType(var.type, var.debugData->location); + expectValidIdentifier(var.name, locationOf(var)); + expectValidType(var.type, locationOf(var)); m_activeVariables.insert(&std::get(varScope.identifiers.at(var.name))); } @@ -320,7 +320,7 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) { m_errorReporter.typeError( 4202_error, - _funCall.functionName.debugData->location, + locationOf(_funCall.functionName), "Attempt to call variable instead of function." ); }, @@ -344,7 +344,7 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) if (!validateInstructions(_funCall)) m_errorReporter.declarationError( 4619_error, - _funCall.functionName.debugData->location, + locationOf(_funCall.functionName), "Function \"" + _funCall.functionName.name.str() + "\" not found." ); yulAssert(!watcher.ok(), "Expected a reported error."); @@ -353,7 +353,7 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) if (parameterTypes && _funCall.arguments.size() != parameterTypes->size()) m_errorReporter.typeError( 7000_error, - _funCall.functionName.debugData->location, + locationOf(_funCall.functionName), "Function \"" + _funCall.functionName.name.str() + "\" expects " + to_string(parameterTypes->size()) + " arguments but got " + @@ -373,13 +373,13 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) if (!holds_alternative(arg)) m_errorReporter.typeError( 9114_error, - _funCall.functionName.debugData->location, + locationOf(_funCall.functionName), "Function expects direct literals as arguments." ); else if (*literalArgumentKind != get(arg).kind) m_errorReporter.typeError( 5859_error, - get(arg).debugData->location, + locationOf(arg), "Function expects " + to_string(*literalArgumentKind) + " literal." ); else if (*literalArgumentKind == LiteralKind::String) @@ -390,7 +390,7 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) if (!m_dataNames.count(get(arg).value)) m_errorReporter.typeError( 3517_error, - get(arg).debugData->location, + locationOf(arg), "Unknown data object \"" + std::get(arg).value.str() + "\"." ); } @@ -399,7 +399,7 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) if (get(arg).value.empty()) m_errorReporter.typeError( 1844_error, - get(arg).debugData->location, + locationOf(arg), "The \"verbatim_*\" builtins cannot be used with empty bytecode." ); } @@ -442,7 +442,7 @@ void AsmAnalyzer::operator()(Switch const& _switch) if (_switch.cases.size() == 1 && !_switch.cases[0].value) m_errorReporter.warning( 9592_error, - _switch.debugData->location, + locationOf(_switch), "\"switch\" statement with only a default case." ); @@ -455,7 +455,7 @@ void AsmAnalyzer::operator()(Switch const& _switch) { auto watcher = m_errorReporter.errorWatcher(); - expectType(valueType, _case.value->type, _case.value->debugData->location); + expectType(valueType, _case.value->type, locationOf(*_case.value)); // We cannot use "expectExpression" here because *_case.value is not an // Expression and would be converted to an Expression otherwise. @@ -465,7 +465,7 @@ void AsmAnalyzer::operator()(Switch const& _switch) if (watcher.ok() && !cases.insert(valueOfLiteral(*_case.value)).second) m_errorReporter.declarationError( 6792_error, - _case.debugData->location, + locationOf(_case), "Duplicate case \"" + valueOfLiteral(*_case.value).str() + "\" defined." @@ -565,11 +565,11 @@ void AsmAnalyzer::checkAssignment(Identifier const& _variable, YulString _valueT ); if (!holds_alternative(*var)) - m_errorReporter.typeError(2657_error, _variable.debugData->location, "Assignment requires variable."); + m_errorReporter.typeError(2657_error, locationOf(_variable), "Assignment requires variable."); else if (!m_activeVariables.count(&std::get(*var))) m_errorReporter.declarationError( 1133_error, - _variable.debugData->location, + locationOf(_variable), "Variable " + _variable.name.str() + " used before it was declared." ); else @@ -588,11 +588,11 @@ void AsmAnalyzer::checkAssignment(Identifier const& _variable, YulString _valueT if (!found && watcher.ok()) // Only add message if the callback did not. - m_errorReporter.declarationError(4634_error, _variable.debugData->location, "Variable not found or variable not lvalue."); + m_errorReporter.declarationError(4634_error, locationOf(_variable), "Variable not found or variable not lvalue."); if (variableType && *variableType != _valueType) m_errorReporter.typeError( 9547_error, - _variable.debugData->location, + locationOf(_variable), "Assigning a value of type \"" + _valueType.str() + "\" to a variable of type \"" + @@ -738,5 +738,5 @@ bool AsmAnalyzer::validateInstructions(evmasm::Instruction _instr, SourceLocatio bool AsmAnalyzer::validateInstructions(FunctionCall const& _functionCall) { - return validateInstructions(_functionCall.functionName.name.str(), _functionCall.functionName.debugData->location); + return validateInstructions(_functionCall.functionName.name.str(), locationOf(_functionCall.functionName)); } diff --git a/libyul/AsmJsonConverter.cpp b/libyul/AsmJsonConverter.cpp index fe595e7d2..0a7f86401 100644 --- a/libyul/AsmJsonConverter.cpp +++ b/libyul/AsmJsonConverter.cpp @@ -33,7 +33,7 @@ namespace solidity::yul Json::Value AsmJsonConverter::operator()(Block const& _node) const { - Json::Value ret = createAstNode(_node.debugData->location, "YulBlock"); + Json::Value ret = createAstNode(locationOf(_node), "YulBlock"); ret["statements"] = vectorOfVariantsToJson(_node.statements); return ret; } @@ -41,7 +41,7 @@ Json::Value AsmJsonConverter::operator()(Block const& _node) const Json::Value AsmJsonConverter::operator()(TypedName const& _node) const { yulAssert(!_node.name.empty(), "Invalid variable name."); - Json::Value ret = createAstNode(_node.debugData->location, "YulTypedName"); + Json::Value ret = createAstNode(locationOf(_node), "YulTypedName"); ret["name"] = _node.name.str(); ret["type"] = _node.type.str(); return ret; @@ -49,7 +49,7 @@ Json::Value AsmJsonConverter::operator()(TypedName const& _node) const Json::Value AsmJsonConverter::operator()(Literal const& _node) const { - Json::Value ret = createAstNode(_node.debugData->location, "YulLiteral"); + Json::Value ret = createAstNode(locationOf(_node), "YulLiteral"); switch (_node.kind) { case LiteralKind::Number: @@ -76,7 +76,7 @@ Json::Value AsmJsonConverter::operator()(Literal const& _node) const Json::Value AsmJsonConverter::operator()(Identifier const& _node) const { yulAssert(!_node.name.empty(), "Invalid identifier"); - Json::Value ret = createAstNode(_node.debugData->location, "YulIdentifier"); + Json::Value ret = createAstNode(locationOf(_node), "YulIdentifier"); ret["name"] = _node.name.str(); return ret; } @@ -84,7 +84,7 @@ Json::Value AsmJsonConverter::operator()(Identifier const& _node) const Json::Value AsmJsonConverter::operator()(Assignment const& _node) const { yulAssert(_node.variableNames.size() >= 1, "Invalid assignment syntax"); - Json::Value ret = createAstNode(_node.debugData->location, "YulAssignment"); + Json::Value ret = createAstNode(locationOf(_node), "YulAssignment"); for (auto const& var: _node.variableNames) ret["variableNames"].append((*this)(var)); ret["value"] = _node.value ? std::visit(*this, *_node.value) : Json::nullValue; @@ -93,7 +93,7 @@ Json::Value AsmJsonConverter::operator()(Assignment const& _node) const Json::Value AsmJsonConverter::operator()(FunctionCall const& _node) const { - Json::Value ret = createAstNode(_node.debugData->location, "YulFunctionCall"); + Json::Value ret = createAstNode(locationOf(_node), "YulFunctionCall"); ret["functionName"] = (*this)(_node.functionName); ret["arguments"] = vectorOfVariantsToJson(_node.arguments); return ret; @@ -101,14 +101,14 @@ Json::Value AsmJsonConverter::operator()(FunctionCall const& _node) const Json::Value AsmJsonConverter::operator()(ExpressionStatement const& _node) const { - Json::Value ret = createAstNode(_node.debugData->location, "YulExpressionStatement"); + Json::Value ret = createAstNode(locationOf(_node), "YulExpressionStatement"); ret["expression"] = std::visit(*this, _node.expression); return ret; } Json::Value AsmJsonConverter::operator()(VariableDeclaration const& _node) const { - Json::Value ret = createAstNode(_node.debugData->location, "YulVariableDeclaration"); + Json::Value ret = createAstNode(locationOf(_node), "YulVariableDeclaration"); for (auto const& var: _node.variables) ret["variables"].append((*this)(var)); @@ -120,7 +120,7 @@ Json::Value AsmJsonConverter::operator()(VariableDeclaration const& _node) const Json::Value AsmJsonConverter::operator()(FunctionDefinition const& _node) const { yulAssert(!_node.name.empty(), "Invalid function name."); - Json::Value ret = createAstNode(_node.debugData->location, "YulFunctionDefinition"); + Json::Value ret = createAstNode(locationOf(_node), "YulFunctionDefinition"); ret["name"] = _node.name.str(); for (auto const& var: _node.parameters) ret["parameters"].append((*this)(var)); @@ -133,7 +133,7 @@ Json::Value AsmJsonConverter::operator()(FunctionDefinition const& _node) const Json::Value AsmJsonConverter::operator()(If const& _node) const { yulAssert(_node.condition, "Invalid if condition."); - Json::Value ret = createAstNode(_node.debugData->location, "YulIf"); + Json::Value ret = createAstNode(locationOf(_node), "YulIf"); ret["condition"] = std::visit(*this, *_node.condition); ret["body"] = (*this)(_node.body); return ret; @@ -142,7 +142,7 @@ Json::Value AsmJsonConverter::operator()(If const& _node) const Json::Value AsmJsonConverter::operator()(Switch const& _node) const { yulAssert(_node.expression, "Invalid expression pointer."); - Json::Value ret = createAstNode(_node.debugData->location, "YulSwitch"); + Json::Value ret = createAstNode(locationOf(_node), "YulSwitch"); ret["expression"] = std::visit(*this, *_node.expression); for (auto const& var: _node.cases) ret["cases"].append((*this)(var)); @@ -151,7 +151,7 @@ Json::Value AsmJsonConverter::operator()(Switch const& _node) const Json::Value AsmJsonConverter::operator()(Case const& _node) const { - Json::Value ret = createAstNode(_node.debugData->location, "YulCase"); + Json::Value ret = createAstNode(locationOf(_node), "YulCase"); ret["value"] = _node.value ? (*this)(*_node.value) : "default"; ret["body"] = (*this)(_node.body); return ret; @@ -160,7 +160,7 @@ Json::Value AsmJsonConverter::operator()(Case const& _node) const Json::Value AsmJsonConverter::operator()(ForLoop const& _node) const { yulAssert(_node.condition, "Invalid for loop condition."); - Json::Value ret = createAstNode(_node.debugData->location, "YulForLoop"); + Json::Value ret = createAstNode(locationOf(_node), "YulForLoop"); ret["pre"] = (*this)(_node.pre); ret["condition"] = std::visit(*this, *_node.condition); ret["post"] = (*this)(_node.post); @@ -170,17 +170,17 @@ Json::Value AsmJsonConverter::operator()(ForLoop const& _node) const Json::Value AsmJsonConverter::operator()(Break const& _node) const { - return createAstNode(_node.debugData->location, "YulBreak"); + return createAstNode(locationOf(_node), "YulBreak"); } Json::Value AsmJsonConverter::operator()(Continue const& _node) const { - return createAstNode(_node.debugData->location, "YulContinue"); + return createAstNode(locationOf(_node), "YulContinue"); } Json::Value AsmJsonConverter::operator()(Leave const& _node) const { - return createAstNode(_node.debugData->location, "YulLeave"); + return createAstNode(locationOf(_node), "YulLeave"); } Json::Value AsmJsonConverter::createAstNode(langutil::SourceLocation const& _location, string _nodeType) const diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index d1465c737..da2aa815e 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -52,7 +52,7 @@ shared_ptr updateLocationEndFrom( langutil::SourceLocation const& _location ) { - SourceLocation updatedLocation = _debugData->location; + SourceLocation updatedLocation = _debugData ? _debugData->location : langutil::SourceLocation{}; updatedLocation.end = _location.end; return make_shared(updatedLocation); } @@ -195,7 +195,7 @@ Statement Parser::parseStatement() _if.condition = make_unique(parseExpression()); _if.body = parseBlock(); if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - _if.debugData = updateLocationEndFrom(_if.debugData, _if.body.debugData->location); + _if.debugData = updateLocationEndFrom(_if.debugData, locationOf(_if.body)); return Statement{move(_if)}; } case Token::Switch: @@ -214,7 +214,7 @@ Statement Parser::parseStatement() if (_switch.cases.empty()) fatalParserError(2418_error, "Switch statement without any cases."); if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - _switch.debugData = updateLocationEndFrom(_switch.debugData, _switch.cases.back().body.debugData->location); + _switch.debugData = updateLocationEndFrom(_switch.debugData, locationOf(_switch.cases.back().body)); return Statement{move(_switch)}; } case Token::For: @@ -328,7 +328,7 @@ Case Parser::parseCase() yulAssert(false, "Case or default case expected."); _case.body = parseBlock(); if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - _case.debugData = updateLocationEndFrom(_case.debugData, _case.body.debugData->location); + _case.debugData = updateLocationEndFrom(_case.debugData, locationOf(_case.body)); return _case; } @@ -349,7 +349,7 @@ ForLoop Parser::parseForLoop() m_currentForLoopComponent = ForLoopComponent::ForLoopBody; forLoop.body = parseBlock(); if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - forLoop.debugData = updateLocationEndFrom(forLoop.debugData, forLoop.body.debugData->location); + forLoop.debugData = updateLocationEndFrom(forLoop.debugData, locationOf(forLoop.body)); m_currentForLoopComponent = outerForLoopComponent; @@ -369,7 +369,7 @@ Expression Parser::parseExpression() if (m_dialect.builtin(_identifier.name)) fatalParserError( 7104_error, - _identifier.debugData->location, + locationOf(_identifier), "Builtin function \"" + _identifier.name.str() + "\" must be called." ); return move(_identifier); @@ -465,7 +465,7 @@ VariableDeclaration Parser::parseVariableDeclaration() varDecl.debugData = updateLocationEndFrom(varDecl.debugData, locationOf(*varDecl.value)); } else if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - varDecl.debugData = updateLocationEndFrom(varDecl.debugData, varDecl.variables.back().debugData->location); + varDecl.debugData = updateLocationEndFrom(varDecl.debugData, locationOf(varDecl.variables.back())); return varDecl; } @@ -512,7 +512,7 @@ FunctionDefinition Parser::parseFunctionDefinition() funDef.body = parseBlock(); m_insideFunction = preInsideFunction; if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - funDef.debugData = updateLocationEndFrom(funDef.debugData, funDef.body.debugData->location); + funDef.debugData = updateLocationEndFrom(funDef.debugData, locationOf(funDef.body)); m_currentForLoopComponent = outerForLoopComponent; return funDef; diff --git a/libyul/ScopeFiller.cpp b/libyul/ScopeFiller.cpp index 5c4599eda..70cd3d80e 100644 --- a/libyul/ScopeFiller.cpp +++ b/libyul/ScopeFiller.cpp @@ -53,7 +53,7 @@ bool ScopeFiller::operator()(ExpressionStatement const& _expr) bool ScopeFiller::operator()(VariableDeclaration const& _varDecl) { for (auto const& variable: _varDecl.variables) - if (!registerVariable(variable, _varDecl.debugData->location, *m_currentScope)) + if (!registerVariable(variable, locationOf(_varDecl), *m_currentScope)) return false; return true; } @@ -68,7 +68,7 @@ bool ScopeFiller::operator()(FunctionDefinition const& _funDef) bool success = true; for (auto const& var: _funDef.parameters + _funDef.returnVariables) - if (!registerVariable(var, _funDef.debugData->location, varScope)) + if (!registerVariable(var, locationOf(_funDef), varScope)) success = false; if (!(*this)(_funDef.body)) @@ -162,7 +162,7 @@ bool ScopeFiller::registerFunction(FunctionDefinition const& _funDef) //@TODO secondary location m_errorReporter.declarationError( 6052_error, - _funDef.debugData->location, + locationOf(_funDef), "Function name " + _funDef.name.str() + " already taken in this scope." ); return false; diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index 947e8d091..824a4b025 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -44,16 +44,6 @@ using namespace solidity; using namespace solidity::yul; using namespace solidity::util; -namespace -{ - -langutil::SourceLocation extractSourceLocationFromDebugData(shared_ptr const& _debugData) -{ - return _debugData ? _debugData->location : langutil::SourceLocation{}; -} - -} - CodeTransform::CodeTransform( AbstractAssembly& _assembly, AsmAnalysisInfo& _analysisInfo, @@ -155,13 +145,13 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl) } else { - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_varDecl.debugData)); + m_assembly.setSourceLocation(locationOf(_varDecl)); size_t variablesLeft = numVariables; while (variablesLeft--) m_assembly.appendConstant(u256(0)); } - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_varDecl.debugData)); + m_assembly.setSourceLocation(locationOf(_varDecl)); bool atTopOfStack = true; for (size_t varIndex = 0; varIndex < numVariables; ++varIndex) { @@ -223,13 +213,13 @@ void CodeTransform::operator()(Assignment const& _assignment) std::visit(*this, *_assignment.value); expectDeposit(static_cast(_assignment.variableNames.size()), height); - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_assignment.debugData)); + m_assembly.setSourceLocation(locationOf(_assignment)); generateMultiAssignment(_assignment.variableNames); } void CodeTransform::operator()(ExpressionStatement const& _statement) { - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_statement.debugData)); + m_assembly.setSourceLocation(locationOf(_statement)); std::visit(*this, _statement.expression); } @@ -237,13 +227,13 @@ void CodeTransform::operator()(FunctionCall const& _call) { yulAssert(m_scope, ""); - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_call.debugData)); + m_assembly.setSourceLocation(locationOf(_call)); if (BuiltinFunctionForEVM const* builtin = m_dialect.builtin(_call.functionName.name)) { for (auto&& [i, arg]: _call.arguments | ranges::views::enumerate | ranges::views::reverse) if (!builtin->literalArgument(i)) visitExpression(arg); - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_call.debugData)); + m_assembly.setSourceLocation(locationOf(_call)); builtin->generateCode(_call, m_assembly, m_builtinContext); } else @@ -260,7 +250,7 @@ void CodeTransform::operator()(FunctionCall const& _call) yulAssert(function->arguments.size() == _call.arguments.size(), ""); for (auto const& arg: _call.arguments | ranges::views::reverse) visitExpression(arg); - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_call.debugData)); + m_assembly.setSourceLocation(locationOf(_call)); m_assembly.appendJumpTo( functionEntryID(_call.functionName.name, *function), static_cast(function->returns.size() - function->arguments.size()) - 1, @@ -272,7 +262,7 @@ void CodeTransform::operator()(FunctionCall const& _call) void CodeTransform::operator()(Identifier const& _identifier) { - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_identifier.debugData)); + m_assembly.setSourceLocation(locationOf(_identifier)); // First search internals, then externals. yulAssert(m_scope, ""); if (m_scope->lookup(_identifier.name, GenericVisitor{ @@ -304,19 +294,19 @@ void CodeTransform::operator()(Identifier const& _identifier) void CodeTransform::operator()(Literal const& _literal) { - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_literal.debugData)); + m_assembly.setSourceLocation(locationOf(_literal)); m_assembly.appendConstant(valueOfLiteral(_literal)); } void CodeTransform::operator()(If const& _if) { visitExpression(*_if.condition); - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_if.debugData)); + m_assembly.setSourceLocation(locationOf(_if)); m_assembly.appendInstruction(evmasm::Instruction::ISZERO); AbstractAssembly::LabelID end = m_assembly.newLabelId(); m_assembly.appendJumpToIf(end); (*this)(_if.body); - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_if.debugData)); + m_assembly.setSourceLocation(locationOf(_if)); m_assembly.appendLabel(end); } @@ -331,7 +321,7 @@ void CodeTransform::operator()(Switch const& _switch) if (c.value) { (*this)(*c.value); - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(c.debugData)); + m_assembly.setSourceLocation(locationOf(c)); AbstractAssembly::LabelID bodyLabel = m_assembly.newLabelId(); caseBodies[&c] = bodyLabel; yulAssert(m_assembly.stackHeight() == expressionHeight + 1, ""); @@ -343,24 +333,24 @@ void CodeTransform::operator()(Switch const& _switch) // default case (*this)(c.body); } - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_switch.debugData)); + m_assembly.setSourceLocation(locationOf(_switch)); m_assembly.appendJumpTo(end); size_t numCases = caseBodies.size(); for (auto const& c: caseBodies) { - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(c.first->debugData)); + m_assembly.setSourceLocation(locationOf(*c.first)); m_assembly.appendLabel(c.second); (*this)(c.first->body); // Avoid useless "jump to next" for the last case. if (--numCases > 0) { - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(c.first->debugData)); + m_assembly.setSourceLocation(locationOf(*c.first)); m_assembly.appendJumpTo(end); } } - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_switch.debugData)); + m_assembly.setSourceLocation(locationOf(_switch)); m_assembly.appendLabel(end); m_assembly.appendInstruction(evmasm::Instruction::POP); } @@ -381,7 +371,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function) m_context->variableStackHeights[&var] = height++; } - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_function.debugData)); + m_assembly.setSourceLocation(locationOf(_function)); int const stackHeightBefore = m_assembly.stackHeight(); m_assembly.appendLabel(functionEntryID(_function.name, function)); @@ -417,7 +407,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function) subTransform(_function.body); - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_function.debugData)); + m_assembly.setSourceLocation(locationOf(_function)); if (!subTransform.m_stackErrors.empty()) { m_assembly.markAsInvalid(); @@ -508,11 +498,11 @@ void CodeTransform::operator()(ForLoop const& _forLoop) AbstractAssembly::LabelID postPart = m_assembly.newLabelId(); AbstractAssembly::LabelID loopEnd = m_assembly.newLabelId(); - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_forLoop.debugData)); + m_assembly.setSourceLocation(locationOf(_forLoop)); m_assembly.appendLabel(loopStart); visitExpression(*_forLoop.condition); - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_forLoop.debugData)); + m_assembly.setSourceLocation(locationOf(_forLoop)); m_assembly.appendInstruction(evmasm::Instruction::ISZERO); m_assembly.appendJumpToIf(loopEnd); @@ -520,12 +510,12 @@ void CodeTransform::operator()(ForLoop const& _forLoop) m_context->forLoopStack.emplace(Context::ForLoopLabels{ {postPart, stackHeightBody}, {loopEnd, stackHeightBody} }); (*this)(_forLoop.body); - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_forLoop.debugData)); + m_assembly.setSourceLocation(locationOf(_forLoop)); m_assembly.appendLabel(postPart); (*this)(_forLoop.post); - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_forLoop.debugData)); + m_assembly.setSourceLocation(locationOf(_forLoop)); m_assembly.appendJumpTo(loopStart); m_assembly.appendLabel(loopEnd); @@ -545,7 +535,7 @@ int CodeTransform::appendPopUntil(int _targetDepth) void CodeTransform::operator()(Break const& _break) { yulAssert(!m_context->forLoopStack.empty(), "Invalid break-statement. Requires surrounding for-loop in code generation."); - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_break.debugData)); + m_assembly.setSourceLocation(locationOf(_break)); Context::JumpInfo const& jump = m_context->forLoopStack.top().done; m_assembly.appendJumpTo(jump.label, appendPopUntil(jump.targetStackHeight)); @@ -554,7 +544,7 @@ void CodeTransform::operator()(Break const& _break) void CodeTransform::operator()(Continue const& _continue) { yulAssert(!m_context->forLoopStack.empty(), "Invalid continue-statement. Requires surrounding for-loop in code generation."); - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_continue.debugData)); + m_assembly.setSourceLocation(locationOf(_continue)); Context::JumpInfo const& jump = m_context->forLoopStack.top().post; m_assembly.appendJumpTo(jump.label, appendPopUntil(jump.targetStackHeight)); @@ -564,7 +554,7 @@ void CodeTransform::operator()(Leave const& _leaveStatement) { yulAssert(m_functionExitLabel, "Invalid leave-statement. Requires surrounding function in code generation."); yulAssert(m_functionExitStackHeight, ""); - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_leaveStatement.debugData)); + m_assembly.setSourceLocation(locationOf(_leaveStatement)); m_assembly.appendJumpTo(*m_functionExitLabel, appendPopUntil(*m_functionExitStackHeight)); } @@ -676,7 +666,7 @@ void CodeTransform::visitStatements(vector const& _statements) auto const* functionDefinition = std::get_if(&statement); if (functionDefinition && !jumpTarget) { - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(functionDefinition->debugData)); + m_assembly.setSourceLocation(locationOf(*functionDefinition)); jumpTarget = m_assembly.newLabelId(); m_assembly.appendJumpTo(*jumpTarget, 0); } @@ -697,7 +687,7 @@ void CodeTransform::visitStatements(vector const& _statements) void CodeTransform::finalizeBlock(Block const& _block, optional blockStartStackHeight) { - m_assembly.setSourceLocation(extractSourceLocationFromDebugData(_block.debugData)); + m_assembly.setSourceLocation(locationOf(_block)); freeUnusedVariables(); From 37f681c430af65181b9c1a5f5dee774fd043f7ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 31 Aug 2021 15:08:16 +0200 Subject: [PATCH 078/232] Deduplicate code for printing source locations --- libsolidity/codegen/ir/Common.cpp | 17 ++++++----- libyul/AsmPrinter.cpp | 49 +++++++++++++++++++++---------- libyul/AsmPrinter.h | 8 ++++- 3 files changed, 50 insertions(+), 24 deletions(-) diff --git a/libsolidity/codegen/ir/Common.cpp b/libsolidity/codegen/ir/Common.cpp index 772e9b53e..aec812c12 100644 --- a/libsolidity/codegen/ir/Common.cpp +++ b/libsolidity/codegen/ir/Common.cpp @@ -22,9 +22,13 @@ #include +#include + using namespace std; -using namespace solidity::util; +using namespace solidity::langutil; using namespace solidity::frontend; +using namespace solidity::util; +using namespace solidity::yul; namespace solidity::frontend { @@ -131,12 +135,11 @@ string dispenseLocationComment(langutil::SourceLocation const& _location, IRGene { solAssert(_location.sourceName, ""); _context.markSourceUsed(*_location.sourceName); - return "/// @src " - + to_string(_context.sourceIndices().at(*_location.sourceName)) - + ":" - + to_string(_location.start) - + ":" - + to_string(_location.end); + return AsmPrinter::formatSourceLocationComment( + _location, + _context.sourceIndices(), + true /* _statement */ + ); } string dispenseLocationComment(ASTNode const& _node, IRGenerationContext& _context) diff --git a/libyul/AsmPrinter.cpp b/libyul/AsmPrinter.cpp index 2a7b705f8..680dd89bc 100644 --- a/libyul/AsmPrinter.cpp +++ b/libyul/AsmPrinter.cpp @@ -38,6 +38,7 @@ using namespace std; using namespace solidity; +using namespace solidity::langutil; using namespace solidity::util; using namespace solidity::yul; @@ -256,7 +257,33 @@ string AsmPrinter::appendTypeName(YulString _type, bool _isBoolLiteral) const return ":" + _type.str(); } -string AsmPrinter::formatSourceLocationComment(shared_ptr const& _debugData, bool _statement) +string AsmPrinter::formatSourceLocationComment( + SourceLocation const& _location, + map const& _nameToSourceIndex, + bool _statement +) +{ + yulAssert(!_nameToSourceIndex.empty(), ""); + + string sourceIndex = "-1"; + if (_location.sourceName) + sourceIndex = to_string(_nameToSourceIndex.at(*_location.sourceName)); + + string sourceLocation = + "@src " + + sourceIndex + + ":" + + to_string(_location.start) + + ":" + + to_string(_location.end); + + return + _statement ? + "/// " + sourceLocation : + "/** " + sourceLocation + " */ "; +} + +string AsmPrinter::formatSourceLocationComment(shared_ptr const& _debugData, bool _statement) { if ( !_debugData || @@ -267,19 +294,9 @@ string AsmPrinter::formatSourceLocationComment(shared_ptr const m_lastLocation = _debugData->location; - string sourceIndex = "-1"; - if (_debugData->location.sourceName) - sourceIndex = to_string(m_nameToSourceIndex.at(*_debugData->location.sourceName)); - - string sourceLocation = - "@src " + - sourceIndex + - ":" + - to_string(_debugData->location.start) + - ":" + - to_string(_debugData->location.end); - return - _statement ? - "/// " + sourceLocation + "\n" : - "/** " + sourceLocation + " */ "; + return formatSourceLocationComment( + _debugData->location, + m_nameToSourceIndex, + _statement + ) + (_statement ? "\n" : ""); } diff --git a/libyul/AsmPrinter.h b/libyul/AsmPrinter.h index 940f663b4..1beb964aa 100644 --- a/libyul/AsmPrinter.h +++ b/libyul/AsmPrinter.h @@ -76,6 +76,12 @@ public: std::string operator()(Leave const& _continue); std::string operator()(Block const& _block); + static std::string formatSourceLocationComment( + langutil::SourceLocation const& _location, + std::map const& _nameToSourceIndex, + bool _statement + ); + private: std::string formatTypedName(TypedName _variable); std::string appendTypeName(YulString _type, bool _isBoolLiteral = false) const; @@ -88,7 +94,7 @@ private: } Dialect const* const m_dialect = nullptr; - std::map m_nameToSourceIndex; + std::map m_nameToSourceIndex; langutil::SourceLocation m_lastLocation = {}; }; From d78522b08b4eb654d4e7c0bd662c39448e41ba9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 2 Sep 2021 15:17:56 +0200 Subject: [PATCH 079/232] AsmParser: Accept optional code snippets after the @src tags --- libyul/AsmParser.cpp | 18 ++++- scripts/error_codes.py | 1 + test/libyul/Parser.cpp | 172 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+), 2 deletions(-) diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index ca2864a5c..8cd88f411 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -135,7 +135,8 @@ void Parser::fetchSourceLocationFromComment() regex_constants::ECMAScript | regex_constants::optimize ); static regex const srcTagArgsRegex = regex( - R"~~(^(-1|\d+):(-1|\d+):(-1|\d+)(?:\s+|$))~~", // index and location, e.g.: 1:234:-1 + R"~~(^(-1|\d+):(-1|\d+):(-1|\d+)(?:\s+|$))~~" // index and location, e.g.: 1:234:-1 + R"~~(("(?:[^"\\]|\\.)*"?)?)~~", // optional code snippet, e.g.: "string memory s = \"abc\";..." regex_constants::ECMAScript | regex_constants::optimize ); @@ -164,9 +165,22 @@ void Parser::fetchSourceLocationFromComment() return; } - solAssert(srcTagArgsMatch.size() == 4, ""); + solAssert(srcTagArgsMatch.size() == 5, ""); position += srcTagArgsMatch.position() + srcTagArgsMatch.length(); + if (srcTagArgsMatch[4].matched && ( + !boost::algorithm::ends_with(srcTagArgsMatch[4].str(), "\"") || + boost::algorithm::ends_with(srcTagArgsMatch[4].str(), "\\\"") + )) + { + m_errorReporter.syntaxError( + 1544_error, + commentLocation, + "Invalid code snippet in source location mapping. Quote is not terminated." + ); + return; + } + optional const sourceIndex = toInt(srcTagArgsMatch[1].str()); optional const start = toInt(srcTagArgsMatch[2].str()); optional const end = toInt(srcTagArgsMatch[3].str()); diff --git a/scripts/error_codes.py b/scripts/error_codes.py index 6f3f9ce95..214e6d3d2 100755 --- a/scripts/error_codes.py +++ b/scripts/error_codes.py @@ -192,6 +192,7 @@ def examine_id_coverage(top_dir, source_id_to_file_names, new_ids_only=False): # white list of ids which are not covered by tests white_ids = { "9804", # Tested in test/libyul/ObjectParser.cpp. + "1544", "2674", "6367", "8387", diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index 4168b23a3..a973e9e5b 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -624,6 +624,20 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_two_locations_no_whitespace) CHECK_LOCATION(result->debugData->location, "", -1, -1); } +BOOST_AUTO_TEST_CASE(customSourceLocations_two_locations_separated_with_single_space) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// @src 0:111:222 @src 1:333:444 + {} + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result && errorList.size() == 0); + CHECK_LOCATION(result->debugData->location, "source1", 333, 444); +} + BOOST_AUTO_TEST_CASE(customSourceLocations_leading_trailing_whitespace) { ErrorList errorList; @@ -656,6 +670,164 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_reference_original_sloc) CHECK_LOCATION(varDecl.debugData->location, "", 10, 20); } +BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"~~~( + { + /// @src 0:149:156 "new C(\"123\")" + let x := 123 + + let y := /** @src 1:96:165 "contract D {..." */ 128 + } + )~~~"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result && errorList.size() == 0); + BOOST_REQUIRE_EQUAL(result->statements.size(), 2); + + BOOST_REQUIRE(holds_alternative(result->statements.at(0))); + VariableDeclaration const& varX = get(result->statements.at(0)); + CHECK_LOCATION(varX.debugData->location, "source0", 149, 156); + + BOOST_REQUIRE(holds_alternative(result->statements.at(1))); + VariableDeclaration const& varY = get(result->statements.at(1)); + BOOST_REQUIRE(!!varY.value); + BOOST_REQUIRE(holds_alternative(*varY.value)); + Literal const& literal128 = get(*varY.value); + CHECK_LOCATION(literal128.debugData->location, "source1", 96, 165); +} + +BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets_empty_snippet) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// @src 0:111:222 "" + {} + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result && errorList.size() == 0); + CHECK_LOCATION(result->debugData->location, "source0", 111, 222); +} + +BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets_no_whitespace_before_snippet) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// @src 0:111:222"abc" def + {} + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result); + BOOST_REQUIRE(errorList.size() == 1); + BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); + BOOST_TEST(errorList[0]->errorId() == 8387_error); + CHECK_LOCATION(result->debugData->location, "", -1, -1); +} + +BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets_no_whitespace_after_snippet) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// @src 0:111:222 "abc"def + {} + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result && errorList.size() == 0); + CHECK_LOCATION(result->debugData->location, "source0", 111, 222); +} + +BOOST_AUTO_TEST_CASE(customSourceLocations_two_locations_with_snippets_no_whitespace) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// @src 0:111:222 "abc"@src 1:333:444 "abc" + {} + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result && errorList.size() == 0); + CHECK_LOCATION(result->debugData->location, "source1", 333, 444); +} + +BOOST_AUTO_TEST_CASE(customSourceLocations_two_locations_with_snippets_unterminated_quote) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// @src 0:111:222 " abc @src 1:333:444 + {} + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result); + BOOST_REQUIRE(errorList.size() == 1); + BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); + BOOST_TEST(errorList[0]->errorId() == 1544_error); + CHECK_LOCATION(result->debugData->location, "", -1, -1); +} + +BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets_with_nested_locations) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"~~~( + { + /// @src 0:149:156 "new C(\"123\") /// @src 1:3:4 " + let x := 123 + + let y := /** @src 1:96:165 "function f() internal { \"\/** @src 0:6:7 *\/\"; }" */ 128 + } + )~~~"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result && errorList.size() == 0); + BOOST_REQUIRE_EQUAL(result->statements.size(), 2); + + BOOST_REQUIRE(holds_alternative(result->statements.at(0))); + VariableDeclaration const& varX = get(result->statements.at(0)); + CHECK_LOCATION(varX.debugData->location, "source0", 149, 156); + + BOOST_REQUIRE(holds_alternative(result->statements.at(1))); + VariableDeclaration const& varY = get(result->statements.at(1)); + BOOST_REQUIRE(!!varY.value); + BOOST_REQUIRE(holds_alternative(*varY.value)); + Literal const& literal128 = get(*varY.value); + CHECK_LOCATION(literal128.debugData->location, "source1", 96, 165); +} + +BOOST_AUTO_TEST_CASE(customSourceLocations_multiple_src_tags_on_one_line) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = + "{\n" + " /// " + R"~~(@src 1:2:3 ""@src 1:2:4 @src-1:2:5@src 1:2:6 @src 1:2:7 "" @src 1:2:8)~~" + R"~~( X "@src 0:10:20 "new C(\"123\") /// @src 1:4:5 "" XYZ)~~" + R"~~( @src0:20:30 "abc"@src0:2:4 @src-0:2:5@)~~" + R"~~( @some text with random @ signs @@@ @- @** 1:6:7 "src 1:8:9")~~" + "\n" + " let x := 123\n" + "}\n"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result && errorList.size() == 0); + BOOST_REQUIRE_EQUAL(result->statements.size(), 1); + + BOOST_REQUIRE(holds_alternative(result->statements.at(0))); + VariableDeclaration const& varX = get(result->statements.at(0)); + CHECK_LOCATION(varX.debugData->location, "source1", 4, 5); +} + BOOST_AUTO_TEST_SUITE_END() } // end namespaces From 14639efc5d438c21b7688517333167401788c3b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 31 Aug 2021 15:10:40 +0200 Subject: [PATCH 080/232] Print code snippets next to source locations in IR output --- libsolidity/ast/ASTJsonConverter.cpp | 1 - libsolidity/codegen/ir/Common.cpp | 3 +- libsolidity/codegen/ir/IRGenerationContext.h | 11 +- libsolidity/codegen/ir/IRGenerator.cpp | 14 +- libsolidity/codegen/ir/IRGenerator.h | 15 +- libsolidity/interface/CompilerStack.cpp | 2 +- libyul/AsmPrinter.cpp | 26 +- libyul/AsmPrinter.h | 16 +- libyul/AssemblyStack.cpp | 4 +- libyul/AssemblyStack.h | 2 +- libyul/Object.cpp | 14 +- libyul/Object.h | 18 +- .../constant_optimizer_yul/output | 12 +- test/cmdlineTests/exp_base_literal/output | 104 ++-- .../output | 8 +- .../ir_compiler_subobjects/output | 30 +- .../output | 4 +- .../output | 4 +- .../keccak_optimization_deploy_code/output | 12 +- .../keccak_optimization_low_runs/output | 8 +- test/cmdlineTests/name_simplifier/output | 18 +- .../cmdlineTests/optimizer_array_sload/output | 28 +- test/cmdlineTests/revert_strings/output | 14 +- .../output.json | 6 +- .../standard_ir_requested/output.json | 14 +- .../standard_viair_requested/output.json | 38 +- test/cmdlineTests/viair_abicoder_v1/output | 20 +- test/cmdlineTests/viair_subobjects/output | 30 +- test/cmdlineTests/yul_optimizer_steps/output | 4 +- .../yul_source_locations/output.json | 156 ++--- .../args | 1 + .../input.sol | 13 + .../output | 578 ++++++++++++++++++ .../yul_string_format_ascii/output.json | 18 +- .../output.json | 18 +- .../output.json | 20 +- .../yul_string_format_ascii_long/output.json | 18 +- .../yul_string_format_hex/output.json | 20 +- 38 files changed, 989 insertions(+), 333 deletions(-) create mode 100644 test/cmdlineTests/yul_source_locations_code_snippet_escaping/args create mode 100644 test/cmdlineTests/yul_source_locations_code_snippet_escaping/input.sol create mode 100644 test/cmdlineTests/yul_source_locations_code_snippet_escaping/output diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index f8c284483..b74f71572 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -26,7 +26,6 @@ #include #include -#include #include #include diff --git a/libsolidity/codegen/ir/Common.cpp b/libsolidity/codegen/ir/Common.cpp index aec812c12..0a445c119 100644 --- a/libsolidity/codegen/ir/Common.cpp +++ b/libsolidity/codegen/ir/Common.cpp @@ -138,7 +138,8 @@ string dispenseLocationComment(langutil::SourceLocation const& _location, IRGene return AsmPrinter::formatSourceLocationComment( _location, _context.sourceIndices(), - true /* _statement */ + true /* _statement */, + _context.soliditySourceProvider() ); } diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index ee3eaced6..fdc617220 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -72,13 +73,15 @@ public: ExecutionContext _executionContext, RevertStrings _revertStrings, OptimiserSettings _optimiserSettings, - std::map _sourceIndices + std::map _sourceIndices, + langutil::CharStreamProvider const* _soliditySourceProvider ): m_evmVersion(_evmVersion), m_executionContext(_executionContext), m_revertStrings(_revertStrings), m_optimiserSettings(std::move(_optimiserSettings)), - m_sourceIndices(std::move(_sourceIndices)) + m_sourceIndices(std::move(_sourceIndices)), + m_soliditySourceProvider(_soliditySourceProvider) {} MultiUseYulFunctionCollector& functionCollector() { return m_functions; } @@ -171,6 +174,8 @@ public: bool immutableRegistered(VariableDeclaration const& _varDecl) const { return m_immutableVariables.count(&_varDecl); } + langutil::CharStreamProvider const* soliditySourceProvider() const { return m_soliditySourceProvider; } + private: langutil::EVMVersion m_evmVersion; ExecutionContext m_executionContext; @@ -214,6 +219,8 @@ private: std::map m_functionIDs; std::set m_subObjects; + + langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr; }; } diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 5affb1c08..30fc149ad 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -45,8 +45,9 @@ using namespace std; using namespace solidity; -using namespace solidity::util; using namespace solidity::frontend; +using namespace solidity::langutil; +using namespace solidity::util; namespace { @@ -115,7 +116,7 @@ pair IRGenerator::run( " * !USE AT YOUR OWN RISK! *\n" " *=====================================================*/\n\n"; - return {warning + ir, warning + asmStack.print()}; + return {warning + ir, warning + asmStack.print(m_context.soliditySourceProvider())}; } string IRGenerator::generate( @@ -1064,7 +1065,14 @@ void IRGenerator::resetContext(ContractDefinition const& _contract, ExecutionCon m_context.internalDispatchClean(), "Reset internal dispatch map without consuming it." ); - IRGenerationContext newContext(m_evmVersion, _context, m_context.revertStrings(), m_optimiserSettings, m_context.sourceIndices()); + IRGenerationContext newContext( + m_evmVersion, + _context, + m_context.revertStrings(), + m_optimiserSettings, + m_context.sourceIndices(), + m_context.soliditySourceProvider() + ); newContext.copyFunctionIDsFrom(m_context); m_context = move(newContext); diff --git a/libsolidity/codegen/ir/IRGenerator.h b/libsolidity/codegen/ir/IRGenerator.h index d5c2cbaec..85b570c7f 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -28,7 +28,10 @@ #include #include #include + +#include #include + #include namespace solidity::frontend @@ -45,11 +48,19 @@ public: langutil::EVMVersion _evmVersion, RevertStrings _revertStrings, OptimiserSettings _optimiserSettings, - std::map _sourceIndices + std::map _sourceIndices, + langutil::CharStreamProvider const* _soliditySourceProvider ): m_evmVersion(_evmVersion), m_optimiserSettings(_optimiserSettings), - m_context(_evmVersion, ExecutionContext::Creation, _revertStrings, std::move(_optimiserSettings), std::move(_sourceIndices)), + m_context( + _evmVersion, + ExecutionContext::Creation, + _revertStrings, + std::move(_optimiserSettings), + std::move(_sourceIndices), + _soliditySourceProvider + ), m_utils(_evmVersion, m_context.revertStrings(), m_context.functionCollector()) {} diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index cbdfff454..68411b071 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -1329,7 +1329,7 @@ void CompilerStack::generateIR(ContractDefinition const& _contract) for (auto const& pair: m_contracts) otherYulSources.emplace(pair.second.contract, pair.second.yulIR); - IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings, sourceIndices()); + IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings, sourceIndices(), this); tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run( _contract, createCBORMetadata(compiledContract), diff --git a/libyul/AsmPrinter.cpp b/libyul/AsmPrinter.cpp index 680dd89bc..9462bbd5a 100644 --- a/libyul/AsmPrinter.cpp +++ b/libyul/AsmPrinter.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -260,15 +261,31 @@ string AsmPrinter::appendTypeName(YulString _type, bool _isBoolLiteral) const string AsmPrinter::formatSourceLocationComment( SourceLocation const& _location, map const& _nameToSourceIndex, - bool _statement + bool _statement, + CharStreamProvider const* _soliditySourceProvider ) { yulAssert(!_nameToSourceIndex.empty(), ""); string sourceIndex = "-1"; + string solidityCodeSnippet = ""; if (_location.sourceName) + { sourceIndex = to_string(_nameToSourceIndex.at(*_location.sourceName)); + if (_soliditySourceProvider) + { + solidityCodeSnippet = escapeAndQuoteString( + _soliditySourceProvider->charStream(*_location.sourceName).singleLineSnippet(_location) + ); + + // On top of escaping quotes we also escape the slash inside any `*/` to guard against + // it prematurely terminating multi-line comment blocks. We do not escape all slashes + // because the ones without `*` are not dangerous and ignoring them reduces visual noise. + boost::replace_all(solidityCodeSnippet, "*/", "*\\/"); + } + } + string sourceLocation = "@src " + sourceIndex + @@ -279,8 +296,8 @@ string AsmPrinter::formatSourceLocationComment( return _statement ? - "/// " + sourceLocation : - "/** " + sourceLocation + " */ "; + "/// " + joinHumanReadable(vector{sourceLocation, solidityCodeSnippet}, " ") : + "/** " + joinHumanReadable(vector{sourceLocation, solidityCodeSnippet}, " ") + " */ "; } string AsmPrinter::formatSourceLocationComment(shared_ptr const& _debugData, bool _statement) @@ -297,6 +314,7 @@ string AsmPrinter::formatSourceLocationComment(shared_ptr const return formatSourceLocationComment( _debugData->location, m_nameToSourceIndex, - _statement + _statement, + m_soliditySourceProvider ) + (_statement ? "\n" : ""); } diff --git a/libyul/AsmPrinter.h b/libyul/AsmPrinter.h index 1beb964aa..de9e8fe90 100644 --- a/libyul/AsmPrinter.h +++ b/libyul/AsmPrinter.h @@ -28,6 +28,7 @@ #include +#include #include #include @@ -46,9 +47,11 @@ class AsmPrinter public: explicit AsmPrinter( Dialect const* _dialect = nullptr, - std::optional>> _sourceIndexToName = {} + std::optional>> _sourceIndexToName = {}, + langutil::CharStreamProvider const* _soliditySourceProvider = nullptr ): - m_dialect(_dialect) + m_dialect(_dialect), + m_soliditySourceProvider(_soliditySourceProvider) { if (_sourceIndexToName) for (auto&& [index, name]: *_sourceIndexToName) @@ -58,8 +61,9 @@ public: explicit AsmPrinter( Dialect const& _dialect, - std::optional>> _sourceIndexToName = {} - ): AsmPrinter(&_dialect, _sourceIndexToName) {} + std::optional>> _sourceIndexToName = {}, + langutil::CharStreamProvider const* _soliditySourceProvider = nullptr + ): AsmPrinter(&_dialect, _sourceIndexToName, _soliditySourceProvider) {} std::string operator()(Literal const& _literal); std::string operator()(Identifier const& _identifier); @@ -79,7 +83,8 @@ public: static std::string formatSourceLocationComment( langutil::SourceLocation const& _location, std::map const& _nameToSourceIndex, - bool _statement + bool _statement, + langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr ); private: @@ -96,6 +101,7 @@ private: Dialect const* const m_dialect = nullptr; std::map m_nameToSourceIndex; langutil::SourceLocation m_lastLocation = {}; + langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr; }; } diff --git a/libyul/AssemblyStack.cpp b/libyul/AssemblyStack.cpp index 8a00608cf..1ed55a2d6 100644 --- a/libyul/AssemblyStack.cpp +++ b/libyul/AssemblyStack.cpp @@ -314,11 +314,11 @@ AssemblyStack::assembleEVMWithDeployed(optional _deployName) const return {make_shared(assembly), {}}; } -string AssemblyStack::print() const +string AssemblyStack::print(CharStreamProvider const* _soliditySourceProvider) const { yulAssert(m_parserResult, ""); yulAssert(m_parserResult->code, ""); - return m_parserResult->toString(&languageToDialect(m_language, m_evmVersion)) + "\n"; + return m_parserResult->toString(&languageToDialect(m_language, m_evmVersion), _soliditySourceProvider) + "\n"; } shared_ptr AssemblyStack::parserResult() const diff --git a/libyul/AssemblyStack.h b/libyul/AssemblyStack.h index 3fcd15998..91ca78af7 100644 --- a/libyul/AssemblyStack.h +++ b/libyul/AssemblyStack.h @@ -116,7 +116,7 @@ public: langutil::ErrorList const& errors() const { return m_errors; } /// Pretty-print the input after having parsed it. - std::string print() const; + std::string print(langutil::CharStreamProvider const* _soliditySourceProvider = nullptr) const; /// Return the parsed and analyzed object. std::shared_ptr parserResult() const; diff --git a/libyul/Object.cpp b/libyul/Object.cpp index a87281cac..eee016aa4 100644 --- a/libyul/Object.cpp +++ b/libyul/Object.cpp @@ -35,8 +35,9 @@ using namespace std; using namespace solidity; -using namespace solidity::yul; +using namespace solidity::langutil; using namespace solidity::util; +using namespace solidity::yul; namespace { @@ -50,12 +51,15 @@ string indent(std::string const& _input) } -string Data::toString(Dialect const*) const +string Data::toString(Dialect const*, CharStreamProvider const*) const { return "data \"" + name.str() + "\" hex\"" + util::toHex(data) + "\""; } -string Object::toString(Dialect const* _dialect) const +string Object::toString( + Dialect const* _dialect, + CharStreamProvider const* _soliditySourceProvider +) const { yulAssert(code, "No code"); yulAssert(debugData, "No debug data"); @@ -70,10 +74,10 @@ string Object::toString(Dialect const* _dialect) const })) + "\n"; - string inner = "code " + AsmPrinter{_dialect, debugData->sourceNames}(*code); + string inner = "code " + AsmPrinter{_dialect, debugData->sourceNames, _soliditySourceProvider}(*code); for (auto const& obj: subObjects) - inner += "\n" + obj->toString(_dialect); + inner += "\n" + obj->toString(_dialect, _soliditySourceProvider); return useSrcComment + "object \"" + name.str() + "\" {\n" + indent(inner) + "\n}"; } diff --git a/libyul/Object.h b/libyul/Object.h index 39fb092d3..480b7e553 100644 --- a/libyul/Object.h +++ b/libyul/Object.h @@ -24,6 +24,8 @@ #include #include +#include + #include #include @@ -49,8 +51,10 @@ struct ObjectNode /// Name of the object. /// Can be empty since .yul files can also just contain code, without explicitly placing it in an object. YulString name; - - virtual std::string toString(Dialect const* _dialect) const = 0; + virtual std::string toString( + Dialect const* _dialect, + langutil::CharStreamProvider const* _soliditySourceProvider + ) const = 0; }; /** @@ -62,7 +66,10 @@ struct Data: public ObjectNode bytes data; - std::string toString(Dialect const* _dialect) const override; + std::string toString( + Dialect const* _dialect, + langutil::CharStreamProvider const* _soliditySourceProvider + ) const override; }; @@ -79,7 +86,10 @@ struct Object: public ObjectNode { public: /// @returns a (parseable) string representation. - std::string toString(Dialect const* _dialect) const; + std::string toString( + Dialect const* _dialect, + langutil::CharStreamProvider const* _soliditySourceProvider = nullptr + ) const; /// @returns the set of names of data objects accessible from within the code of /// this object, including the name of object itself diff --git a/test/cmdlineTests/constant_optimizer_yul/output b/test/cmdlineTests/constant_optimizer_yul/output index 15304fb3b..328ac2544 100644 --- a/test/cmdlineTests/constant_optimizer_yul/output +++ b/test/cmdlineTests/constant_optimizer_yul/output @@ -10,12 +10,12 @@ Optimized IR: object "C_12" { code { { - /// @src 0:61:418 + /// @src 0:61:418 "contract C {..." mstore(64, 128) if callvalue() { revert(0, 0) } - /// @src 0:103:238 + /// @src 0:103:238 "assembly {..." sstore(0, shl(180, 1)) - /// @src 0:61:418 + /// @src 0:61:418 "contract C {..." let _1 := datasize("C_12_deployed") codecopy(128, dataoffset("C_12_deployed"), _1) return(128, _1) @@ -25,12 +25,12 @@ object "C_12" { object "C_12_deployed" { code { { - /// @src 0:61:418 + /// @src 0:61:418 "contract C {..." mstore(64, 128) if callvalue() { revert(0, 0) } - /// @src 0:279:410 + /// @src 0:279:410 "assembly {..." sstore(0, 0x1000000000000000000000000000000000000000000000) - /// @src 0:61:418 + /// @src 0:61:418 "contract C {..." stop() } } diff --git a/test/cmdlineTests/exp_base_literal/output b/test/cmdlineTests/exp_base_literal/output index f4f8042c2..7a7f0647a 100644 --- a/test/cmdlineTests/exp_base_literal/output +++ b/test/cmdlineTests/exp_base_literal/output @@ -10,7 +10,7 @@ IR: /// @use-src 0:"exp_base_literal/input.sol" object "C_81" { code { - /// @src 0:82:370 + /// @src 0:82:370 "contract C {..." mstore(64, 128) if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } @@ -29,19 +29,19 @@ object "C_81" { revert(0, 0) } - /// @src 0:82:370 + /// @src 0:82:370 "contract C {..." function constructor_C_81() { - /// @src 0:82:370 + /// @src 0:82:370 "contract C {..." } - /// @src 0:82:370 + /// @src 0:82:370 "contract C {..." } /// @use-src 0:"exp_base_literal/input.sol" object "C_81_deployed" { code { - /// @src 0:82:370 + /// @src 0:82:370 "contract C {..." mstore(64, 128) if iszero(lt(calldatasize(), 4)) @@ -288,123 +288,123 @@ object "C_81" { power := exp(1, exponent) } - /// @src 0:96:368 + /// @src 0:96:368 "function f(uint a, uint b, uint c, uint d) public pure returns (uint, int, uint, uint) {..." function fun_f_80(var_a_4, var_b_6, var_c_8, var_d_10) -> var__13, var__15, var__17, var__19 { - /// @src 0:160:164 + /// @src 0:160:164 "uint" let zero_t_uint256_1 := zero_value_for_split_t_uint256() var__13 := zero_t_uint256_1 - /// @src 0:166:169 + /// @src 0:166:169 "int" let zero_t_int256_2 := zero_value_for_split_t_int256() var__15 := zero_t_int256_2 - /// @src 0:171:175 + /// @src 0:171:175 "uint" let zero_t_uint256_3 := zero_value_for_split_t_uint256() var__17 := zero_t_uint256_3 - /// @src 0:177:181 + /// @src 0:177:181 "uint" let zero_t_uint256_4 := zero_value_for_split_t_uint256() var__19 := zero_t_uint256_4 - /// @src 0:196:197 + /// @src 0:196:197 "2" let expr_23 := 0x02 - /// @src 0:199:200 + /// @src 0:199:200 "a" let _5 := var_a_4 let expr_24 := _5 - /// @src 0:196:200 + /// @src 0:196:200 "2**a" let _6 := convert_t_rational_2_by_1_to_t_uint256(expr_23) let expr_25 := checked_exp_t_rational_2_by_1_t_uint256(expr_24) - /// @src 0:187:200 + /// @src 0:187:200 "uint w = 2**a" let var_w_22 := expr_25 - /// @src 0:213:215 + /// @src 0:213:215 "-2" let expr_30 := 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe - /// @src 0:212:216 + /// @src 0:212:216 "(-2)" let expr_31 := expr_30 - /// @src 0:218:219 + /// @src 0:218:219 "b" let _7 := var_b_6 let expr_32 := _7 - /// @src 0:212:219 + /// @src 0:212:219 "(-2)**b" let _8 := convert_t_rational_minus_2_by_1_to_t_int256(expr_31) let expr_33 := checked_exp_t_rational_minus_2_by_1_t_uint256(expr_32) - /// @src 0:204:219 + /// @src 0:204:219 "int x = (-2)**b" let var_x_28 := expr_33 - /// @src 0:232:234 + /// @src 0:232:234 "10" let expr_37 := 0x0a - /// @src 0:236:237 + /// @src 0:236:237 "c" let _9 := var_c_8 let expr_38 := _9 - /// @src 0:232:237 + /// @src 0:232:237 "10**c" let _10 := convert_t_rational_10_by_1_to_t_uint256(expr_37) let expr_39 := checked_exp_t_rational_10_by_1_t_uint256(expr_38) - /// @src 0:223:237 + /// @src 0:223:237 "uint y = 10**c" let var_y_36 := expr_39 - /// @src 0:251:260 + /// @src 0:251:260 "2**256 -1" let expr_47 := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - /// @src 0:250:262 + /// @src 0:250:262 "(2**256 -1 )" let expr_48 := expr_47 - /// @src 0:264:265 + /// @src 0:264:265 "d" let _11 := var_d_10 let expr_49 := _11 - /// @src 0:250:265 + /// @src 0:250:265 "(2**256 -1 )**d" let _12 := convert_t_rational_115792089237316195423570985008687907853269984665640564039457584007913129639935_by_1_to_t_uint256(expr_48) let expr_50 := checked_exp_t_rational_115792089237316195423570985008687907853269984665640564039457584007913129639935_by_1_t_uint256(expr_49) - /// @src 0:241:265 + /// @src 0:241:265 "uint z = (2**256 -1 )**d" let var_z_42 := expr_50 - /// @src 0:308:309 + /// @src 0:308:309 "0" let expr_53 := 0x00 - /// @src 0:307:310 + /// @src 0:307:310 "(0)" let expr_54 := expr_53 - /// @src 0:312:313 + /// @src 0:312:313 "a" let _13 := var_a_4 let expr_55 := _13 - /// @src 0:307:313 + /// @src 0:307:313 "(0)**a" let _14 := convert_t_rational_0_by_1_to_t_uint256(expr_54) let expr_56 := checked_exp_t_rational_0_by_1_t_uint256(expr_55) - /// @src 0:303:313 + /// @src 0:303:313 "w = (0)**a" var_w_22 := expr_56 let expr_57 := expr_56 - /// @src 0:322:324 + /// @src 0:322:324 "-1" let expr_61 := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - /// @src 0:321:325 + /// @src 0:321:325 "(-1)" let expr_62 := expr_61 - /// @src 0:327:328 + /// @src 0:327:328 "b" let _15 := var_b_6 let expr_63 := _15 - /// @src 0:321:328 + /// @src 0:321:328 "(-1)**b" let _16 := convert_t_rational_minus_1_by_1_to_t_int256(expr_62) let expr_64 := checked_exp_t_rational_minus_1_by_1_t_uint256(expr_63) - /// @src 0:317:328 + /// @src 0:317:328 "x = (-1)**b" var_x_28 := expr_64 let expr_65 := expr_64 - /// @src 0:336:337 + /// @src 0:336:337 "1" let expr_68 := 0x01 - /// @src 0:339:340 + /// @src 0:339:340 "c" let _17 := var_c_8 let expr_69 := _17 - /// @src 0:336:340 + /// @src 0:336:340 "1**c" let _18 := convert_t_rational_1_by_1_to_t_uint256(expr_68) let expr_70 := checked_exp_t_rational_1_by_1_t_uint256(expr_69) - /// @src 0:332:340 + /// @src 0:332:340 "y = 1**c" var_y_36 := expr_70 let expr_71 := expr_70 - /// @src 0:353:354 + /// @src 0:353:354 "w" let _19 := var_w_22 let expr_73 := _19 - /// @src 0:352:364 + /// @src 0:352:364 "(w, x, y, z)" let expr_77_component_1 := expr_73 - /// @src 0:356:357 + /// @src 0:356:357 "x" let _20 := var_x_28 let expr_74 := _20 - /// @src 0:352:364 + /// @src 0:352:364 "(w, x, y, z)" let expr_77_component_2 := expr_74 - /// @src 0:359:360 + /// @src 0:359:360 "y" let _21 := var_y_36 let expr_75 := _21 - /// @src 0:352:364 + /// @src 0:352:364 "(w, x, y, z)" let expr_77_component_3 := expr_75 - /// @src 0:362:363 + /// @src 0:362:363 "z" let _22 := var_z_42 let expr_76 := _22 - /// @src 0:352:364 + /// @src 0:352:364 "(w, x, y, z)" let expr_77_component_4 := expr_76 - /// @src 0:345:364 + /// @src 0:345:364 "return (w, x, y, z)" var__13 := expr_77_component_1 var__15 := expr_77_component_2 var__17 := expr_77_component_3 @@ -412,7 +412,7 @@ object "C_81" { leave } - /// @src 0:82:370 + /// @src 0:82:370 "contract C {..." } diff --git a/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output b/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output index 8f948ccb9..12c61e783 100644 --- a/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output +++ b/test/cmdlineTests/ir_compiler_inheritance_nosubobjects/output @@ -10,7 +10,7 @@ Optimized IR: object "C_7" { code { { - /// @src 0:82:117 + /// @src 0:82:117 "contract C {..." mstore(64, 128) if callvalue() { revert(0, 0) } let _1 := datasize("C_7_deployed") @@ -22,7 +22,7 @@ object "C_7" { object "C_7_deployed" { code { { - /// @src 0:82:117 + /// @src 0:82:117 "contract C {..." mstore(64, 128) revert(0, 0) } @@ -43,7 +43,7 @@ Optimized IR: object "D_10" { code { { - /// @src 0:118:137 + /// @src 0:118:137 "contract D is C {..." mstore(64, 128) if callvalue() { revert(0, 0) } let _1 := datasize("D_10_deployed") @@ -55,7 +55,7 @@ object "D_10" { object "D_10_deployed" { code { { - /// @src 0:118:137 + /// @src 0:118:137 "contract D is C {..." mstore(64, 128) revert(0, 0) } diff --git a/test/cmdlineTests/ir_compiler_subobjects/output b/test/cmdlineTests/ir_compiler_subobjects/output index 9da2e5e7f..8c23c8ad7 100644 --- a/test/cmdlineTests/ir_compiler_subobjects/output +++ b/test/cmdlineTests/ir_compiler_subobjects/output @@ -10,7 +10,7 @@ Optimized IR: object "C_3" { code { { - /// @src 0:82:95 + /// @src 0:82:95 "contract C {}" mstore(64, 128) if callvalue() { revert(0, 0) } let _1 := datasize("C_3_deployed") @@ -22,7 +22,7 @@ object "C_3" { object "C_3_deployed" { code { { - /// @src 0:82:95 + /// @src 0:82:95 "contract C {}" mstore(64, 128) revert(0, 0) } @@ -43,7 +43,7 @@ Optimized IR: object "D_16" { code { { - /// @src 0:96:165 + /// @src 0:96:165 "contract D {..." mstore(64, 128) if callvalue() { revert(0, 0) } let _1 := datasize("D_16_deployed") @@ -55,7 +55,7 @@ object "D_16" { object "D_16_deployed" { code { { - /// @src 0:96:165 + /// @src 0:96:165 "contract D {..." mstore(64, 128) if iszero(lt(calldatasize(), 4)) { @@ -64,22 +64,22 @@ object "D_16" { { if callvalue() { revert(_1, _1) } if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } - /// @src 0:149:156 + /// @src 0:149:156 "new C()" let _2 := datasize("C_3") - let _3 := add(/** @src 0:96:165 */ 128, /** @src 0:149:156 */ _2) - if or(gt(_3, 0xffffffffffffffff), lt(_3, /** @src 0:96:165 */ 128)) - /// @src 0:149:156 + let _3 := add(/** @src 0:96:165 "contract D {..." */ 128, /** @src 0:149:156 "new C()" */ _2) + if or(gt(_3, 0xffffffffffffffff), lt(_3, /** @src 0:96:165 "contract D {..." */ 128)) + /// @src 0:149:156 "new C()" { - /// @src 0:96:165 + /// @src 0:96:165 "contract D {..." mstore(_1, shl(224, 0x4e487b71)) mstore(4, 0x41) revert(_1, 0x24) } - /// @src 0:149:156 - datacopy(/** @src 0:96:165 */ 128, /** @src 0:149:156 */ dataoffset("C_3"), _2) - if iszero(create(/** @src 0:96:165 */ _1, 128, /** @src 0:149:156 */ _2)) + /// @src 0:149:156 "new C()" + datacopy(/** @src 0:96:165 "contract D {..." */ 128, /** @src 0:149:156 "new C()" */ dataoffset("C_3"), _2) + if iszero(create(/** @src 0:96:165 "contract D {..." */ _1, 128, /** @src 0:149:156 "new C()" */ _2)) { - /// @src 0:96:165 + /// @src 0:96:165 "contract D {..." let pos := mload(64) returndatacopy(pos, _1, returndatasize()) revert(pos, returndatasize()) @@ -94,7 +94,7 @@ object "D_16" { object "C_3" { code { { - /// @src 0:82:95 + /// @src 0:82:95 "contract C {}" mstore(64, 128) if callvalue() { revert(0, 0) } let _1 := datasize("C_3_deployed") @@ -106,7 +106,7 @@ object "D_16" { object "C_3_deployed" { code { { - /// @src 0:82:95 + /// @src 0:82:95 "contract C {}" mstore(64, 128) revert(0, 0) } diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output index dff1fb478..930899aea 100644 --- a/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_creation/output @@ -10,7 +10,7 @@ Optimized IR: object "D_12" { code { { - /// @src 0:82:161 + /// @src 0:82:161 "contract D {..." mstore(64, 128) if callvalue() { revert(0, 0) } let _1 := datasize("D_12_deployed") @@ -22,7 +22,7 @@ object "D_12" { object "D_12_deployed" { code { { - /// @src 0:82:161 + /// @src 0:82:161 "contract D {..." mstore(64, 128) if iszero(lt(calldatasize(), 4)) { diff --git a/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output index 2fbed1d26..da6540fa7 100644 --- a/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output +++ b/test/cmdlineTests/ir_with_assembly_no_memoryguard_runtime/output @@ -10,7 +10,7 @@ Optimized IR: object "D_8" { code { { - /// @src 0:82:153 + /// @src 0:82:153 "contract D {..." mstore(64, 128) if callvalue() { revert(0, 0) } let _1 := datasize("D_8_deployed") @@ -22,7 +22,7 @@ object "D_8" { object "D_8_deployed" { code { { - /// @src 0:82:153 + /// @src 0:82:153 "contract D {..." mstore(64, 128) if iszero(lt(calldatasize(), 4)) { diff --git a/test/cmdlineTests/keccak_optimization_deploy_code/output b/test/cmdlineTests/keccak_optimization_deploy_code/output index 09ea3d776..4abb046f6 100644 --- a/test/cmdlineTests/keccak_optimization_deploy_code/output +++ b/test/cmdlineTests/keccak_optimization_deploy_code/output @@ -10,13 +10,13 @@ Optimized IR: object "C_12" { code { { - /// @src 0:62:463 + /// @src 0:62:463 "contract C {..." mstore(64, 128) if callvalue() { revert(0, 0) } - /// @src 0:103:275 + /// @src 0:103:275 "assembly {..." mstore(0, 100) sstore(0, keccak256(0, 32)) - /// @src 0:62:463 + /// @src 0:62:463 "contract C {..." let _1 := datasize("C_12_deployed") codecopy(128, dataoffset("C_12_deployed"), _1) return(128, _1) @@ -26,13 +26,13 @@ object "C_12" { object "C_12_deployed" { code { { - /// @src 0:62:463 + /// @src 0:62:463 "contract C {..." mstore(64, 128) if callvalue() { revert(0, 0) } - /// @src 0:317:454 + /// @src 0:317:454 "assembly {..." mstore(0, 100) sstore(0, 17385872270140913825666367956517731270094621555228275961425792378517567244498) - /// @src 0:62:463 + /// @src 0:62:463 "contract C {..." stop() } } diff --git a/test/cmdlineTests/keccak_optimization_low_runs/output b/test/cmdlineTests/keccak_optimization_low_runs/output index 692bd4384..25b678ee0 100644 --- a/test/cmdlineTests/keccak_optimization_low_runs/output +++ b/test/cmdlineTests/keccak_optimization_low_runs/output @@ -10,7 +10,7 @@ Optimized IR: object "C_7" { code { { - /// @src 0:62:285 + /// @src 0:62:285 "contract C {..." mstore(64, 128) if callvalue() { revert(0, 0) } let _1 := datasize("C_7_deployed") @@ -22,13 +22,13 @@ object "C_7" { object "C_7_deployed" { code { { - /// @src 0:62:285 + /// @src 0:62:285 "contract C {..." mstore(64, 128) if callvalue() { revert(0, 0) } - /// @src 0:109:277 + /// @src 0:109:277 "assembly {..." mstore(0, 100) sstore(0, keccak256(0, 32)) - /// @src 0:62:285 + /// @src 0:62:285 "contract C {..." stop() } } diff --git a/test/cmdlineTests/name_simplifier/output b/test/cmdlineTests/name_simplifier/output index fcd70e0b0..36d68bfd9 100644 --- a/test/cmdlineTests/name_simplifier/output +++ b/test/cmdlineTests/name_simplifier/output @@ -10,7 +10,7 @@ Optimized IR: object "C_59" { code { { - /// @src 0:346:625 + /// @src 0:346:625 "contract C {..." mstore(64, 128) if callvalue() { revert(0, 0) } let _1 := datasize("C_59_deployed") @@ -22,7 +22,7 @@ object "C_59" { object "C_59_deployed" { code { { - /// @src 0:346:625 + /// @src 0:346:625 "contract C {..." mstore(64, 128) if iszero(lt(calldatasize(), 4)) { @@ -106,18 +106,18 @@ object "C_59" { mstore(4, 0x32) revert(0, 0x24) } - /// @src 0:381:623 + /// @src 0:381:623 "function sumArray(S[] memory _s) public returns (uint, string memory) {..." function fun_sumArray(var_s_mpos) -> var, var_mpos { - /// @src 0:346:625 + /// @src 0:346:625 "contract C {..." if iszero(mload(var_s_mpos)) { panic_error_0x32() } - sstore(/** @src 0:472:473 */ 0x00, /** @src 0:346:625 */ mload(/** @src 0:469:474 */ mload(/** @src 0:346:625 */ add(var_s_mpos, 32)))) + sstore(/** @src 0:472:473 "0" */ 0x00, /** @src 0:346:625 "contract C {..." */ mload(/** @src 0:469:474 "_s[0]" */ mload(/** @src 0:346:625 "contract C {..." */ add(var_s_mpos, 32)))) if iszero(lt(1, mload(var_s_mpos))) { panic_error_0x32() } - let _1 := mload(/** @src 0:489:494 */ mload(/** @src 0:346:625 */ add(var_s_mpos, 64))) + let _1 := mload(/** @src 0:489:494 "_s[1]" */ mload(/** @src 0:346:625 "contract C {..." */ add(var_s_mpos, 64))) sstore(0x02, _1) - /// @src 0:500:619 + /// @src 0:500:619 "return (t.y[0], \"longstringlongstringlongstringlongstringlongstringlongstringlongstringlongstringlongstringlongstring\")" var := _1 - /// @src 0:346:625 + /// @src 0:346:625 "contract C {..." let memPtr := mload(64) let newFreePtr := add(memPtr, 160) if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } @@ -127,7 +127,7 @@ object "C_59" { mstore(add(memPtr, 64), "ngstringlongstringlongstringlong") mstore(add(memPtr, 96), "stringlongstringlongstringlongst") mstore(add(memPtr, 128), "ring") - /// @src 0:500:619 + /// @src 0:500:619 "return (t.y[0], \"longstringlongstringlongstringlongstringlongstringlongstringlongstringlongstringlongstringlongstring\")" var_mpos := memPtr } } diff --git a/test/cmdlineTests/optimizer_array_sload/output b/test/cmdlineTests/optimizer_array_sload/output index e7bf19abf..448b0badc 100644 --- a/test/cmdlineTests/optimizer_array_sload/output +++ b/test/cmdlineTests/optimizer_array_sload/output @@ -10,7 +10,7 @@ Optimized IR: object "Arraysum_34" { code { { - /// @src 0:80:429 + /// @src 0:80:429 "contract Arraysum {..." mstore(64, 128) if callvalue() { revert(0, 0) } let _1 := datasize("Arraysum_34_deployed") @@ -22,7 +22,7 @@ object "Arraysum_34" { object "Arraysum_34_deployed" { code { { - /// @src 0:80:429 + /// @src 0:80:429 "contract Arraysum {..." mstore(64, 128) if iszero(lt(calldatasize(), 4)) { @@ -32,27 +32,27 @@ object "Arraysum_34" { if callvalue() { revert(_1, _1) } if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } let var_sum := _1 - /// @src 0:368:378 - let var_i := /** @src 0:80:429 */ _1 + /// @src 0:368:378 "uint i = 0" + let var_i := /** @src 0:80:429 "contract Arraysum {..." */ _1 let _2 := sload(_1) - /// @src 0:364:423 + /// @src 0:364:423 "for(uint i = 0; i < values.length; i++)..." for { } - /** @src 0:380:397 */ lt(var_i, _2) - /// @src 0:368:378 + /** @src 0:380:397 "i < values.length" */ lt(var_i, _2) + /// @src 0:368:378 "uint i = 0" { - /// @src 0:80:429 + /// @src 0:80:429 "contract Arraysum {..." if eq(var_i, not(0)) { panic_error_0x11() } - /// @src 0:399:402 - var_i := /** @src 0:80:429 */ add(var_i, 1) + /// @src 0:399:402 "i++" + var_i := /** @src 0:80:429 "contract Arraysum {..." */ add(var_i, 1) } - /// @src 0:399:402 + /// @src 0:399:402 "i++" { - /// @src 0:80:429 + /// @src 0:80:429 "contract Arraysum {..." mstore(_1, _1) let _3 := sload(add(18569430475105882587588266137607568536673111973893317399460219858819262702947, var_i)) if gt(var_sum, not(_3)) { panic_error_0x11() } - /// @src 0:407:423 - var_sum := /** @src 0:80:429 */ add(var_sum, _3) + /// @src 0:407:423 "sum += values[i]" + var_sum := /** @src 0:80:429 "contract Arraysum {..." */ add(var_sum, _3) } let memPos := mload(64) return(memPos, sub(abi_encode_uint256(memPos, var_sum), memPos)) diff --git a/test/cmdlineTests/revert_strings/output b/test/cmdlineTests/revert_strings/output index fde886ed5..989d7594c 100644 --- a/test/cmdlineTests/revert_strings/output +++ b/test/cmdlineTests/revert_strings/output @@ -10,7 +10,7 @@ IR: /// @use-src 0:"revert_strings/input.sol" object "C_15" { code { - /// @src 0:59:147 + /// @src 0:59:147 "contract C {..." mstore(64, 128) if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } @@ -44,19 +44,19 @@ object "C_15" { } - /// @src 0:59:147 + /// @src 0:59:147 "contract C {..." function constructor_C_15() { - /// @src 0:59:147 + /// @src 0:59:147 "contract C {..." } - /// @src 0:59:147 + /// @src 0:59:147 "contract C {..." } /// @use-src 0:"revert_strings/input.sol" object "C_15_deployed" { code { - /// @src 0:59:147 + /// @src 0:59:147 "contract C {..." mstore(64, 128) if iszero(lt(calldatasize(), 4)) @@ -359,11 +359,11 @@ object "C_15" { } - /// @src 0:93:145 + /// @src 0:93:145 "function f(uint[][] memory, E e) public pure {..." function fun_f_14(var__7_mpos, var_e_10) { } - /// @src 0:59:147 + /// @src 0:59:147 "contract C {..." } diff --git a/test/cmdlineTests/standard_irOptimized_requested/output.json b/test/cmdlineTests/standard_irOptimized_requested/output.json index 2651856c0..696a03573 100644 --- a/test/cmdlineTests/standard_irOptimized_requested/output.json +++ b/test/cmdlineTests/standard_irOptimized_requested/output.json @@ -8,7 +8,7 @@ /// @use-src 0:\"A\" object \"C_7\" { code { - /// @src 0:79:121 + /// @src 0:79:121 \"contract C { function f() public pure {} }\" mstore(64, 128) if callvalue() { @@ -28,7 +28,7 @@ object \"C_7\" { /// @use-src 0:\"A\" object \"C_7_deployed\" { code { - /// @src 0:79:121 + /// @src 0:79:121 \"contract C { function f() public pure {} }\" mstore(64, 128) if iszero(lt(calldatasize(), 4)) { @@ -68,7 +68,7 @@ object \"C_7\" { { tail := add(headStart, 0) } function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } - /// @src 0:92:119 + /// @src 0:92:119 \"function f() public pure {}\" function fun_f_6() { } } diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index bc61d38bd..a056672b9 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -9,7 +9,7 @@ /// @use-src 0:\"A\" object \"C_7\" { code { - /// @src 0:79:121 + /// @src 0:79:121 \"contract C { function f() public pure {} }\" mstore(64, 128) if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } @@ -28,19 +28,19 @@ object \"C_7\" { revert(0, 0) } - /// @src 0:79:121 + /// @src 0:79:121 \"contract C { function f() public pure {} }\" function constructor_C_7() { - /// @src 0:79:121 + /// @src 0:79:121 \"contract C { function f() public pure {} }\" } - /// @src 0:79:121 + /// @src 0:79:121 \"contract C { function f() public pure {} }\" } /// @use-src 0:\"A\" object \"C_7_deployed\" { code { - /// @src 0:79:121 + /// @src 0:79:121 \"contract C { function f() public pure {} }\" mstore(64, 128) if iszero(lt(calldatasize(), 4)) @@ -98,11 +98,11 @@ object \"C_7\" { revert(0, 0) } - /// @src 0:92:119 + /// @src 0:92:119 \"function f() public pure {}\" function fun_f_6() { } - /// @src 0:79:121 + /// @src 0:79:121 \"contract C { function f() public pure {} }\" } diff --git a/test/cmdlineTests/standard_viair_requested/output.json b/test/cmdlineTests/standard_viair_requested/output.json index 3ba066ab4..31ab3de5e 100644 --- a/test/cmdlineTests/standard_viair_requested/output.json +++ b/test/cmdlineTests/standard_viair_requested/output.json @@ -9,7 +9,7 @@ /// @use-src 0:\"A\" object \"C_3\" { code { - /// @src 0:79:92 + /// @src 0:79:92 \"contract C {}\" mstore(64, 128) if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } @@ -28,19 +28,19 @@ object \"C_3\" { revert(0, 0) } - /// @src 0:79:92 + /// @src 0:79:92 \"contract C {}\" function constructor_C_3() { - /// @src 0:79:92 + /// @src 0:79:92 \"contract C {}\" } - /// @src 0:79:92 + /// @src 0:79:92 \"contract C {}\" } /// @use-src 0:\"A\" object \"C_3_deployed\" { code { - /// @src 0:79:92 + /// @src 0:79:92 \"contract C {}\" mstore(64, 128) if iszero(lt(calldatasize(), 4)) @@ -86,7 +86,7 @@ object \"C_3\" { /// @use-src 0:\"A\" object \"D_16\" { code { - /// @src 0:93:146 + /// @src 0:93:146 \"contract D { function f() public { C c = new C(); } }\" mstore(64, 128) if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } @@ -105,19 +105,19 @@ object \"D_16\" { revert(0, 0) } - /// @src 0:93:146 + /// @src 0:93:146 \"contract D { function f() public { C c = new C(); } }\" function constructor_D_16() { - /// @src 0:93:146 + /// @src 0:93:146 \"contract D { function f() public { C c = new C(); } }\" } - /// @src 0:93:146 + /// @src 0:93:146 \"contract D { function f() public { C c = new C(); } }\" } /// @use-src 0:\"A\" object \"D_16_deployed\" { code { - /// @src 0:93:146 + /// @src 0:93:146 \"contract D { function f() public { C c = new C(); } }\" mstore(64, 128) if iszero(lt(calldatasize(), 4)) @@ -187,10 +187,10 @@ object \"D_16\" { revert(pos, returndatasize()) } - /// @src 0:106:144 + /// @src 0:106:144 \"function f() public { C c = new C(); }\" function fun_f_15() { - /// @src 0:134:141 + /// @src 0:134:141 \"new C()\" let _1 := allocate_unbounded() let _2 := add(_1, datasize(\"C_3\")) if or(gt(_2, 0xffffffffffffffff), lt(_2, _1)) { panic_error_0x41() } @@ -201,11 +201,11 @@ object \"D_16\" { if iszero(expr_12_address) { revert_forward_1() } - /// @src 0:128:141 + /// @src 0:128:141 \"C c = new C()\" let var_c_8_address := expr_12_address } - /// @src 0:93:146 + /// @src 0:93:146 \"contract D { function f() public { C c = new C(); } }\" } /*=====================================================* @@ -218,7 +218,7 @@ object \"D_16\" { /// @use-src 0:\"A\" object \"C_3\" { code { - /// @src 0:79:92 + /// @src 0:79:92 \"contract C {}\" mstore(64, 128) if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } @@ -237,19 +237,19 @@ object \"D_16\" { revert(0, 0) } - /// @src 0:79:92 + /// @src 0:79:92 \"contract C {}\" function constructor_C_3() { - /// @src 0:79:92 + /// @src 0:79:92 \"contract C {}\" } - /// @src 0:79:92 + /// @src 0:79:92 \"contract C {}\" } /// @use-src 0:\"A\" object \"C_3_deployed\" { code { - /// @src 0:79:92 + /// @src 0:79:92 \"contract C {}\" mstore(64, 128) if iszero(lt(calldatasize(), 4)) diff --git a/test/cmdlineTests/viair_abicoder_v1/output b/test/cmdlineTests/viair_abicoder_v1/output index c3715f007..3a0d4744b 100644 --- a/test/cmdlineTests/viair_abicoder_v1/output +++ b/test/cmdlineTests/viair_abicoder_v1/output @@ -10,7 +10,7 @@ IR: /// @use-src 0:"viair_abicoder_v1/input.sol" object "test_11" { code { - /// @src 0:79:169 + /// @src 0:79:169 "contract test {..." mstore(64, 128) if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } @@ -29,19 +29,19 @@ object "test_11" { revert(0, 0) } - /// @src 0:79:169 + /// @src 0:79:169 "contract test {..." function constructor_test_11() { - /// @src 0:79:169 + /// @src 0:79:169 "contract test {..." } - /// @src 0:79:169 + /// @src 0:79:169 "contract test {..." } /// @use-src 0:"viair_abicoder_v1/input.sol" object "test_11_deployed" { code { - /// @src 0:79:169 + /// @src 0:79:169 "contract test {..." mstore(64, 128) if iszero(lt(calldatasize(), 4)) @@ -113,20 +113,20 @@ object "test_11" { ret := 0 } - /// @src 0:99:167 + /// @src 0:99:167 "function f() public pure returns (bool) {..." function fun_f_10() -> var__5 { - /// @src 0:133:137 + /// @src 0:133:137 "bool" let zero_t_bool_1 := zero_value_for_split_t_bool() var__5 := zero_t_bool_1 - /// @src 0:156:160 + /// @src 0:156:160 "true" let expr_7 := 0x01 - /// @src 0:149:160 + /// @src 0:149:160 "return true" var__5 := expr_7 leave } - /// @src 0:79:169 + /// @src 0:79:169 "contract test {..." } diff --git a/test/cmdlineTests/viair_subobjects/output b/test/cmdlineTests/viair_subobjects/output index 03e952c7e..eef7d27e8 100644 --- a/test/cmdlineTests/viair_subobjects/output +++ b/test/cmdlineTests/viair_subobjects/output @@ -16,7 +16,7 @@ Optimized IR: object "C_3" { code { { - /// @src 0:82:95 + /// @src 0:82:95 "contract C {}" mstore(64, 128) if callvalue() { revert(0, 0) } let _1 := datasize("C_3_deployed") @@ -28,7 +28,7 @@ object "C_3" { object "C_3_deployed" { code { { - /// @src 0:82:95 + /// @src 0:82:95 "contract C {}" mstore(64, 128) revert(0, 0) } @@ -55,7 +55,7 @@ Optimized IR: object "D_16" { code { { - /// @src 0:96:165 + /// @src 0:96:165 "contract D {..." mstore(64, 128) if callvalue() { revert(0, 0) } let _1 := datasize("D_16_deployed") @@ -67,7 +67,7 @@ object "D_16" { object "D_16_deployed" { code { { - /// @src 0:96:165 + /// @src 0:96:165 "contract D {..." mstore(64, 128) if iszero(lt(calldatasize(), 4)) { @@ -76,22 +76,22 @@ object "D_16" { { if callvalue() { revert(_1, _1) } if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } - /// @src 0:149:156 + /// @src 0:149:156 "new C()" let _2 := datasize("C_3") - let _3 := add(/** @src 0:96:165 */ 128, /** @src 0:149:156 */ _2) - if or(gt(_3, 0xffffffffffffffff), lt(_3, /** @src 0:96:165 */ 128)) - /// @src 0:149:156 + let _3 := add(/** @src 0:96:165 "contract D {..." */ 128, /** @src 0:149:156 "new C()" */ _2) + if or(gt(_3, 0xffffffffffffffff), lt(_3, /** @src 0:96:165 "contract D {..." */ 128)) + /// @src 0:149:156 "new C()" { - /// @src 0:96:165 + /// @src 0:96:165 "contract D {..." mstore(_1, shl(224, 0x4e487b71)) mstore(4, 0x41) revert(_1, 0x24) } - /// @src 0:149:156 - datacopy(/** @src 0:96:165 */ 128, /** @src 0:149:156 */ dataoffset("C_3"), _2) - if iszero(create(/** @src 0:96:165 */ _1, 128, /** @src 0:149:156 */ _2)) + /// @src 0:149:156 "new C()" + datacopy(/** @src 0:96:165 "contract D {..." */ 128, /** @src 0:149:156 "new C()" */ dataoffset("C_3"), _2) + if iszero(create(/** @src 0:96:165 "contract D {..." */ _1, 128, /** @src 0:149:156 "new C()" */ _2)) { - /// @src 0:96:165 + /// @src 0:96:165 "contract D {..." let pos := mload(64) returndatacopy(pos, _1, returndatasize()) revert(pos, returndatasize()) @@ -106,7 +106,7 @@ object "D_16" { object "C_3" { code { { - /// @src 0:82:95 + /// @src 0:82:95 "contract C {}" mstore(64, 128) if callvalue() { revert(0, 0) } let _1 := datasize("C_3_deployed") @@ -118,7 +118,7 @@ object "D_16" { object "C_3_deployed" { code { { - /// @src 0:82:95 + /// @src 0:82:95 "contract C {}" mstore(64, 128) revert(0, 0) } diff --git a/test/cmdlineTests/yul_optimizer_steps/output b/test/cmdlineTests/yul_optimizer_steps/output index 3e4ba5809..478c844db 100644 --- a/test/cmdlineTests/yul_optimizer_steps/output +++ b/test/cmdlineTests/yul_optimizer_steps/output @@ -10,7 +10,7 @@ Optimized IR: object "C_7" { code { { - /// @src 0:80:112 + /// @src 0:80:112 "contract C..." mstore(64, 128) if callvalue() { @@ -29,7 +29,7 @@ object "C_7" { object "C_7_deployed" { code { { - /// @src 0:80:112 + /// @src 0:80:112 "contract C..." mstore(64, 128) if iszero(lt(calldatasize(), 4)) { diff --git a/test/cmdlineTests/yul_source_locations/output.json b/test/cmdlineTests/yul_source_locations/output.json index f6f431177..0839fb1f3 100644 --- a/test/cmdlineTests/yul_source_locations/output.json +++ b/test/cmdlineTests/yul_source_locations/output.json @@ -9,7 +9,7 @@ /// @use-src 0:\"C\" object \"C_54\" { code { - /// @src 0:79:428 + /// @src 0:79:428 \"contract C...\" mstore(64, 160) if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } @@ -135,31 +135,31 @@ object \"C_54\" { sstore(slot, update_byte_slice_32_shift_0(sload(slot), prepare_store_t_int256(convertedValue_0))) } - /// @src 0:175:223 + /// @src 0:175:223 \"constructor(int _init)...\" function constructor_C_54(var__init_12) { - /// @src 0:175:223 + /// @src 0:175:223 \"constructor(int _init)...\" - /// @src 0:147:149 + /// @src 0:147:149 \"42\" let expr_7 := 0x2a let _3 := convert_t_rational_42_by_1_to_t_int256(expr_7) mstore(128, _3) - /// @src 0:214:219 + /// @src 0:214:219 \"_init\" let _4 := var__init_12 let expr_16 := _4 - /// @src 0:203:219 + /// @src 0:203:219 \"stateVar = _init\" update_storage_value_offset_0t_int256_to_t_int256(0x00, expr_16) let expr_17 := expr_16 } - /// @src 0:79:428 + /// @src 0:79:428 \"contract C...\" } /// @use-src 0:\"C\" object \"C_54_deployed\" { code { - /// @src 0:79:428 + /// @src 0:79:428 \"contract C...\" mstore(64, 128) if iszero(lt(calldatasize(), 4)) @@ -267,7 +267,7 @@ object \"C_54\" { } - /// @src 0:152:171 + /// @src 0:152:171 \"int public stateVar\" function getter_fun_stateVar_10() -> ret { let slot := 0 @@ -276,7 +276,7 @@ object \"C_54\" { ret := read_from_storage_split_dynamic_t_int256(slot, offset) } - /// @src 0:79:428 + /// @src 0:79:428 \"contract C...\" function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) @@ -298,9 +298,9 @@ object \"C_54\" { converted := cleanup_t_int256(identity(cleanup_t_rational_41_by_1(value))) } - /// @src 0:93:119 + /// @src 0:93:119 \"int constant constVar = 41\" function constant_constVar_5() -> ret { - /// @src 0:117:119 + /// @src 0:117:119 \"41\" let expr_4 := 0x29 let _2 := convert_t_rational_41_by_1_to_t_int256(expr_4) @@ -325,26 +325,26 @@ object \"C_54\" { sum := add(x, y) } - /// @src 0:226:302 + /// @src 0:226:302 \"function f() external pure returns (int)...\" function fun_f_30() -> var__23 { - /// @src 0:262:265 + /// @src 0:262:265 \"int\" let zero_t_int256_1 := zero_value_for_split_t_int256() var__23 := zero_t_int256_1 - /// @src 0:279:287 + /// @src 0:279:287 \"constVar\" let expr_25 := constant_constVar_5() - /// @src 0:290:298 + /// @src 0:290:298 \"immutVar\" let _3 := loadimmutable(\"8\") let expr_26 := _3 - /// @src 0:279:298 + /// @src 0:279:298 \"constVar + immutVar\" let expr_27 := checked_add_t_int256(expr_25, expr_26) - /// @src 0:272:298 + /// @src 0:272:298 \"return constVar + immutVar\" var__23 := expr_27 leave } - /// @src 0:79:428 + /// @src 0:79:428 \"contract C...\" function shift_right_0_unsigned(value) -> newValue { newValue := @@ -395,20 +395,20 @@ object \"C_54\" { sstore(slot, update_byte_slice_32_shift_0(sload(slot), prepare_store_t_int256(convertedValue_0))) } - /// @src 0:304:341 + /// @src 0:304:341 \"modifier m()...\" function modifier_m_40(var__42) -> _5 { _5 := var__42 - /// @src 0:322:332 + /// @src 0:322:332 \"stateVar++\" let _7 := read_from_storage_split_offset_0_t_int256(0x00) let _6 := increment_t_int256(_7) update_storage_value_offset_0t_int256_to_t_int256(0x00, _6) let expr_33 := _7 - /// @src 0:336:337 + /// @src 0:336:337 \"_\" _5 := fun_f2_53_inner(var__42) } - /// @src 0:79:428 + /// @src 0:79:428 \"contract C...\" function cleanup_t_uint160(value) -> cleaned { cleaned := and(value, 0xffffffffffffffffffffffffffffffffffffffff) @@ -490,19 +490,19 @@ object \"C_54\" { revert(pos, returndatasize()) } - /// @src 0:343:426 + /// @src 0:343:426 \"function f2() m public returns (int)...\" function fun_f2_53_inner(_8) -> var__42 { var__42 := _8 - /// @src 0:392:400 + /// @src 0:392:400 \"stateVar\" let _9 := read_from_storage_split_offset_0_t_int256(0x00) let expr_44 := _9 - /// @src 0:403:407 + /// @src 0:403:407 \"this\" let expr_45_address := address() - /// @src 0:403:409 + /// @src 0:403:409 \"this.f\" let expr_46_address := convert_t_contract$_C_$54_to_t_address(expr_45_address) let expr_46_functionSelector := 0x26121ff0 - /// @src 0:403:411 + /// @src 0:403:411 \"this.f()\" if iszero(extcodesize(expr_46_address)) { revert_error_0cc013b6b3b6beabea4e3a74a6d380f0df81852ca99887912475e1f66b2a2c20() } // storage for arguments and returned data @@ -523,31 +523,31 @@ object \"C_54\" { // decode return parameters from external try-call into retVars expr_47 := abi_decode_tuple_t_int256_fromMemory(_10, add(_10, returndatasize())) } - /// @src 0:392:411 + /// @src 0:392:411 \"stateVar + this.f()\" let expr_48 := checked_add_t_int256(expr_44, expr_47) - /// @src 0:414:422 + /// @src 0:414:422 \"immutVar\" let _13 := loadimmutable(\"8\") let expr_49 := _13 - /// @src 0:392:422 + /// @src 0:392:422 \"stateVar + this.f() + immutVar\" let expr_50 := checked_add_t_int256(expr_48, expr_49) - /// @src 0:385:422 + /// @src 0:385:422 \"return stateVar + this.f() + immutVar\" var__42 := expr_50 leave } - /// @src 0:79:428 + /// @src 0:79:428 \"contract C...\" - /// @src 0:343:426 + /// @src 0:343:426 \"function f2() m public returns (int)...\" function fun_f2_53() -> var__42 { - /// @src 0:375:378 + /// @src 0:375:378 \"int\" let zero_t_int256_4 := zero_value_for_split_t_int256() var__42 := zero_t_int256_4 var__42 := modifier_m_40(var__42) } - /// @src 0:79:428 + /// @src 0:79:428 \"contract C...\" } @@ -567,7 +567,7 @@ object \"C_54\" { /// @use-src 0:\"C\", 1:\"D\" object \"D_72\" { code { - /// @src 1:91:166 + /// @src 1:91:166 \"contract D is C(3)...\" mstore(64, 160) if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } @@ -731,26 +731,26 @@ object \"D_72\" { sstore(slot, update_byte_slice_32_shift_0(sload(slot), prepare_store_t_int256(convertedValue_0))) } - /// @src 1:113:164 + /// @src 1:113:164 \"constructor(int _init2)...\" function constructor_D_72(var__init2_63) { - /// @src 1:107:108 + /// @src 1:107:108 \"3\" let expr_60 := 0x03 let _3 := convert_t_rational_3_by_1_to_t_int256(expr_60) - /// @src 1:113:164 + /// @src 1:113:164 \"constructor(int _init2)...\" constructor_C_54(_3) - /// @src 1:154:160 + /// @src 1:154:160 \"_init2\" let _4 := var__init2_63 let expr_67 := _4 - /// @src 1:142:160 + /// @src 1:142:160 \"stateVar += _init2\" let _5 := read_from_storage_split_offset_0_t_int256(0x00) let expr_68 := checked_add_t_int256(_5, expr_67) update_storage_value_offset_0t_int256_to_t_int256(0x00, expr_68) } - /// @src 1:91:166 + /// @src 1:91:166 \"contract D is C(3)...\" function cleanup_t_rational_42_by_1(value) -> cleaned { cleaned := value @@ -760,31 +760,31 @@ object \"D_72\" { converted := cleanup_t_int256(identity(cleanup_t_rational_42_by_1(value))) } - /// @src 0:175:223 + /// @src 0:175:223 \"constructor(int _init)...\" function constructor_C_54(var__init_12) { - /// @src 0:175:223 + /// @src 0:175:223 \"constructor(int _init)...\" - /// @src 0:147:149 + /// @src 0:147:149 \"42\" let expr_7 := 0x2a let _6 := convert_t_rational_42_by_1_to_t_int256(expr_7) mstore(128, _6) - /// @src 0:214:219 + /// @src 0:214:219 \"_init\" let _7 := var__init_12 let expr_16 := _7 - /// @src 0:203:219 + /// @src 0:203:219 \"stateVar = _init\" update_storage_value_offset_0t_int256_to_t_int256(0x00, expr_16) let expr_17 := expr_16 } - /// @src 1:91:166 + /// @src 1:91:166 \"contract D is C(3)...\" } /// @use-src 0:\"C\", 1:\"D\" object \"D_72_deployed\" { code { - /// @src 1:91:166 + /// @src 1:91:166 \"contract D is C(3)...\" mstore(64, 128) if iszero(lt(calldatasize(), 4)) @@ -892,7 +892,7 @@ object \"D_72\" { } - /// @src 0:152:171 + /// @src 0:152:171 \"int public stateVar\" function getter_fun_stateVar_10() -> ret { let slot := 0 @@ -901,7 +901,7 @@ object \"D_72\" { ret := read_from_storage_split_dynamic_t_int256(slot, offset) } - /// @src 1:91:166 + /// @src 1:91:166 \"contract D is C(3)...\" function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) @@ -923,9 +923,9 @@ object \"D_72\" { converted := cleanup_t_int256(identity(cleanup_t_rational_41_by_1(value))) } - /// @src 0:93:119 + /// @src 0:93:119 \"int constant constVar = 41\" function constant_constVar_5() -> ret { - /// @src 0:117:119 + /// @src 0:117:119 \"41\" let expr_4 := 0x29 let _2 := convert_t_rational_41_by_1_to_t_int256(expr_4) @@ -950,26 +950,26 @@ object \"D_72\" { sum := add(x, y) } - /// @src 0:226:302 + /// @src 0:226:302 \"function f() external pure returns (int)...\" function fun_f_30() -> var__23 { - /// @src 0:262:265 + /// @src 0:262:265 \"int\" let zero_t_int256_1 := zero_value_for_split_t_int256() var__23 := zero_t_int256_1 - /// @src 0:279:287 + /// @src 0:279:287 \"constVar\" let expr_25 := constant_constVar_5() - /// @src 0:290:298 + /// @src 0:290:298 \"immutVar\" let _3 := loadimmutable(\"8\") let expr_26 := _3 - /// @src 0:279:298 + /// @src 0:279:298 \"constVar + immutVar\" let expr_27 := checked_add_t_int256(expr_25, expr_26) - /// @src 0:272:298 + /// @src 0:272:298 \"return constVar + immutVar\" var__23 := expr_27 leave } - /// @src 1:91:166 + /// @src 1:91:166 \"contract D is C(3)...\" function shift_right_0_unsigned(value) -> newValue { newValue := @@ -1020,20 +1020,20 @@ object \"D_72\" { sstore(slot, update_byte_slice_32_shift_0(sload(slot), prepare_store_t_int256(convertedValue_0))) } - /// @src 0:304:341 + /// @src 0:304:341 \"modifier m()...\" function modifier_m_40(var__42) -> _5 { _5 := var__42 - /// @src 0:322:332 + /// @src 0:322:332 \"stateVar++\" let _7 := read_from_storage_split_offset_0_t_int256(0x00) let _6 := increment_t_int256(_7) update_storage_value_offset_0t_int256_to_t_int256(0x00, _6) let expr_33 := _7 - /// @src 0:336:337 + /// @src 0:336:337 \"_\" _5 := fun_f2_53_inner(var__42) } - /// @src 1:91:166 + /// @src 1:91:166 \"contract D is C(3)...\" function cleanup_t_uint160(value) -> cleaned { cleaned := and(value, 0xffffffffffffffffffffffffffffffffffffffff) @@ -1115,19 +1115,19 @@ object \"D_72\" { revert(pos, returndatasize()) } - /// @src 0:343:426 + /// @src 0:343:426 \"function f2() m public returns (int)...\" function fun_f2_53_inner(_8) -> var__42 { var__42 := _8 - /// @src 0:392:400 + /// @src 0:392:400 \"stateVar\" let _9 := read_from_storage_split_offset_0_t_int256(0x00) let expr_44 := _9 - /// @src 0:403:407 + /// @src 0:403:407 \"this\" let expr_45_address := address() - /// @src 0:403:409 + /// @src 0:403:409 \"this.f\" let expr_46_address := convert_t_contract$_C_$54_to_t_address(expr_45_address) let expr_46_functionSelector := 0x26121ff0 - /// @src 0:403:411 + /// @src 0:403:411 \"this.f()\" if iszero(extcodesize(expr_46_address)) { revert_error_0cc013b6b3b6beabea4e3a74a6d380f0df81852ca99887912475e1f66b2a2c20() } // storage for arguments and returned data @@ -1148,31 +1148,31 @@ object \"D_72\" { // decode return parameters from external try-call into retVars expr_47 := abi_decode_tuple_t_int256_fromMemory(_10, add(_10, returndatasize())) } - /// @src 0:392:411 + /// @src 0:392:411 \"stateVar + this.f()\" let expr_48 := checked_add_t_int256(expr_44, expr_47) - /// @src 0:414:422 + /// @src 0:414:422 \"immutVar\" let _13 := loadimmutable(\"8\") let expr_49 := _13 - /// @src 0:392:422 + /// @src 0:392:422 \"stateVar + this.f() + immutVar\" let expr_50 := checked_add_t_int256(expr_48, expr_49) - /// @src 0:385:422 + /// @src 0:385:422 \"return stateVar + this.f() + immutVar\" var__42 := expr_50 leave } - /// @src 1:91:166 + /// @src 1:91:166 \"contract D is C(3)...\" - /// @src 0:343:426 + /// @src 0:343:426 \"function f2() m public returns (int)...\" function fun_f2_53() -> var__42 { - /// @src 0:375:378 + /// @src 0:375:378 \"int\" let zero_t_int256_4 := zero_value_for_split_t_int256() var__42 := zero_t_int256_4 var__42 := modifier_m_40(var__42) } - /// @src 1:91:166 + /// @src 1:91:166 \"contract D is C(3)...\" } diff --git a/test/cmdlineTests/yul_source_locations_code_snippet_escaping/args b/test/cmdlineTests/yul_source_locations_code_snippet_escaping/args new file mode 100644 index 000000000..7282a28fe --- /dev/null +++ b/test/cmdlineTests/yul_source_locations_code_snippet_escaping/args @@ -0,0 +1 @@ +--ir-optimized --ir --optimize diff --git a/test/cmdlineTests/yul_source_locations_code_snippet_escaping/input.sol b/test/cmdlineTests/yul_source_locations_code_snippet_escaping/input.sol new file mode 100644 index 000000000..598f3b280 --- /dev/null +++ b/test/cmdlineTests/yul_source_locations_code_snippet_escaping/input.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0.0; + +// Intentionally badly wrapped and commented in weird places to get source locations inside code +// snippets in generated Yul. Also contains stuff that could break the assembly if not escaped properly. + +contract C {} contract D /** @src 0:96:165 "contract D {..." */ { + function f() /* @use-src 0:"input.sol", 1:"#utility.yul" @ast-id 15 */ public returns (string memory) { C c = new /// @src 0:149:156 "new C()" + C(); c; + string memory s = "/*"; s; return "/** @src 0:96:165 \"contract D {...\" */" + ; + } +} diff --git a/test/cmdlineTests/yul_source_locations_code_snippet_escaping/output b/test/cmdlineTests/yul_source_locations_code_snippet_escaping/output new file mode 100644 index 000000000..6563ceb3e --- /dev/null +++ b/test/cmdlineTests/yul_source_locations_code_snippet_escaping/output @@ -0,0 +1,578 @@ +IR: +/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + + +/// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" +object "C_2" { + code { + /// @src 0:265:278 "contract C {}" + mstore(64, 128) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_C_2() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_2_deployed"), datasize("C_2_deployed")) + + return(_1, datasize("C_2_deployed")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:265:278 "contract C {}" + function constructor_C_2() { + + /// @src 0:265:278 "contract C {}" + + } + /// @src 0:265:278 "contract C {}" + + } + /// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" + object "C_2_deployed" { + code { + /// @src 0:265:278 "contract C {}" + mstore(64, 128) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + default {} + } + if iszero(calldatasize()) { } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + } + + data ".metadata" hex"" + } + +} + + +Optimized IR: +/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + +/// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" +object "C_2" { + code { + { + /// @src 0:265:278 "contract C {}" + mstore(64, 128) + if callvalue() { revert(0, 0) } + let _1 := datasize("C_2_deployed") + codecopy(128, dataoffset("C_2_deployed"), _1) + return(128, _1) + } + } + /// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" + object "C_2_deployed" { + code { + { + /// @src 0:265:278 "contract C {}" + mstore(64, 128) + revert(0, 0) + } + } + data ".metadata" hex"" + } +} + +IR: +/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + + +/// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" +object "D_27" { + code { + /// @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." + mstore(64, 128) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_D_27() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("D_27_deployed"), datasize("D_27_deployed")) + + return(_1, datasize("D_27_deployed")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." + function constructor_D_27() { + + /// @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." + + } + /// @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." + + } + /// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" + object "D_27_deployed" { + code { + /// @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." + mstore(64, 128) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + case 0x26121ff0 + { + // f() + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := fun_f_26() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + } + + default {} + } + if iszero(calldatasize()) { } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + function revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() { + revert(0, 0) + } + + function abi_decode_tuple_(headStart, dataEnd) { + if slt(sub(dataEnd, headStart), 0) { revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b() } + + } + + function array_length_t_string_memory_ptr(value) -> length { + + length := mload(value) + + } + + function array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, length) -> updated_pos { + mstore(pos, length) + updated_pos := add(pos, 0x20) + } + + function copy_memory_to_memory(src, dst, length) { + let i := 0 + for { } lt(i, length) { i := add(i, 32) } + { + mstore(add(dst, i), mload(add(src, i))) + } + if gt(i, length) + { + // clear end + mstore(add(dst, length), 0) + } + } + + function round_up_to_mul_of_32(value) -> result { + result := and(add(value, 31), not(31)) + } + + function abi_encode_t_string_memory_ptr_to_t_string_memory_ptr_fromStack(value, pos) -> end { + let length := array_length_t_string_memory_ptr(value) + pos := array_storeLengthForEncoding_t_string_memory_ptr_fromStack(pos, length) + copy_memory_to_memory(add(value, 0x20), pos, length) + end := add(pos, round_up_to_mul_of_32(length)) + } + + function abi_encode_tuple_t_string_memory_ptr__to_t_string_memory_ptr__fromStack(headStart , value0) -> tail { + tail := add(headStart, 32) + + mstore(add(headStart, 0), sub(tail, headStart)) + tail := abi_encode_t_string_memory_ptr_to_t_string_memory_ptr_fromStack(value0, tail) + + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function zero_value_for_split_t_string_memory_ptr() -> ret { + ret := 96 + } + + function panic_error_0x41() { + mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856) + mstore(4, 0x41) + revert(0, 0x24) + } + + function abi_encode_tuple__to__fromStack(headStart ) -> tail { + tail := add(headStart, 0) + + } + + function revert_forward_1() { + let pos := allocate_unbounded() + returndatacopy(pos, 0, returndatasize()) + revert(pos, returndatasize()) + } + + function finalize_allocation(memPtr, size) { + let newFreePtr := add(memPtr, round_up_to_mul_of_32(size)) + // protect against overflow + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() } + mstore(64, newFreePtr) + } + + function allocate_memory(size) -> memPtr { + memPtr := allocate_unbounded() + finalize_allocation(memPtr, size) + } + + function array_allocation_size_t_string_memory_ptr(length) -> size { + // Make sure we can allocate memory without overflow + if gt(length, 0xffffffffffffffff) { panic_error_0x41() } + + size := round_up_to_mul_of_32(length) + + // add length slot + size := add(size, 0x20) + + } + + function allocate_memory_array_t_string_memory_ptr(length) -> memPtr { + let allocSize := array_allocation_size_t_string_memory_ptr(length) + memPtr := allocate_memory(allocSize) + + mstore(memPtr, length) + + } + + function store_literal_in_memory_c077635d0709aa1fd7cea2045028c270f982d687d1647e48e759eec32ec54a50(memPtr) { + + mstore(add(memPtr, 0), "/*") + + } + + function copy_literal_to_memory_c077635d0709aa1fd7cea2045028c270f982d687d1647e48e759eec32ec54a50() -> memPtr { + memPtr := allocate_memory_array_t_string_memory_ptr(2) + store_literal_in_memory_c077635d0709aa1fd7cea2045028c270f982d687d1647e48e759eec32ec54a50(add(memPtr, 32)) + } + + function convert_t_stringliteral_c077635d0709aa1fd7cea2045028c270f982d687d1647e48e759eec32ec54a50_to_t_string_memory_ptr() -> converted { + converted := copy_literal_to_memory_c077635d0709aa1fd7cea2045028c270f982d687d1647e48e759eec32ec54a50() + } + + function store_literal_in_memory_5bde9a896e3f09acac1496d16642fcdd887d2a000bf1ab18bdff3f17b91e320b(memPtr) { + + mstore(add(memPtr, 0), 0x2f2a2a204073726320303a39363a313635202022636f6e74726163742044207b) + + mstore(add(memPtr, 32), 0x2e2e2e22202a2f00000000000000000000000000000000000000000000000000) + + } + + function copy_literal_to_memory_5bde9a896e3f09acac1496d16642fcdd887d2a000bf1ab18bdff3f17b91e320b() -> memPtr { + memPtr := allocate_memory_array_t_string_memory_ptr(39) + store_literal_in_memory_5bde9a896e3f09acac1496d16642fcdd887d2a000bf1ab18bdff3f17b91e320b(add(memPtr, 32)) + } + + function convert_t_stringliteral_5bde9a896e3f09acac1496d16642fcdd887d2a000bf1ab18bdff3f17b91e320b_to_t_string_memory_ptr() -> converted { + converted := copy_literal_to_memory_5bde9a896e3f09acac1496d16642fcdd887d2a000bf1ab18bdff3f17b91e320b() + } + + /// @src 0:336:597 "function f() /* @use-src 0:\"input.sol\", 1:\"#utility.yul\" @ast-id 15 *\/ public returns (string memory) { C c = new /// @src 0:149:156 \"new C()\"..." + function fun_f_26() -> var__5_mpos { + /// @src 0:423:436 "string memory" + let zero_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr() + var__5_mpos := zero_t_string_memory_ptr_1_mpos + + /// @src 0:446:491 "new /// @src 0:149:156 \"new C()\"..." + let _2 := allocate_unbounded() + let _3 := add(_2, datasize("C_2")) + if or(gt(_3, 0xffffffffffffffff), lt(_3, _2)) { panic_error_0x41() } + datacopy(_2, dataoffset("C_2"), datasize("C_2")) + _3 := abi_encode_tuple__to__fromStack(_3) + + let expr_13_address := create(0, _2, sub(_3, _2)) + + if iszero(expr_13_address) { revert_forward_1() } + + /// @src 0:440:491 "C c = new /// @src 0:149:156 \"new C()\"..." + let var_c_9_address := expr_13_address + /// @src 0:493:494 "c" + let _4_address := var_c_9_address + let expr_15_address := _4_address + /// @src 0:504:526 "string memory s = \"/*\"" + let var_s_18_mpos := convert_t_stringliteral_c077635d0709aa1fd7cea2045028c270f982d687d1647e48e759eec32ec54a50_to_t_string_memory_ptr() + /// @src 0:528:529 "s" + let _5_mpos := var_s_18_mpos + let expr_21_mpos := _5_mpos + /// @src 0:531:581 "return \"/** @src 0:96:165 \\\"contract D {...\\\" *\/\"" + var__5_mpos := convert_t_stringliteral_5bde9a896e3f09acac1496d16642fcdd887d2a000bf1ab18bdff3f17b91e320b_to_t_string_memory_ptr() + leave + + } + /// @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." + + } + /*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + + /// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" + object "C_2" { + code { + /// @src 0:265:278 "contract C {}" + mstore(64, 128) + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + + constructor_C_2() + + let _1 := allocate_unbounded() + codecopy(_1, dataoffset("C_2_deployed"), datasize("C_2_deployed")) + + return(_1, datasize("C_2_deployed")) + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() { + revert(0, 0) + } + + /// @src 0:265:278 "contract C {}" + function constructor_C_2() { + + /// @src 0:265:278 "contract C {}" + + } + /// @src 0:265:278 "contract C {}" + + } + /// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" + object "C_2_deployed" { + code { + /// @src 0:265:278 "contract C {}" + mstore(64, 128) + + if iszero(lt(calldatasize(), 4)) + { + let selector := shift_right_224_unsigned(calldataload(0)) + switch selector + + default {} + } + if iszero(calldatasize()) { } + revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() + + function shift_right_224_unsigned(value) -> newValue { + newValue := + + shr(224, value) + + } + + function allocate_unbounded() -> memPtr { + memPtr := mload(64) + } + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + } + + data ".metadata" hex"" + } + + } + + data ".metadata" hex"" + } + +} + + +Optimized IR: +/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + +/// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" +object "D_27" { + code { + { + /// @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." + mstore(64, 128) + if callvalue() { revert(0, 0) } + let _1 := datasize("D_27_deployed") + codecopy(128, dataoffset("D_27_deployed"), _1) + return(128, _1) + } + } + /// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" + object "D_27_deployed" { + code { + { + /// @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." + mstore(64, 128) + if iszero(lt(calldatasize(), 4)) + { + let _1 := 0 + if eq(0x26121ff0, shr(224, calldataload(_1))) + { + if callvalue() { revert(_1, _1) } + if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } + /// @src 0:446:491 "new /// @src 0:149:156 \"new C()\"..." + let _2 := datasize("C_2") + let _3 := add(/** @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." */ 128, /** @src 0:446:491 "new /// @src 0:149:156 \"new C()\"..." */ _2) + if or(gt(_3, 0xffffffffffffffff), lt(_3, /** @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." */ 128)) + /// @src 0:446:491 "new /// @src 0:149:156 \"new C()\"..." + { panic_error_0x41() } + datacopy(/** @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." */ 128, /** @src 0:446:491 "new /// @src 0:149:156 \"new C()\"..." */ dataoffset("C_2"), _2) + if iszero(create(/** @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." */ _1, 128, /** @src 0:446:491 "new /// @src 0:149:156 \"new C()\"..." */ _2)) + { + /// @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." + let pos := mload(64) + returndatacopy(pos, _1, returndatasize()) + revert(pos, returndatasize()) + } + mstore(add(allocate_memory_array_string(), 32), "/*") + let memPtr := allocate_memory_array_string_482() + mstore(add(memPtr, 32), 0x2f2a2a204073726320303a39363a313635202022636f6e74726163742044207b) + mstore(add(memPtr, 64), shl(200, 0x2e2e2e22202a2f)) + let memPos := mload(64) + return(memPos, sub(abi_encode_string(memPos, memPtr), memPos)) + } + } + revert(0, 0) + } + function abi_encode_string(headStart, value0) -> tail + { + let _1 := 32 + mstore(headStart, _1) + let length := mload(value0) + mstore(add(headStart, _1), length) + let i := 0 + for { } lt(i, length) { i := add(i, _1) } + { + mstore(add(add(headStart, i), 64), mload(add(add(value0, i), _1))) + } + if gt(i, length) + { + mstore(add(add(headStart, length), 64), 0) + } + tail := add(add(headStart, and(add(length, 31), not(31))), 64) + } + function panic_error_0x41() + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 0x41) + revert(0, 0x24) + } + function allocate_memory_array_string() -> memPtr + { + let memPtr_1 := mload(64) + let newFreePtr := add(memPtr_1, 64) + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr_1)) { panic_error_0x41() } + mstore(64, newFreePtr) + memPtr := memPtr_1 + mstore(memPtr_1, 2) + } + function allocate_memory_array_string_482() -> memPtr + { + let memPtr_1 := mload(64) + let newFreePtr := add(memPtr_1, 96) + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr_1)) { panic_error_0x41() } + mstore(64, newFreePtr) + memPtr := memPtr_1 + mstore(memPtr_1, 39) + } + } + /// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" + object "C_2" { + code { + { + /// @src 0:265:278 "contract C {}" + mstore(64, 128) + if callvalue() { revert(0, 0) } + let _1 := datasize("C_2_deployed") + codecopy(128, dataoffset("C_2_deployed"), _1) + return(128, _1) + } + } + /// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" + object "C_2_deployed" { + code { + { + /// @src 0:265:278 "contract C {}" + mstore(64, 128) + revert(0, 0) + } + } + data ".metadata" hex"" + } + } + data ".metadata" hex"" + } +} diff --git a/test/cmdlineTests/yul_string_format_ascii/output.json b/test/cmdlineTests/yul_string_format_ascii/output.json index 4c42c4f78..221c9d306 100644 --- a/test/cmdlineTests/yul_string_format_ascii/output.json +++ b/test/cmdlineTests/yul_string_format_ascii/output.json @@ -9,7 +9,7 @@ /// @use-src 0:\"A\" object \"C_11\" { code { - /// @src 0:78:164 + /// @src 0:78:164 \"contract C { function f() external pure returns (string memory) { return \\\"abcabc\\\"; } }\" mstore(64, 128) if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } @@ -28,19 +28,19 @@ object \"C_11\" { revert(0, 0) } - /// @src 0:78:164 + /// @src 0:78:164 \"contract C { function f() external pure returns (string memory) { return \\\"abcabc\\\"; } }\" function constructor_C_11() { - /// @src 0:78:164 + /// @src 0:78:164 \"contract C { function f() external pure returns (string memory) { return \\\"abcabc\\\"; } }\" } - /// @src 0:78:164 + /// @src 0:78:164 \"contract C { function f() external pure returns (string memory) { return \\\"abcabc\\\"; } }\" } /// @use-src 0:\"A\" object \"C_11_deployed\" { code { - /// @src 0:78:164 + /// @src 0:78:164 \"contract C { function f() external pure returns (string memory) { return \\\"abcabc\\\"; } }\" mstore(64, 128) if iszero(lt(calldatasize(), 4)) @@ -192,18 +192,18 @@ object \"C_11\" { converted := copy_literal_to_memory_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21() } - /// @src 0:91:162 + /// @src 0:91:162 \"function f() external pure returns (string memory) { return \\\"abcabc\\\"; }\" function fun_f_10() -> var__5_mpos { - /// @src 0:127:140 + /// @src 0:127:140 \"string memory\" let zero_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr() var__5_mpos := zero_t_string_memory_ptr_1_mpos - /// @src 0:144:159 + /// @src 0:144:159 \"return \\\"abcabc\\\"\" var__5_mpos := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_string_memory_ptr() leave } - /// @src 0:78:164 + /// @src 0:78:164 \"contract C { function f() external pure returns (string memory) { return \\\"abcabc\\\"; } }\" } diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json index 0832d0e4e..0c8fbe701 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json @@ -9,7 +9,7 @@ /// @use-src 0:\"A\" object \"C_11\" { code { - /// @src 0:78:158 + /// @src 0:78:158 \"contract C { function f() external pure returns (bytes32) { return \\\"abcabc\\\"; } }\" mstore(64, 128) if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } @@ -28,19 +28,19 @@ object \"C_11\" { revert(0, 0) } - /// @src 0:78:158 + /// @src 0:78:158 \"contract C { function f() external pure returns (bytes32) { return \\\"abcabc\\\"; } }\" function constructor_C_11() { - /// @src 0:78:158 + /// @src 0:78:158 \"contract C { function f() external pure returns (bytes32) { return \\\"abcabc\\\"; } }\" } - /// @src 0:78:158 + /// @src 0:78:158 \"contract C { function f() external pure returns (bytes32) { return \\\"abcabc\\\"; } }\" } /// @use-src 0:\"A\" object \"C_11_deployed\" { code { - /// @src 0:78:158 + /// @src 0:78:158 \"contract C { function f() external pure returns (bytes32) { return \\\"abcabc\\\"; } }\" mstore(64, 128) if iszero(lt(calldatasize(), 4)) @@ -116,18 +116,18 @@ object \"C_11\" { converted := 0x6162636162630000000000000000000000000000000000000000000000000000 } - /// @src 0:91:156 + /// @src 0:91:156 \"function f() external pure returns (bytes32) { return \\\"abcabc\\\"; }\" function fun_f_10() -> var__5 { - /// @src 0:127:134 + /// @src 0:127:134 \"bytes32\" let zero_t_bytes32_1 := zero_value_for_split_t_bytes32() var__5 := zero_t_bytes32_1 - /// @src 0:138:153 + /// @src 0:138:153 \"return \\\"abcabc\\\"\" var__5 := convert_t_stringliteral_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21_to_t_bytes32() leave } - /// @src 0:78:158 + /// @src 0:78:158 \"contract C { function f() external pure returns (bytes32) { return \\\"abcabc\\\"; } }\" } diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json index f6c63057c..f495dc98a 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json @@ -9,7 +9,7 @@ /// @use-src 0:\"A\" object \"C_11\" { code { - /// @src 0:78:159 + /// @src 0:78:159 \"contract C { function f() external pure returns (bytes4) { return 0x61626364; } }\" mstore(64, 128) if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } @@ -28,19 +28,19 @@ object \"C_11\" { revert(0, 0) } - /// @src 0:78:159 + /// @src 0:78:159 \"contract C { function f() external pure returns (bytes4) { return 0x61626364; } }\" function constructor_C_11() { - /// @src 0:78:159 + /// @src 0:78:159 \"contract C { function f() external pure returns (bytes4) { return 0x61626364; } }\" } - /// @src 0:78:159 + /// @src 0:78:159 \"contract C { function f() external pure returns (bytes4) { return 0x61626364; } }\" } /// @use-src 0:\"A\" object \"C_11_deployed\" { code { - /// @src 0:78:159 + /// @src 0:78:159 \"contract C { function f() external pure returns (bytes4) { return 0x61626364; } }\" mstore(64, 128) if iszero(lt(calldatasize(), 4)) @@ -127,20 +127,20 @@ object \"C_11\" { converted := cleanup_t_bytes4(shift_left_224(cleanup_t_rational_1633837924_by_1(value))) } - /// @src 0:91:157 + /// @src 0:91:157 \"function f() external pure returns (bytes4) { return 0x61626364; }\" function fun_f_10() -> var__5 { - /// @src 0:127:133 + /// @src 0:127:133 \"bytes4\" let zero_t_bytes4_1 := zero_value_for_split_t_bytes4() var__5 := zero_t_bytes4_1 - /// @src 0:144:154 + /// @src 0:144:154 \"0x61626364\" let expr_7 := 0x61626364 - /// @src 0:137:154 + /// @src 0:137:154 \"return 0x61626364\" var__5 := convert_t_rational_1633837924_by_1_to_t_bytes4(expr_7) leave } - /// @src 0:78:159 + /// @src 0:78:159 \"contract C { function f() external pure returns (bytes4) { return 0x61626364; } }\" } diff --git a/test/cmdlineTests/yul_string_format_ascii_long/output.json b/test/cmdlineTests/yul_string_format_ascii_long/output.json index c1f4cd6e2..c32952157 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/output.json @@ -9,7 +9,7 @@ /// @use-src 0:\"A\" object \"C_11\" { code { - /// @src 0:78:243 + /// @src 0:78:243 \"contract C { function f() external pure returns (string memory) { return \\\"abcdabcdcafecafeabcdabcdcafecafeffffzzzzoooo0123456789,.<,>.?:;'[{]}|`~!@#$%^&*()-_=+\\\"; } }\" mstore(64, 128) if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } @@ -28,19 +28,19 @@ object \"C_11\" { revert(0, 0) } - /// @src 0:78:243 + /// @src 0:78:243 \"contract C { function f() external pure returns (string memory) { return \\\"abcdabcdcafecafeabcdabcdcafecafeffffzzzzoooo0123456789,.<,>.?:;'[{]}|`~!@#$%^&*()-_=+\\\"; } }\" function constructor_C_11() { - /// @src 0:78:243 + /// @src 0:78:243 \"contract C { function f() external pure returns (string memory) { return \\\"abcdabcdcafecafeabcdabcdcafecafeffffzzzzoooo0123456789,.<,>.?:;'[{]}|`~!@#$%^&*()-_=+\\\"; } }\" } - /// @src 0:78:243 + /// @src 0:78:243 \"contract C { function f() external pure returns (string memory) { return \\\"abcdabcdcafecafeabcdabcdcafecafeffffzzzzoooo0123456789,.<,>.?:;'[{]}|`~!@#$%^&*()-_=+\\\"; } }\" } /// @use-src 0:\"A\" object \"C_11_deployed\" { code { - /// @src 0:78:243 + /// @src 0:78:243 \"contract C { function f() external pure returns (string memory) { return \\\"abcdabcdcafecafeabcdabcdcafecafeffffzzzzoooo0123456789,.<,>.?:;'[{]}|`~!@#$%^&*()-_=+\\\"; } }\" mstore(64, 128) if iszero(lt(calldatasize(), 4)) @@ -196,18 +196,18 @@ object \"C_11\" { converted := copy_literal_to_memory_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571() } - /// @src 0:91:241 + /// @src 0:91:241 \"function f() external pure returns (string memory) { return \\\"abcdabcdcafecafeabcdabcdcafecafeffffzzzzoooo0123456789,.<,>.?:;'[{]}|`~!@#$%^&*()-_=+\\\"; }\" function fun_f_10() -> var__5_mpos { - /// @src 0:127:140 + /// @src 0:127:140 \"string memory\" let zero_t_string_memory_ptr_1_mpos := zero_value_for_split_t_string_memory_ptr() var__5_mpos := zero_t_string_memory_ptr_1_mpos - /// @src 0:144:238 + /// @src 0:144:238 \"return \\\"abcdabcdcafecafeabcdabcdcafecafeffffzzzzoooo0123456789,.<,>.?:;'[{]}|`~!@#$%^&*()-_=+\\\"\" var__5_mpos := convert_t_stringliteral_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571_to_t_string_memory_ptr() leave } - /// @src 0:78:243 + /// @src 0:78:243 \"contract C { function f() external pure returns (string memory) { return \\\"abcdabcdcafecafeabcdabcdcafecafeffffzzzzoooo0123456789,.<,>.?:;'[{]}|`~!@#$%^&*()-_=+\\\"; } }\" } diff --git a/test/cmdlineTests/yul_string_format_hex/output.json b/test/cmdlineTests/yul_string_format_hex/output.json index a5a46751a..98e3c8e46 100644 --- a/test/cmdlineTests/yul_string_format_hex/output.json +++ b/test/cmdlineTests/yul_string_format_hex/output.json @@ -9,7 +9,7 @@ /// @use-src 0:\"A\" object \"C_11\" { code { - /// @src 0:78:159 + /// @src 0:78:159 \"contract C { function f() external pure returns (bytes4) { return 0xaabbccdd; } }\" mstore(64, 128) if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } @@ -28,19 +28,19 @@ object \"C_11\" { revert(0, 0) } - /// @src 0:78:159 + /// @src 0:78:159 \"contract C { function f() external pure returns (bytes4) { return 0xaabbccdd; } }\" function constructor_C_11() { - /// @src 0:78:159 + /// @src 0:78:159 \"contract C { function f() external pure returns (bytes4) { return 0xaabbccdd; } }\" } - /// @src 0:78:159 + /// @src 0:78:159 \"contract C { function f() external pure returns (bytes4) { return 0xaabbccdd; } }\" } /// @use-src 0:\"A\" object \"C_11_deployed\" { code { - /// @src 0:78:159 + /// @src 0:78:159 \"contract C { function f() external pure returns (bytes4) { return 0xaabbccdd; } }\" mstore(64, 128) if iszero(lt(calldatasize(), 4)) @@ -127,20 +127,20 @@ object \"C_11\" { converted := cleanup_t_bytes4(shift_left_224(cleanup_t_rational_2864434397_by_1(value))) } - /// @src 0:91:157 + /// @src 0:91:157 \"function f() external pure returns (bytes4) { return 0xaabbccdd; }\" function fun_f_10() -> var__5 { - /// @src 0:127:133 + /// @src 0:127:133 \"bytes4\" let zero_t_bytes4_1 := zero_value_for_split_t_bytes4() var__5 := zero_t_bytes4_1 - /// @src 0:144:154 + /// @src 0:144:154 \"0xaabbccdd\" let expr_7 := 0xaabbccdd - /// @src 0:137:154 + /// @src 0:137:154 \"return 0xaabbccdd\" var__5 := convert_t_rational_2864434397_by_1_to_t_bytes4(expr_7) leave } - /// @src 0:78:159 + /// @src 0:78:159 \"contract C { function f() external pure returns (bytes4) { return 0xaabbccdd; } }\" } From 75c32863118de58b0543362325aca61ba0462ed2 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 5 Jul 2021 18:19:18 +0200 Subject: [PATCH 081/232] Optimized EVM Code Transform. --- libyul/AST.h | 16 +- libyul/CMakeLists.txt | 4 +- .../evm/OptimizedEVMCodeTransform.cpp | 513 ++++++++++++++++++ .../backends/evm/OptimizedEVMCodeTransform.h | 110 ++++ 4 files changed, 633 insertions(+), 10 deletions(-) create mode 100644 libyul/backends/evm/OptimizedEVMCodeTransform.cpp create mode 100644 libyul/backends/evm/OptimizedEVMCodeTransform.h diff --git a/libyul/AST.h b/libyul/AST.h index 54d44f6ae..486e11faa 100644 --- a/libyul/AST.h +++ b/libyul/AST.h @@ -83,18 +83,16 @@ struct Continue { std::shared_ptr debugData; }; /// Leave statement (valid within function) struct Leave { std::shared_ptr debugData; }; -struct LocationExtractor -{ - template langutil::SourceLocation operator()(T const& _node) const - { - return _node.debugData ? _node.debugData->location : langutil::SourceLocation{}; - } -}; - /// Extracts the source location from a Yul node. template inline langutil::SourceLocation locationOf(T const& _node) { - return std::visit(LocationExtractor(), _node); + return _node.debugData ? _node.debugData->location : langutil::SourceLocation{}; +} + +/// Extracts the source location from a Yul node. +template inline langutil::SourceLocation locationOf(std::variant const& _node) +{ + return std::visit([](auto const& _arg) { return locationOf(_arg); }, _node); } struct DebugDataExtractor diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index 278f80545..2cc5578e8 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -68,9 +68,11 @@ add_library(yul backends/evm/EVMMetrics.h backends/evm/NoOutputAssembly.h backends/evm/NoOutputAssembly.cpp + backends/evm/OptimizedEVMCodeTransform.cpp + backends/evm/OptimizedEVMCodeTransform.h backends/evm/StackHelpers.h - backends/evm/StackLayoutGenerator.h backends/evm/StackLayoutGenerator.cpp + backends/evm/StackLayoutGenerator.h backends/evm/VariableReferenceCounter.h backends/evm/VariableReferenceCounter.cpp backends/wasm/EVMToEwasmTranslator.cpp diff --git a/libyul/backends/evm/OptimizedEVMCodeTransform.cpp b/libyul/backends/evm/OptimizedEVMCodeTransform.cpp new file mode 100644 index 000000000..91f19ad62 --- /dev/null +++ b/libyul/backends/evm/OptimizedEVMCodeTransform.cpp @@ -0,0 +1,513 @@ +/* + 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 +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace solidity; +using namespace solidity::yul; +using namespace std; + +vector OptimizedEVMCodeTransform::run( + AbstractAssembly& _assembly, + AsmAnalysisInfo& _analysisInfo, + Block const& _block, + EVMDialect const& _dialect, + BuiltinContext& _builtinContext, + bool _useNamedLabelsForFunctions +) +{ + std::unique_ptr dfg = ControlFlowGraphBuilder::build(_analysisInfo, _dialect, _block); + StackLayout stackLayout = StackLayoutGenerator::run(*dfg); + OptimizedEVMCodeTransform optimizedCodeTransform( + _assembly, + _builtinContext, + _useNamedLabelsForFunctions, + *dfg, + stackLayout + ); + // Create initial entry layout. + optimizedCodeTransform.createStackLayout(stackLayout.blockInfos.at(dfg->entry).entryLayout); + optimizedCodeTransform(*dfg->entry); + for (Scope::Function const* function: dfg->functions) + optimizedCodeTransform(dfg->functionInfo.at(function)); + return move(optimizedCodeTransform.m_stackErrors); +} + +void OptimizedEVMCodeTransform::operator()(CFG::FunctionCall const& _call) +{ + // Validate stack. + { + yulAssert(m_assembly.stackHeight() == static_cast(m_stack.size()), ""); + yulAssert(m_stack.size() >= _call.function.get().arguments.size() + 1, ""); + // Assert that we got the correct arguments on stack for the call. + for (auto&& [arg, slot]: ranges::zip_view( + _call.functionCall.get().arguments | ranges::views::reverse, + m_stack | ranges::views::take_last(_call.functionCall.get().arguments.size()) + )) + validateSlot(slot, arg); + // Assert that we got the correct return label on stack. + auto const* returnLabelSlot = get_if( + &m_stack.at(m_stack.size() - _call.functionCall.get().arguments.size() - 1) + ); + yulAssert(returnLabelSlot && &returnLabelSlot->call.get() == &_call.functionCall.get(), ""); + } + + // Emit code. + { + m_assembly.setSourceLocation(locationOf(_call)); + m_assembly.appendJumpTo( + getFunctionLabel(_call.function), + static_cast(_call.function.get().returns.size() - _call.function.get().arguments.size()) - 1, + AbstractAssembly::JumpType::IntoFunction + ); + m_assembly.appendLabel(m_returnLabels.at(&_call.functionCall.get())); + } + + // Update stack. + { + // Remove arguments and return label from m_stack. + for (size_t i = 0; i < _call.function.get().arguments.size() + 1; ++i) + m_stack.pop_back(); + // Push return values to m_stack. + for (size_t index: ranges::views::iota(0u, _call.function.get().returns.size())) + m_stack.emplace_back(TemporarySlot{_call.functionCall, index}); + yulAssert(m_assembly.stackHeight() == static_cast(m_stack.size()), ""); + } +} + +void OptimizedEVMCodeTransform::operator()(CFG::BuiltinCall const& _call) +{ + // Validate stack. + { + yulAssert(m_assembly.stackHeight() == static_cast(m_stack.size()), ""); + yulAssert(m_stack.size() >= _call.arguments, ""); + // Assert that we got a correct stack for the call. + for (auto&& [arg, slot]: ranges::zip_view( + _call.functionCall.get().arguments | + ranges::views::enumerate | + ranges::views::filter(util::mapTuple([&](size_t idx, auto&) -> bool { + return !_call.builtin.get().literalArgument(idx); + })) | + ranges::views::reverse | + ranges::views::values, + m_stack | ranges::views::take_last(_call.arguments) + )) + validateSlot(slot, arg); + } + + // Emit code. + { + m_assembly.setSourceLocation(locationOf(_call)); + static_cast(_call.builtin.get()).generateCode( + _call.functionCall, + m_assembly, + m_builtinContext + ); + } + + // Update stack. + { + // Remove arguments from m_stack. + for (size_t i = 0; i < _call.arguments; ++i) + m_stack.pop_back(); + // Push return values to m_stack. + for (size_t index: ranges::views::iota(0u, _call.builtin.get().returns.size())) + m_stack.emplace_back(TemporarySlot{_call.functionCall, index}); + yulAssert(m_assembly.stackHeight() == static_cast(m_stack.size()), ""); + } +} + +void OptimizedEVMCodeTransform::operator()(CFG::Assignment const& _assignment) +{ + yulAssert(m_assembly.stackHeight() == static_cast(m_stack.size()), ""); + + // Invalidate occurrences of the assigned variables. + for (auto& currentSlot: m_stack) + if (VariableSlot const* varSlot = get_if(¤tSlot)) + if (util::contains(_assignment.variables, *varSlot)) + currentSlot = JunkSlot{}; + + // Assign variables to current stack top. + yulAssert(m_stack.size() >= _assignment.variables.size(), ""); + for (auto&& [currentSlot, varSlot]: ranges::zip_view( + m_stack | ranges::views::take_last(_assignment.variables.size()), + _assignment.variables + )) + currentSlot = varSlot; +} + +OptimizedEVMCodeTransform::OptimizedEVMCodeTransform( + AbstractAssembly& _assembly, + BuiltinContext& _builtinContext, + bool _useNamedLabelsForFunctions, + CFG const& _dfg, + StackLayout const& _stackLayout +): + m_assembly(_assembly), + m_builtinContext(_builtinContext), + m_useNamedLabelsForFunctions(_useNamedLabelsForFunctions), + m_dfg(_dfg), + m_stackLayout(_stackLayout) +{ +} + +void OptimizedEVMCodeTransform::assertLayoutCompatibility(Stack const& _currentStack, Stack const& _desiredStack) +{ + yulAssert(_currentStack.size() == _desiredStack.size(), ""); + for (auto&& [currentSlot, desiredSlot]: ranges::zip_view(_currentStack, _desiredStack)) + yulAssert(holds_alternative(desiredSlot) || currentSlot == desiredSlot, ""); +} + +AbstractAssembly::LabelID OptimizedEVMCodeTransform::getFunctionLabel(Scope::Function const& _function) +{ + CFG::FunctionInfo const& functionInfo = m_dfg.functionInfo.at(&_function); + if (!m_functionLabels.count(&functionInfo)) + m_functionLabels[&functionInfo] = m_useNamedLabelsForFunctions ? m_assembly.namedLabel( + functionInfo.function.name.str(), + functionInfo.function.arguments.size(), + functionInfo.function.returns.size(), + {} + ) : m_assembly.newLabelId(); + return m_functionLabels[&functionInfo]; +} + +void OptimizedEVMCodeTransform::validateSlot(StackSlot const& _slot, Expression const& _expression) +{ + std::visit(util::GenericVisitor{ + [&](yul::Literal const& _literal) { + auto* literalSlot = get_if(&_slot); + yulAssert(literalSlot && valueOfLiteral(_literal) == literalSlot->value, ""); + }, + [&](yul::Identifier const& _identifier) { + auto* variableSlot = get_if(&_slot); + yulAssert(variableSlot && variableSlot->variable.get().name == _identifier.name, ""); + }, + [&](yul::FunctionCall const& _call) { + auto* temporarySlot = get_if(&_slot); + yulAssert(temporarySlot && &temporarySlot->call.get() == &_call && temporarySlot->index == 0, ""); + } + }, _expression); +} + +void OptimizedEVMCodeTransform::createStackLayout(Stack _targetStack) +{ + static constexpr auto slotVariableName = [](StackSlot const& _slot) { + return std::visit(util::GenericVisitor{ + [](VariableSlot const& _var) { return _var.variable.get().name; }, + [](auto const&) { return YulString{}; } + }, _slot); + }; + + yulAssert(m_assembly.stackHeight() == static_cast(m_stack.size()), ""); + // ::createStackLayout asserts that it has successfully achieved the target layout. + ::createStackLayout( + m_stack, + _targetStack | ranges::to, + // Swap callback. + [&](unsigned _i) + { + yulAssert(static_cast(m_stack.size()) == m_assembly.stackHeight(), ""); + yulAssert(_i > 0 && _i < m_stack.size(), ""); + if (_i <= 16) + m_assembly.appendInstruction(evmasm::swapInstruction(_i)); + else + { + int deficit = static_cast(_i) - 16; + StackSlot const& deepSlot = m_stack.at(m_stack.size() - _i - 1); + YulString varNameDeep = slotVariableName(deepSlot); + YulString varNameTop = slotVariableName(m_stack.back()); + string msg = + "Cannot swap " + (varNameDeep.empty() ? "Slot " + stackSlotToString(deepSlot) : "Variable " + varNameDeep.str()) + + " with " + (varNameTop.empty() ? "Slot " + stackSlotToString(m_stack.back()) : "Variable " + varNameTop.str()) + + ": too deep in the stack by " + to_string(deficit) + " slots in " + stackToString(m_stack); + m_stackErrors.emplace_back(StackTooDeepError( + m_currentFunctionInfo ? m_currentFunctionInfo->function.name : YulString{}, + varNameDeep.empty() ? varNameTop : varNameDeep, + deficit, + msg + )); + m_assembly.markAsInvalid(); + } + }, + // Push or dup callback. + [&](StackSlot const& _slot) + { + yulAssert(static_cast(m_stack.size()) == m_assembly.stackHeight(), ""); + + // Dup the slot, if already on stack and reachable. + if (auto depth = util::findOffset(m_stack | ranges::views::reverse, _slot)) + { + if (*depth < 16) + { + m_assembly.appendInstruction(evmasm::dupInstruction(static_cast(*depth + 1))); + return; + } + else if (!canBeFreelyGenerated(_slot)) + { + int deficit = static_cast(*depth - 15); + YulString varName = slotVariableName(_slot); + string msg = + (varName.empty() ? "Slot " + stackSlotToString(_slot) : "Variable " + varName.str()) + + " is " + to_string(*depth - 15) + " too deep in the stack " + stackToString(m_stack); + m_stackErrors.emplace_back(StackTooDeepError( + m_currentFunctionInfo ? m_currentFunctionInfo->function.name : YulString{}, + varName, + deficit, + msg + )); + m_assembly.markAsInvalid(); + m_assembly.appendConstant(u256(0xCAFFEE)); + return; + } + // else: the slot is too deep in stack, but can be freely generated, we fall through to push it again. + } + + // The slot can be freely generated or is an unassigned return variable. Push it. + std::visit(util::GenericVisitor{ + [&](LiteralSlot const& _literal) + { + m_assembly.setSourceLocation(locationOf(_literal)); + m_assembly.appendConstant(_literal.value); + }, + [&](FunctionReturnLabelSlot const&) + { + yulAssert(false, "Cannot produce function return label."); + }, + [&](FunctionCallReturnLabelSlot const& _returnLabel) + { + if (!m_returnLabels.count(&_returnLabel.call.get())) + m_returnLabels[&_returnLabel.call.get()] = m_assembly.newLabelId(); + m_assembly.setSourceLocation(locationOf(_returnLabel.call.get())); + m_assembly.appendLabelReference(m_returnLabels.at(&_returnLabel.call.get())); + }, + [&](VariableSlot const& _variable) + { + if (m_currentFunctionInfo && util::contains(m_currentFunctionInfo->returnVariables, _variable)) + { + m_assembly.setSourceLocation(locationOf(_variable)); + m_assembly.appendConstant(0); + return; + } + yulAssert(false, "Variable not found on stack."); + }, + [&](TemporarySlot const&) + { + yulAssert(false, "Function call result requested, but not found on stack."); + }, + [&](JunkSlot const&) + { + // Note: this will always be popped, so we can push anything. + m_assembly.appendInstruction(evmasm::Instruction::CODESIZE); + } + }, _slot); + }, + // Pop callback. + [&]() + { + m_assembly.appendInstruction(evmasm::Instruction::POP); + } + ); + yulAssert(m_assembly.stackHeight() == static_cast(m_stack.size()), ""); +} + +void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block) +{ + // Assert that this is the first visit of the block and mark as generated. + yulAssert(m_generated.insert(&_block).second, ""); + + auto const& blockInfo = m_stackLayout.blockInfos.at(&_block); + + // Assert that the stack is valid for entering the block. + assertLayoutCompatibility(m_stack, blockInfo.entryLayout); + m_stack = blockInfo.entryLayout; // Might set some slots to junk, if not required by the block. + yulAssert(static_cast(m_stack.size()) == m_assembly.stackHeight(), ""); + + // Emit jump label, if required. + if (auto label = util::valueOrNullptr(m_blockLabels, &_block)) + m_assembly.appendLabel(*label); + + for (auto const& operation: _block.operations) + { + // Create required layout for entering the operation. + createStackLayout(m_stackLayout.operationEntryLayout.at(&operation)); + + // Assert that we have the inputs of the operation on stack top. + yulAssert(static_cast(m_stack.size()) == m_assembly.stackHeight(), ""); + yulAssert(m_stack.size() >= operation.input.size(), ""); + size_t baseHeight = m_stack.size() - operation.input.size(); + assertLayoutCompatibility( + m_stack | ranges::views::take_last(operation.input.size()) | ranges::to, + operation.input + ); + + // Perform the operation. + std::visit(*this, operation.operation); + + // Assert that the operation produced its proclaimed output. + yulAssert(static_cast(m_stack.size()) == m_assembly.stackHeight(), ""); + yulAssert(m_stack.size() == baseHeight + operation.output.size(), ""); + yulAssert(m_stack.size() >= operation.output.size(), ""); + assertLayoutCompatibility( + m_stack | ranges::views::take_last(operation.output.size()) | ranges::to, + operation.output + ); + } + + // Exit the block. + std::visit(util::GenericVisitor{ + [&](CFG::BasicBlock::MainExit const&) + { + m_assembly.appendInstruction(evmasm::Instruction::STOP); + }, + [&](CFG::BasicBlock::Jump const& _jump) + { + // Create the stack expected at the jump target. + createStackLayout(m_stackLayout.blockInfos.at(_jump.target).entryLayout); + + // If this is the only jump to the block, we do not need a label and can directly continue with the target block. + if (!m_blockLabels.count(_jump.target) && _jump.target->entries.size() == 1) + { + yulAssert(!_jump.backwards, ""); + (*this)(*_jump.target); + } + else + { + // Generate a jump label for the target, if not already present. + if (!m_blockLabels.count(_jump.target)) + m_blockLabels[_jump.target] = m_assembly.newLabelId(); + + // If we already have generated the target block, jump to it, otherwise generate it in place. + if (m_generated.count(_jump.target)) + m_assembly.appendJumpTo(m_blockLabels[_jump.target]); + else + (*this)(*_jump.target); + } + }, + [&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) + { + // Create the shared entry layout of the jump targets, which is stored as exit layout of the current block. + createStackLayout(blockInfo.exitLayout); + + // Create labels for the targets, if not already present. + if (!m_blockLabels.count(_conditionalJump.nonZero)) + m_blockLabels[_conditionalJump.nonZero] = m_assembly.newLabelId(); + if (!m_blockLabels.count(_conditionalJump.zero)) + m_blockLabels[_conditionalJump.zero] = m_assembly.newLabelId(); + + // Assert that we have the correct condition on stack. + yulAssert(!m_stack.empty(), ""); + yulAssert(m_stack.back() == _conditionalJump.condition, ""); + + // Emit the conditional jump to the non-zero label and update the stored stack. + m_assembly.appendJumpToIf(m_blockLabels[_conditionalJump.nonZero]); + m_stack.pop_back(); + + // Assert that we have a valid stack for both jump targets. + assertLayoutCompatibility(m_stack, m_stackLayout.blockInfos.at(_conditionalJump.nonZero).entryLayout); + assertLayoutCompatibility(m_stack, m_stackLayout.blockInfos.at(_conditionalJump.zero).entryLayout); + + { + // Restore the stack afterwards for the non-zero case below. + ScopeGuard stackRestore([storedStack = m_stack, this]() { + m_stack = move(storedStack); + m_assembly.setStackHeight(static_cast(m_stack.size())); + }); + + // If we have already generated the zero case, jump to it, otherwise generate it in place. + if (m_generated.count(_conditionalJump.zero)) + m_assembly.appendJumpTo(m_blockLabels[_conditionalJump.zero]); + else + (*this)(*_conditionalJump.zero); + } + // Note that each block visit terminates control flow, so we cannot fall through from the zero case. + + // Generate the non-zero block, if not done already. + if (!m_generated.count(_conditionalJump.nonZero)) + (*this)(*_conditionalJump.nonZero); + }, + [&](CFG::BasicBlock::FunctionReturn const& _functionReturn) + { + yulAssert(m_currentFunctionInfo, ""); + yulAssert(m_currentFunctionInfo == _functionReturn.info, ""); + + // Construct the function return layout, which is fully determined by the function signature. + Stack exitStack = m_currentFunctionInfo->returnVariables | ranges::views::transform([](auto const& _varSlot){ + return StackSlot{_varSlot}; + }) | ranges::to; + exitStack.emplace_back(FunctionReturnLabelSlot{_functionReturn.info->function}); + + // Create the function return layout and jump. + m_assembly.setSourceLocation(locationOf(*m_currentFunctionInfo)); + createStackLayout(exitStack); + m_assembly.setSourceLocation(locationOf(*m_currentFunctionInfo)); + m_assembly.appendJump(0, AbstractAssembly::JumpType::OutOfFunction); + }, + [&](CFG::BasicBlock::Terminated const&) + { + // Assert that the last builtin call was in fact terminating. + yulAssert(!_block.operations.empty(), ""); + CFG::BuiltinCall const* builtinCall = get_if(&_block.operations.back().operation); + yulAssert(builtinCall, ""); + yulAssert(builtinCall->builtin.get().controlFlowSideEffects.terminates, ""); + } + }, _block.exit); + // TODO: We could assert that the last emitted assembly item terminated or was an (unconditional) jump. + // But currently AbstractAssembly does not allow peeking at the last emitted assembly item. + m_stack.clear(); + m_assembly.setStackHeight(0); +} + +void OptimizedEVMCodeTransform::operator()(CFG::FunctionInfo const& _functionInfo) +{ + yulAssert(!m_currentFunctionInfo, ""); + ScopedSaveAndRestore currentFunctionInfoRestore(m_currentFunctionInfo, &_functionInfo); + + yulAssert(m_stack.empty() && m_assembly.stackHeight() == 0, ""); + + // Create function entry layout in m_stack. + m_stack.emplace_back(FunctionReturnLabelSlot{_functionInfo.function}); + for (auto const& param: _functionInfo.parameters | ranges::views::reverse) + m_stack.emplace_back(param); + m_assembly.setStackHeight(static_cast(m_stack.size())); + + m_assembly.setSourceLocation(locationOf(_functionInfo)); + m_assembly.appendLabel(getFunctionLabel(_functionInfo.function)); + + // Create the entry layout of the function body block and visit. + createStackLayout(m_stackLayout.blockInfos.at(_functionInfo.entry).entryLayout); + (*this)(*_functionInfo.entry); + + m_stack.clear(); + m_assembly.setStackHeight(0); +} diff --git a/libyul/backends/evm/OptimizedEVMCodeTransform.h b/libyul/backends/evm/OptimizedEVMCodeTransform.h new file mode 100644 index 000000000..bbbfcc363 --- /dev/null +++ b/libyul/backends/evm/OptimizedEVMCodeTransform.h @@ -0,0 +1,110 @@ +/* + 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 +/** + * Code generator for translating Yul / inline assembly to EVM. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +namespace solidity::langutil +{ +class ErrorReporter; +} + +namespace solidity::yul +{ +struct AsmAnalysisInfo; +struct StackLayout; + +class OptimizedEVMCodeTransform +{ +public: + [[nodiscard]] static std::vector run( + AbstractAssembly& _assembly, + AsmAnalysisInfo& _analysisInfo, + Block const& _block, + EVMDialect const& _dialect, + BuiltinContext& _builtinContext, + bool _useNamedLabelsForFunctions = false + ); + + /// Generate code for the function call @a _call. Only public for using with std::visit. + void operator()(CFG::FunctionCall const& _call); + /// Generate code for the builtin call @a _call. Only public for using with std::visit. + void operator()(CFG::BuiltinCall const& _call); + /// Generate code for the assignment @a _assignment. Only public for using with std::visit. + void operator()(CFG::Assignment const& _assignment); +private: + OptimizedEVMCodeTransform( + AbstractAssembly& _assembly, + BuiltinContext& _builtinContext, + bool _useNamedLabelsForFunctions, + CFG const& _dfg, + StackLayout const& _stackLayout + ); + + /// Assert that it is valid to transition from @a _currentStack to @a _desiredStack. + /// That is @a _currentStack matches each slot in @a _desiredStack that is not a JunkSlot exactly. + static void assertLayoutCompatibility(Stack const& _currentStack, Stack const& _desiredStack); + /// @returns The label of the entry point of the given @a _function. + /// Creates and stores a new label, if none exists already. + AbstractAssembly::LabelID getFunctionLabel(Scope::Function const& _function); + /// Assert that @a _slot contains the value of @a _expression. + static void validateSlot(StackSlot const& _slot, Expression const& _expression); + + /// Shuffles m_stack to the desired @a _targetStack while emitting the shuffling code to m_assembly. + void createStackLayout(Stack _targetStack); + + /// Generate code for the given block @a _block. + /// Expects the current stack layout m_stack to be a stack layout that is compatible with the + /// entry layout expected by the block. + /// Recursively generates code for blocks that are jumped to. + /// The last emitted assembly instruction is always an unconditional jump or terminating. + /// Always exits with an empty stack layout. + void operator()(CFG::BasicBlock const& _block); + + /// Generate code for the given function. + /// Resets m_stack. + void operator()(CFG::FunctionInfo const& _functionInfo); + + AbstractAssembly& m_assembly; + BuiltinContext& m_builtinContext; + bool m_useNamedLabelsForFunctions = true; + CFG const& m_dfg; + StackLayout const& m_stackLayout; + Stack m_stack; + std::map m_returnLabels; + std::map m_blockLabels; + std::map m_functionLabels; + /// Set of blocks already generated. If any of the contained blocks is ever jumped to, m_blockLabels should + /// contain a jump label for it. + std::set m_generated; + CFG::FunctionInfo const* m_currentFunctionInfo = nullptr; + std::vector m_stackErrors; +}; + +} From 854b8b65b525aa62d08b5e3126253759875e24d1 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Thu, 9 Sep 2021 16:49:36 +0200 Subject: [PATCH 082/232] Better source locations in Yul ControlFlowGraph and OptimizedEVMCodeTransform. --- libyul/AST.h | 14 +-- libyul/backends/evm/ControlFlowGraph.h | 13 +- .../backends/evm/ControlFlowGraphBuilder.cpp | 118 ++++++++++-------- libyul/backends/evm/ControlFlowGraphBuilder.h | 19 +-- .../evm/OptimizedEVMCodeTransform.cpp | 23 ++-- .../backends/evm/OptimizedEVMCodeTransform.h | 3 +- 6 files changed, 108 insertions(+), 82 deletions(-) diff --git a/libyul/AST.h b/libyul/AST.h index 486e11faa..01eece34d 100644 --- a/libyul/AST.h +++ b/libyul/AST.h @@ -95,18 +95,16 @@ template inline langutil::SourceLocation locationOf(std::variant return std::visit([](auto const& _arg) { return locationOf(_arg); }, _node); } -struct DebugDataExtractor +/// Extracts the debug data from a Yul node. +template inline std::shared_ptr debugDataOf(T const& _node) { - template std::shared_ptr const& operator()(T const& _node) const - { - return _node.debugData; - } -}; + return _node.debugData; +} /// Extracts the debug data from a Yul node. -template inline std::shared_ptr const& debugDataOf(T const& _node) +template inline std::shared_ptr debugDataOf(std::variant const& _node) { - return std::visit(DebugDataExtractor(), _node); + return std::visit([](auto const& _arg) { return debugDataOf(_arg); }, _node); } } diff --git a/libyul/backends/evm/ControlFlowGraph.h b/libyul/backends/evm/ControlFlowGraph.h index b78a37843..0099b9924 100644 --- a/libyul/backends/evm/ControlFlowGraph.h +++ b/libyul/backends/evm/ControlFlowGraph.h @@ -172,18 +172,25 @@ struct CFG struct MainExit {}; struct ConditionalJump { + std::shared_ptr debugData; StackSlot condition; BasicBlock* nonZero = nullptr; BasicBlock* zero = nullptr; }; struct Jump { + std::shared_ptr debugData; BasicBlock* target = nullptr; /// The only backwards jumps are jumps from loop post to loop condition. bool backwards = false; }; - struct FunctionReturn { CFG::FunctionInfo* info = nullptr; }; + struct FunctionReturn + { + std::shared_ptr debugData; + CFG::FunctionInfo* info = nullptr; + }; struct Terminated {}; + std::shared_ptr debugData; std::vector entries; std::vector operations; std::variant exit = MainExit{}; @@ -216,9 +223,9 @@ struct CFG /// the switch case literals when transforming the control flow of a switch to a sequence of conditional jumps. std::list ghostCalls; - BasicBlock& makeBlock() + BasicBlock& makeBlock(std::shared_ptr _debugData) { - return blocks.emplace_back(BasicBlock{}); + return blocks.emplace_back(BasicBlock{move(_debugData), {}, {}}); } }; diff --git a/libyul/backends/evm/ControlFlowGraphBuilder.cpp b/libyul/backends/evm/ControlFlowGraphBuilder.cpp index f4077f177..fd5b4682d 100644 --- a/libyul/backends/evm/ControlFlowGraphBuilder.cpp +++ b/libyul/backends/evm/ControlFlowGraphBuilder.cpp @@ -134,7 +134,7 @@ std::unique_ptr ControlFlowGraphBuilder::build( ) { auto result = std::make_unique(); - result->entry = &result->makeBlock(); + result->entry = &result->makeBlock(debugDataOf(_block)); ControlFlowGraphBuilder builder(*result, _analysisInfo, _dialect); builder.m_currentBlock = result->entry; @@ -233,7 +233,7 @@ void ControlFlowGraphBuilder::operator()(ExpressionStatement const& _exprStmt) if (builtin->controlFlowSideEffects.terminates) { m_currentBlock->exit = CFG::BasicBlock::Terminated{}; - m_currentBlock = &m_graph.makeBlock(); + m_currentBlock = &m_graph.makeBlock(debugDataOf(*m_currentBlock)); } } @@ -246,15 +246,19 @@ void ControlFlowGraphBuilder::operator()(Block const& _block) void ControlFlowGraphBuilder::operator()(If const& _if) { - auto&& [ifBranch, afterIf] = makeConditionalJump(std::visit(*this, *_if.condition)); - m_currentBlock = ifBranch; + auto& ifBranch = m_graph.makeBlock(debugDataOf(_if.body)); + auto& afterIf = m_graph.makeBlock(debugDataOf(*m_currentBlock)); + makeConditionalJump(debugDataOf(_if), std::visit(*this, *_if.condition), ifBranch, afterIf); + m_currentBlock = &ifBranch; (*this)(_if.body); - jump(*afterIf); + jump(debugDataOf(_if.body), afterIf); } void ControlFlowGraphBuilder::operator()(Switch const& _switch) { yulAssert(m_currentBlock, ""); + shared_ptr preSwitchDebugData = debugDataOf(_switch); + auto ghostVariableId = m_graph.ghostVariables.size(); YulString ghostVariableName("GHOST[" + to_string(ghostVariableId) + "]"); auto& ghostVar = m_graph.ghostVariables.emplace_back(Scope::Variable{""_yulstring, ghostVariableName}); @@ -273,43 +277,46 @@ void ControlFlowGraphBuilder::operator()(Switch const& _switch) // Artificially generate: // eq(, ) - auto makeValueCompare = [&](Literal const& _value) { + auto makeValueCompare = [&](Case const& _case) { yul::FunctionCall const& ghostCall = m_graph.ghostCalls.emplace_back(yul::FunctionCall{ - _value.debugData, + debugDataOf(_case), yul::Identifier{{}, "eq"_yulstring}, - {_value, Identifier{{}, ghostVariableName}} + {*_case.value, Identifier{{}, ghostVariableName}} }); CFG::Operation& operation = m_currentBlock->operations.emplace_back(CFG::Operation{ - Stack{ghostVarSlot, LiteralSlot{valueOfLiteral(_value), _value.debugData}}, + Stack{ghostVarSlot, LiteralSlot{valueOfLiteral(*_case.value), debugDataOf(*_case.value)}}, Stack{TemporarySlot{ghostCall, 0}}, - CFG::BuiltinCall{_switch.debugData, *equalityBuiltin, ghostCall, 2}, + CFG::BuiltinCall{debugDataOf(_case), *equalityBuiltin, ghostCall, 2}, }); return operation.output.front(); }; - CFG::BasicBlock& afterSwitch = m_graph.makeBlock(); + CFG::BasicBlock& afterSwitch = m_graph.makeBlock(preSwitchDebugData); yulAssert(!_switch.cases.empty(), ""); for (auto const& switchCase: _switch.cases | ranges::views::drop_last(1)) { yulAssert(switchCase.value, ""); - auto&& [caseBranch, elseBranch] = makeConditionalJump(makeValueCompare(*switchCase.value)); - m_currentBlock = caseBranch; + auto& caseBranch = m_graph.makeBlock(debugDataOf(switchCase.body)); + auto& elseBranch = m_graph.makeBlock(debugDataOf(_switch)); + makeConditionalJump(debugDataOf(switchCase), makeValueCompare(switchCase), caseBranch, elseBranch); + m_currentBlock = &caseBranch; (*this)(switchCase.body); - jump(afterSwitch); - m_currentBlock = elseBranch; + jump(debugDataOf(switchCase.body), afterSwitch); + m_currentBlock = &elseBranch; } Case const& switchCase = _switch.cases.back(); if (switchCase.value) { - CFG::BasicBlock& caseBranch = m_graph.makeBlock(); - makeConditionalJump(makeValueCompare(*switchCase.value), caseBranch, afterSwitch); + CFG::BasicBlock& caseBranch = m_graph.makeBlock(debugDataOf(switchCase.body)); + makeConditionalJump(debugDataOf(switchCase), makeValueCompare(switchCase), caseBranch, afterSwitch); m_currentBlock = &caseBranch; } (*this)(switchCase.body); - jump(afterSwitch); + jump(debugDataOf(switchCase.body), afterSwitch); } void ControlFlowGraphBuilder::operator()(ForLoop const& _loop) { + shared_ptr preLoopDebugData = debugDataOf(_loop); ScopedSaveAndRestore scopeRestore(m_scope, m_info.scopes.at(&_loop.pre).get()); (*this)(_loop.pre); @@ -317,10 +324,10 @@ void ControlFlowGraphBuilder::operator()(ForLoop const& _loop) if (auto const* literalCondition = get_if(_loop.condition.get())) constantCondition = valueOfLiteral(*literalCondition) != 0; - CFG::BasicBlock& loopCondition = m_graph.makeBlock(); - CFG::BasicBlock& loopBody = m_graph.makeBlock(); - CFG::BasicBlock& post = m_graph.makeBlock(); - CFG::BasicBlock& afterLoop = m_graph.makeBlock(); + CFG::BasicBlock& loopCondition = m_graph.makeBlock(debugDataOf(*_loop.condition)); + CFG::BasicBlock& loopBody = m_graph.makeBlock(debugDataOf(_loop.body)); + CFG::BasicBlock& post = m_graph.makeBlock(debugDataOf(_loop.post)); + CFG::BasicBlock& afterLoop = m_graph.makeBlock(preLoopDebugData); ScopedSaveAndRestore scopedSaveAndRestore(m_forLoopInfo, ForLoopInfo{afterLoop, post}); @@ -328,48 +335,49 @@ void ControlFlowGraphBuilder::operator()(ForLoop const& _loop) { if (*constantCondition) { - jump(loopBody); + jump(debugDataOf(_loop.pre), loopBody); (*this)(_loop.body); - jump(post); + jump(debugDataOf(_loop.body), post); (*this)(_loop.post); - jump(loopBody, true); + jump(debugDataOf(_loop.post), loopBody, true); } else - jump(afterLoop); + jump(debugDataOf(_loop.pre), afterLoop); } else { - jump(loopCondition); - makeConditionalJump(std::visit(*this, *_loop.condition), loopBody, afterLoop); + jump(debugDataOf(_loop.pre), loopCondition); + makeConditionalJump(debugDataOf(*_loop.condition), std::visit(*this, *_loop.condition), loopBody, afterLoop); m_currentBlock = &loopBody; (*this)(_loop.body); - jump(post); + jump(debugDataOf(_loop.body), post); (*this)(_loop.post); - jump(loopCondition, true); + jump(debugDataOf(_loop.post), loopCondition, true); } m_currentBlock = &afterLoop; } -void ControlFlowGraphBuilder::operator()(Break const&) +void ControlFlowGraphBuilder::operator()(Break const& _break) { yulAssert(m_forLoopInfo.has_value(), ""); - jump(m_forLoopInfo->afterLoop); - m_currentBlock = &m_graph.makeBlock(); + jump(debugDataOf(_break), m_forLoopInfo->afterLoop); + m_currentBlock = &m_graph.makeBlock(debugDataOf(*m_currentBlock)); } -void ControlFlowGraphBuilder::operator()(Continue const&) +void ControlFlowGraphBuilder::operator()(Continue const& _continue) { yulAssert(m_forLoopInfo.has_value(), ""); - jump(m_forLoopInfo->post); - m_currentBlock = &m_graph.makeBlock(); + jump(debugDataOf(_continue), m_forLoopInfo->post); + m_currentBlock = &m_graph.makeBlock(debugDataOf(*m_currentBlock)); } -void ControlFlowGraphBuilder::operator()(Leave const&) +// '_leave' and '__leave' are reserved in VisualStudio +void ControlFlowGraphBuilder::operator()(Leave const& leave_) { - yulAssert(m_currentFunctionExit.has_value(), ""); - m_currentBlock->exit = *m_currentFunctionExit; - m_currentBlock = &m_graph.makeBlock(); + yulAssert(m_currentFunction.has_value(), ""); + m_currentBlock->exit = CFG::BasicBlock::FunctionReturn{debugDataOf(leave_), *m_currentFunction}; + m_currentBlock = &m_graph.makeBlock(debugDataOf(*m_currentBlock)); } void ControlFlowGraphBuilder::operator()(FunctionDefinition const& _function) @@ -386,7 +394,7 @@ void ControlFlowGraphBuilder::operator()(FunctionDefinition const& _function) auto&& [it, inserted] = m_graph.functionInfo.emplace(std::make_pair(&function, CFG::FunctionInfo{ _function.debugData, function, - &m_graph.makeBlock(), + &m_graph.makeBlock(debugDataOf(_function.body)), _function.parameters | ranges::views::transform([&](auto const& _param) { return VariableSlot{ std::get(virtualFunctionScope->identifiers.at(_param.name)), @@ -404,10 +412,10 @@ void ControlFlowGraphBuilder::operator()(FunctionDefinition const& _function) CFG::FunctionInfo& functionInfo = it->second; ControlFlowGraphBuilder builder{m_graph, m_info, m_dialect}; - builder.m_currentFunctionExit = CFG::BasicBlock::FunctionReturn{&functionInfo}; + builder.m_currentFunction = &functionInfo; builder.m_currentBlock = functionInfo.entry; builder(_function.body); - builder.m_currentBlock->exit = CFG::BasicBlock::FunctionReturn{&functionInfo}; + builder.m_currentBlock->exit = CFG::BasicBlock::FunctionReturn{debugDataOf(_function), &functionInfo}; } @@ -497,18 +505,16 @@ Scope::Variable const& ControlFlowGraphBuilder::lookupVariable(YulString _name) yulAssert(false, "External identifier access unimplemented."); } -std::pair ControlFlowGraphBuilder::makeConditionalJump(StackSlot _condition) -{ - CFG::BasicBlock& nonZero = m_graph.makeBlock(); - CFG::BasicBlock& zero = m_graph.makeBlock(); - makeConditionalJump(move(_condition), nonZero, zero); - return {&nonZero, &zero}; -} - -void ControlFlowGraphBuilder::makeConditionalJump(StackSlot _condition, CFG::BasicBlock& _nonZero, CFG::BasicBlock& _zero) +void ControlFlowGraphBuilder::makeConditionalJump( + shared_ptr _debugData, + StackSlot _condition, + CFG::BasicBlock& _nonZero, + CFG::BasicBlock& _zero +) { yulAssert(m_currentBlock, ""); m_currentBlock->exit = CFG::BasicBlock::ConditionalJump{ + move(_debugData), move(_condition), &_nonZero, &_zero @@ -518,10 +524,14 @@ void ControlFlowGraphBuilder::makeConditionalJump(StackSlot _condition, CFG::Bas m_currentBlock = nullptr; } -void ControlFlowGraphBuilder::jump(CFG::BasicBlock& _target, bool backwards) +void ControlFlowGraphBuilder::jump( + shared_ptr _debugData, + CFG::BasicBlock& _target, + bool backwards +) { yulAssert(m_currentBlock, ""); - m_currentBlock->exit = CFG::BasicBlock::Jump{&_target, backwards}; + m_currentBlock->exit = CFG::BasicBlock::Jump{move(_debugData), &_target, backwards}; _target.entries.emplace_back(m_currentBlock); m_currentBlock = &_target; } diff --git a/libyul/backends/evm/ControlFlowGraphBuilder.h b/libyul/backends/evm/ControlFlowGraphBuilder.h index 2a70a9472..f99a879f6 100644 --- a/libyul/backends/evm/ControlFlowGraphBuilder.h +++ b/libyul/backends/evm/ControlFlowGraphBuilder.h @@ -62,13 +62,18 @@ private: Scope::Function const& lookupFunction(YulString _name) const; Scope::Variable const& lookupVariable(YulString _name) const; - /// @returns a pair of newly created blocks, the first element being the non-zero branch, the second element the - /// zero branch. /// Resets m_currentBlock to enforce a subsequent explicit reassignment. - std::pair makeConditionalJump(StackSlot _condition); - /// Resets m_currentBlock to enforce a subsequent explicit reassignment. - void makeConditionalJump(StackSlot _condition, CFG::BasicBlock& _nonZero, CFG::BasicBlock& _zero); - void jump(CFG::BasicBlock& _target, bool _backwards = false); + void makeConditionalJump( + std::shared_ptr _debugData, + StackSlot _condition, + CFG::BasicBlock& _nonZero, + CFG::BasicBlock& _zero + ); + void jump( + std::shared_ptr _debugData, + CFG::BasicBlock& _target, + bool _backwards = false + ); CFG& m_graph; AsmAnalysisInfo const& m_info; Dialect const& m_dialect; @@ -80,7 +85,7 @@ private: std::reference_wrapper post; }; std::optional m_forLoopInfo; - std::optional m_currentFunctionExit; + std::optional m_currentFunction; }; } diff --git a/libyul/backends/evm/OptimizedEVMCodeTransform.cpp b/libyul/backends/evm/OptimizedEVMCodeTransform.cpp index 91f19ad62..3aedfec3a 100644 --- a/libyul/backends/evm/OptimizedEVMCodeTransform.cpp +++ b/libyul/backends/evm/OptimizedEVMCodeTransform.cpp @@ -57,7 +57,7 @@ vector OptimizedEVMCodeTransform::run( stackLayout ); // Create initial entry layout. - optimizedCodeTransform.createStackLayout(stackLayout.blockInfos.at(dfg->entry).entryLayout); + optimizedCodeTransform.createStackLayout(debugDataOf(*dfg->entry), stackLayout.blockInfos.at(dfg->entry).entryLayout); optimizedCodeTransform(*dfg->entry); for (Scope::Function const* function: dfg->functions) optimizedCodeTransform(dfg->functionInfo.at(function)); @@ -220,7 +220,7 @@ void OptimizedEVMCodeTransform::validateSlot(StackSlot const& _slot, Expression }, _expression); } -void OptimizedEVMCodeTransform::createStackLayout(Stack _targetStack) +void OptimizedEVMCodeTransform::createStackLayout(std::shared_ptr _debugData, Stack _targetStack) { static constexpr auto slotVariableName = [](StackSlot const& _slot) { return std::visit(util::GenericVisitor{ @@ -231,6 +231,8 @@ void OptimizedEVMCodeTransform::createStackLayout(Stack _targetStack) yulAssert(m_assembly.stackHeight() == static_cast(m_stack.size()), ""); // ::createStackLayout asserts that it has successfully achieved the target layout. + langutil::SourceLocation sourceLocation = _debugData ? _debugData->location : langutil::SourceLocation{}; + m_assembly.setSourceLocation(sourceLocation); ::createStackLayout( m_stack, _targetStack | ranges::to, @@ -299,6 +301,7 @@ void OptimizedEVMCodeTransform::createStackLayout(Stack _targetStack) { m_assembly.setSourceLocation(locationOf(_literal)); m_assembly.appendConstant(_literal.value); + m_assembly.setSourceLocation(sourceLocation); }, [&](FunctionReturnLabelSlot const&) { @@ -310,6 +313,7 @@ void OptimizedEVMCodeTransform::createStackLayout(Stack _targetStack) m_returnLabels[&_returnLabel.call.get()] = m_assembly.newLabelId(); m_assembly.setSourceLocation(locationOf(_returnLabel.call.get())); m_assembly.appendLabelReference(m_returnLabels.at(&_returnLabel.call.get())); + m_assembly.setSourceLocation(sourceLocation); }, [&](VariableSlot const& _variable) { @@ -317,6 +321,7 @@ void OptimizedEVMCodeTransform::createStackLayout(Stack _targetStack) { m_assembly.setSourceLocation(locationOf(_variable)); m_assembly.appendConstant(0); + m_assembly.setSourceLocation(sourceLocation); return; } yulAssert(false, "Variable not found on stack."); @@ -346,6 +351,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block) // Assert that this is the first visit of the block and mark as generated. yulAssert(m_generated.insert(&_block).second, ""); + m_assembly.setSourceLocation(locationOf(_block)); auto const& blockInfo = m_stackLayout.blockInfos.at(&_block); // Assert that the stack is valid for entering the block. @@ -360,7 +366,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block) for (auto const& operation: _block.operations) { // Create required layout for entering the operation. - createStackLayout(m_stackLayout.operationEntryLayout.at(&operation)); + createStackLayout(debugDataOf(operation.operation), m_stackLayout.operationEntryLayout.at(&operation)); // Assert that we have the inputs of the operation on stack top. yulAssert(static_cast(m_stack.size()) == m_assembly.stackHeight(), ""); @@ -385,6 +391,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block) } // Exit the block. + m_assembly.setSourceLocation(locationOf(_block)); std::visit(util::GenericVisitor{ [&](CFG::BasicBlock::MainExit const&) { @@ -393,7 +400,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block) [&](CFG::BasicBlock::Jump const& _jump) { // Create the stack expected at the jump target. - createStackLayout(m_stackLayout.blockInfos.at(_jump.target).entryLayout); + createStackLayout(debugDataOf(_jump), m_stackLayout.blockInfos.at(_jump.target).entryLayout); // If this is the only jump to the block, we do not need a label and can directly continue with the target block. if (!m_blockLabels.count(_jump.target) && _jump.target->entries.size() == 1) @@ -417,7 +424,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block) [&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) { // Create the shared entry layout of the jump targets, which is stored as exit layout of the current block. - createStackLayout(blockInfo.exitLayout); + createStackLayout(debugDataOf(_conditionalJump), blockInfo.exitLayout); // Create labels for the targets, if not already present. if (!m_blockLabels.count(_conditionalJump.nonZero)) @@ -468,9 +475,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block) exitStack.emplace_back(FunctionReturnLabelSlot{_functionReturn.info->function}); // Create the function return layout and jump. - m_assembly.setSourceLocation(locationOf(*m_currentFunctionInfo)); - createStackLayout(exitStack); - m_assembly.setSourceLocation(locationOf(*m_currentFunctionInfo)); + createStackLayout(debugDataOf(_functionReturn), exitStack); m_assembly.appendJump(0, AbstractAssembly::JumpType::OutOfFunction); }, [&](CFG::BasicBlock::Terminated const&) @@ -505,7 +510,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::FunctionInfo const& _functionInf m_assembly.appendLabel(getFunctionLabel(_functionInfo.function)); // Create the entry layout of the function body block and visit. - createStackLayout(m_stackLayout.blockInfos.at(_functionInfo.entry).entryLayout); + createStackLayout(debugDataOf(_functionInfo), m_stackLayout.blockInfos.at(_functionInfo.entry).entryLayout); (*this)(*_functionInfo.entry); m_stack.clear(); diff --git a/libyul/backends/evm/OptimizedEVMCodeTransform.h b/libyul/backends/evm/OptimizedEVMCodeTransform.h index bbbfcc363..48819251a 100644 --- a/libyul/backends/evm/OptimizedEVMCodeTransform.h +++ b/libyul/backends/evm/OptimizedEVMCodeTransform.h @@ -77,7 +77,8 @@ private: static void validateSlot(StackSlot const& _slot, Expression const& _expression); /// Shuffles m_stack to the desired @a _targetStack while emitting the shuffling code to m_assembly. - void createStackLayout(Stack _targetStack); + /// Sets the source locations to the one in @a _debugData. + void createStackLayout(std::shared_ptr _debugData, Stack _targetStack); /// Generate code for the given block @a _block. /// Expects the current stack layout m_stack to be a stack layout that is compatible with the From 83b3bd0227f3d98ce3e98d94440ca05cb5dc11ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 10 Sep 2021 15:50:37 +0200 Subject: [PATCH 083/232] Add a version of isValidMetadata() that accepts already parsed metadata --- test/Metadata.cpp | 34 +++++++++++++++++++--------------- test/Metadata.h | 9 ++++++--- test/libsolidity/Metadata.cpp | 16 ++++++++-------- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/test/Metadata.cpp b/test/Metadata.cpp index 61654ae00..687b9d73e 100644 --- a/test/Metadata.cpp +++ b/test/Metadata.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #include using namespace std; @@ -170,30 +169,35 @@ std::optional> parseCBORMetadata(bytes const& _metadata) } } -bool isValidMetadata(string const& _metadata) +bool isValidMetadata(string const& _serialisedMetadata) { Json::Value metadata; - if (!util::jsonParseStrict(_metadata, metadata)) + if (!util::jsonParseStrict(_serialisedMetadata, metadata)) return false; + return isValidMetadata(metadata); +} + +bool isValidMetadata(Json::Value const& _metadata) +{ if ( - !metadata.isObject() || - !metadata.isMember("version") || - !metadata.isMember("language") || - !metadata.isMember("compiler") || - !metadata.isMember("settings") || - !metadata.isMember("sources") || - !metadata.isMember("output") || - !metadata["settings"].isMember("evmVersion") || - !metadata["settings"].isMember("metadata") || - !metadata["settings"]["metadata"].isMember("bytecodeHash") + !_metadata.isObject() || + !_metadata.isMember("version") || + !_metadata.isMember("language") || + !_metadata.isMember("compiler") || + !_metadata.isMember("settings") || + !_metadata.isMember("sources") || + !_metadata.isMember("output") || + !_metadata["settings"].isMember("evmVersion") || + !_metadata["settings"].isMember("metadata") || + !_metadata["settings"]["metadata"].isMember("bytecodeHash") ) return false; - if (!metadata["version"].isNumeric() || metadata["version"] != 1) + if (!_metadata["version"].isNumeric() || _metadata["version"] != 1) return false; - if (!metadata["language"].isString() || metadata["language"].asString() != "Solidity") + if (!_metadata["language"].isString() || _metadata["language"].asString() != "Solidity") return false; /// @TODO add more strict checks diff --git a/test/Metadata.h b/test/Metadata.h index c91ceb559..86b43e245 100644 --- a/test/Metadata.h +++ b/test/Metadata.h @@ -21,6 +21,7 @@ */ #include +#include #include #include @@ -48,8 +49,10 @@ std::string bytecodeSansMetadata(std::string const& _bytecode); /// - everything else is invalid std::optional> parseCBORMetadata(bytes const& _metadata); -/// Expects a serialised metadata JSON and returns true if the -/// content is valid metadata. -bool isValidMetadata(std::string const& _metadata); +/// Expects a serialised metadata JSON and returns true if the content is valid metadata. +bool isValidMetadata(std::string const& _serialisedMetadata); + +/// Expects a deserialised metadata JSON and returns true if the content is valid metadata. +bool isValidMetadata(Json::Value const& _metadata); } // end namespaces diff --git a/test/libsolidity/Metadata.cpp b/test/libsolidity/Metadata.cpp index ae2dd85db..706bf15d5 100644 --- a/test/libsolidity/Metadata.cpp +++ b/test/libsolidity/Metadata.cpp @@ -58,9 +58,9 @@ optional compileAndCheckLicenseMetadata(string const& _contractName, cha BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed"); std::string const& serialisedMetadata = compilerStack.metadata(_contractName); - BOOST_CHECK(solidity::test::isValidMetadata(serialisedMetadata)); Json::Value metadata; BOOST_REQUIRE(util::jsonParseStrict(serialisedMetadata, metadata)); + BOOST_CHECK(solidity::test::isValidMetadata(metadata)); BOOST_CHECK_EQUAL(metadata["sources"].size(), 1); BOOST_REQUIRE(metadata["sources"].isMember("A.sol")); @@ -250,9 +250,9 @@ BOOST_AUTO_TEST_CASE(metadata_relevant_sources) BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed"); std::string const& serialisedMetadata = compilerStack.metadata("A"); - BOOST_CHECK(solidity::test::isValidMetadata(serialisedMetadata)); Json::Value metadata; BOOST_REQUIRE(util::jsonParseStrict(serialisedMetadata, metadata)); + BOOST_CHECK(solidity::test::isValidMetadata(metadata)); BOOST_CHECK_EQUAL(metadata["sources"].size(), 1); BOOST_CHECK(metadata["sources"].isMember("A")); @@ -291,9 +291,9 @@ BOOST_AUTO_TEST_CASE(metadata_relevant_sources_imports) BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed"); std::string const& serialisedMetadata = compilerStack.metadata("C"); - BOOST_CHECK(solidity::test::isValidMetadata(serialisedMetadata)); Json::Value metadata; BOOST_REQUIRE(util::jsonParseStrict(serialisedMetadata, metadata)); + BOOST_CHECK(solidity::test::isValidMetadata(metadata)); BOOST_CHECK_EQUAL(metadata["sources"].size(), 3); BOOST_CHECK(metadata["sources"].isMember("A")); @@ -320,8 +320,8 @@ BOOST_AUTO_TEST_CASE(metadata_useLiteralContent) BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed"); string metadata_str = compilerStack.metadata("test"); Json::Value metadata; - util::jsonParseStrict(metadata_str, metadata); - BOOST_CHECK(solidity::test::isValidMetadata(metadata_str)); + BOOST_REQUIRE(util::jsonParseStrict(metadata_str, metadata)); + BOOST_CHECK(solidity::test::isValidMetadata(metadata)); BOOST_CHECK(metadata.isMember("settings")); BOOST_CHECK(metadata["settings"].isMember("metadata")); BOOST_CHECK(metadata["settings"]["metadata"].isMember("bytecodeHash")); @@ -354,8 +354,8 @@ BOOST_AUTO_TEST_CASE(metadata_viair) BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed"); string metadata_str = compilerStack.metadata("test"); Json::Value metadata; - util::jsonParseStrict(metadata_str, metadata); - BOOST_CHECK(solidity::test::isValidMetadata(metadata_str)); + BOOST_REQUIRE(util::jsonParseStrict(metadata_str, metadata)); + BOOST_CHECK(solidity::test::isValidMetadata(metadata)); BOOST_CHECK(metadata.isMember("settings")); if (_viair) { @@ -381,9 +381,9 @@ BOOST_AUTO_TEST_CASE(metadata_revert_strings) BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed"); std::string const& serialisedMetadata = compilerStack.metadata("A"); - BOOST_CHECK(solidity::test::isValidMetadata(serialisedMetadata)); Json::Value metadata; BOOST_REQUIRE(util::jsonParseStrict(serialisedMetadata, metadata)); + BOOST_CHECK(solidity::test::isValidMetadata(metadata)); BOOST_CHECK_EQUAL(metadata["settings"]["debug"]["revertStrings"], "strip"); } From 405a9e9971dadba12c4c8eb33e06895c10a9528c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 10 Sep 2021 15:54:32 +0200 Subject: [PATCH 084/232] Generate separate metadata for the old and the new codegen --- libsolidity/interface/CompilerStack.cpp | 31 ++++++++++--------------- libsolidity/interface/CompilerStack.h | 25 +++++++++++++------- test/libsolidity/Metadata.cpp | 28 ++++++++++++++++++---- 3 files changed, 52 insertions(+), 32 deletions(-) diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 68411b071..16df9b7b1 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -1000,20 +1000,12 @@ Json::Value CompilerStack::methodIdentifiers(string const& _contractName) const return methodIdentifiers; } -string const& CompilerStack::metadata(string const& _contractName) const +bytes CompilerStack::cborMetadata(string const& _contractName, bool _forIR) const { if (m_stackState < AnalysisPerformed) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); - return metadata(contract(_contractName)); -} - -bytes CompilerStack::cborMetadata(string const& _contractName) const -{ - if (m_stackState < AnalysisPerformed) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful.")); - - return createCBORMetadata(contract(_contractName)); + return createCBORMetadata(contract(_contractName), _forIR); } string const& CompilerStack::metadata(Contract const& _contract) const @@ -1023,7 +1015,7 @@ string const& CompilerStack::metadata(Contract const& _contract) const solAssert(_contract.contract, ""); - return _contract.metadata.init([&]{ return createMetadata(_contract); }); + return _contract.metadata.init([&]{ return createMetadata(_contract, m_viaIR); }); } CharStream const& CompilerStack::charStream(string const& _sourceName) const @@ -1283,7 +1275,8 @@ void CompilerStack::compileContract( shared_ptr compiler = make_shared(m_evmVersion, m_revertStrings, m_optimiserSettings); compiledContract.compiler = compiler; - bytes cborEncodedMetadata = createCBORMetadata(compiledContract); + solAssert(!m_viaIR, ""); + bytes cborEncodedMetadata = createCBORMetadata(compiledContract, /* _forIR */ false); try { @@ -1332,7 +1325,7 @@ void CompilerStack::generateIR(ContractDefinition const& _contract) IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings, sourceIndices(), this); tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run( _contract, - createCBORMetadata(compiledContract), + createCBORMetadata(compiledContract, /* _forIR */ true), otherYulSources ); } @@ -1434,7 +1427,7 @@ CompilerStack::Source const& CompilerStack::source(string const& _sourceName) co return it->second; } -string CompilerStack::createMetadata(Contract const& _contract) const +string CompilerStack::createMetadata(Contract const& _contract, bool _forIR) const { Json::Value meta; meta["version"] = 1; @@ -1510,8 +1503,8 @@ string CompilerStack::createMetadata(Contract const& _contract) const static vector hashes{"ipfs", "bzzr1", "none"}; meta["settings"]["metadata"]["bytecodeHash"] = hashes.at(unsigned(m_metadataHash)); - if (m_viaIR) - meta["settings"]["viaIR"] = m_viaIR; + if (_forIR) + meta["settings"]["viaIR"] = _forIR; meta["settings"]["evmVersion"] = m_evmVersion.name(); meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] = *_contract.contract->annotation().canonicalName; @@ -1617,7 +1610,7 @@ private: bytes m_data; }; -bytes CompilerStack::createCBORMetadata(Contract const& _contract) const +bytes CompilerStack::createCBORMetadata(Contract const& _contract, bool _forIR) const { if (m_metadataFormat == MetadataFormat::NoMetadata) return bytes{}; @@ -1626,7 +1619,7 @@ bytes CompilerStack::createCBORMetadata(Contract const& _contract) const _contract.contract->sourceUnit().annotation().experimentalFeatures ); - string meta = metadata(_contract); + string meta = (_forIR == m_viaIR ? metadata(_contract) : createMetadata(_contract, _forIR)); MetadataCBOREncoder encoder; @@ -1637,7 +1630,7 @@ bytes CompilerStack::createCBORMetadata(Contract const& _contract) const else solAssert(m_metadataHash == MetadataHash::None, "Invalid metadata hash"); - if (experimentalMode || m_viaIR) + if (experimentalMode || _forIR) encoder.pushBool("experimental", true); if (m_metadataFormat == MetadataFormat::WithReleaseVersionTag) encoder.pushBytes("solc", VersionCompactBytes); diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 9c713da24..bbef4dc64 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -326,11 +326,16 @@ public: /// @returns a JSON representing a map of method identifiers (hashes) to function names. Json::Value methodIdentifiers(std::string const& _contractName) const; - /// @returns the Contract Metadata - std::string const& metadata(std::string const& _contractName) const; + /// @returns the Contract Metadata matching the pipeline selected using the viaIR setting. + std::string const& metadata(std::string const& _contractName) const { return metadata(contract(_contractName)); } - /// @returns the cbor-encoded metadata. - bytes cborMetadata(std::string const& _contractName) const; + /// @returns the CBOR-encoded metadata matching the pipeline selected using the viaIR setting. + bytes cborMetadata(std::string const& _contractName) const { return cborMetadata(_contractName, m_viaIR); } + + /// @returns the CBOR-encoded metadata. + /// @param _forIR If true, the metadata for the IR codegen is used. Otherwise it's the metadata + /// for the EVM codegen + bytes cborMetadata(std::string const& _contractName, bool _forIR) const; /// @returns a JSON representing the estimated gas usage for contract creation, internal and external functions Json::Value gasEstimates(std::string const& _contractName) const; @@ -339,6 +344,7 @@ public: /// This is mostly a workaround to avoid bytecode and gas differences between compiler builds /// caused by differences in metadata. Should only be used for testing. void setMetadataFormat(MetadataFormat _metadataFormat) { m_metadataFormat = _metadataFormat; } + private: /// The state per source unit. Filled gradually during parsing. struct Source @@ -437,11 +443,14 @@ private: /// Can only be called after state is SourcesSet. Source const& source(std::string const& _sourceName) const; + /// @param _forIR If true, include a flag that indicates that the bytecode comes from the + /// experimental IR codegen. /// @returns the metadata JSON as a compact string for the given contract. - std::string createMetadata(Contract const& _contract) const; + std::string createMetadata(Contract const& _contract, bool _forIR) const; /// @returns the metadata CBOR for the given serialised metadata JSON. - bytes createCBORMetadata(Contract const& _contract) const; + /// @param _forIR If true, use the metadata for the IR codegen. Otherwise the one for EVM codegen. + bytes createCBORMetadata(Contract const& _contract, bool _forIR) const; /// @returns the contract ABI as a JSON object. /// This will generate the JSON object and store it in the Contract object if it is not present yet. @@ -459,9 +468,9 @@ private: /// This will generate the JSON object and store it in the Contract object if it is not present yet. Json::Value const& natspecDev(Contract const&) const; - /// @returns the Contract Metadata + /// @returns the Contract Metadata matching the pipeline selected using the viaIR setting. /// This will generate the metadata and store it in the Contract object if it is not present yet. - std::string const& metadata(Contract const&) const; + std::string const& metadata(Contract const& _contract) const; /// @returns the offset of the entry point of the given function into the list of assembly items /// or zero if it is not found or does not exist. diff --git a/test/libsolidity/Metadata.cpp b/test/libsolidity/Metadata.cpp index 706bf15d5..8d0b65e4c 100644 --- a/test/libsolidity/Metadata.cpp +++ b/test/libsolidity/Metadata.cpp @@ -344,24 +344,42 @@ BOOST_AUTO_TEST_CASE(metadata_viair) } )"; - auto check = [](char const* _src, bool _viair) + auto check = [](char const* _src, bool _viaIR) { CompilerStack compilerStack; compilerStack.setSources({{"", std::string(_src)}}); compilerStack.setEVMVersion(solidity::test::CommonOptions::get().evmVersion()); compilerStack.setOptimiserSettings(solidity::test::CommonOptions::get().optimize); - compilerStack.setViaIR(_viair); + compilerStack.setViaIR(_viaIR); BOOST_REQUIRE_MESSAGE(compilerStack.compile(), "Compiling contract failed"); - string metadata_str = compilerStack.metadata("test"); + Json::Value metadata; - BOOST_REQUIRE(util::jsonParseStrict(metadata_str, metadata)); + BOOST_REQUIRE(util::jsonParseStrict(compilerStack.metadata("test"), metadata)); BOOST_CHECK(solidity::test::isValidMetadata(metadata)); BOOST_CHECK(metadata.isMember("settings")); - if (_viair) + if (_viaIR) { BOOST_CHECK(metadata["settings"].isMember("viaIR")); BOOST_CHECK(metadata["settings"]["viaIR"].asBool()); } + else + BOOST_CHECK(!metadata["settings"].isMember("viaIR")); + + BOOST_CHECK(compilerStack.cborMetadata("test") == compilerStack.cborMetadata("test", _viaIR)); + BOOST_CHECK(compilerStack.cborMetadata("test") != compilerStack.cborMetadata("test", !_viaIR)); + + map const parsedCBORMetadata = requireParsedCBORMetadata( + compilerStack.runtimeObject("test").bytecode, + CompilerStack::MetadataFormat::WithReleaseVersionTag + ); + + if (_viaIR) + { + BOOST_CHECK(parsedCBORMetadata.count("experimental") == 1); + BOOST_CHECK(parsedCBORMetadata.at("experimental") == "true"); + } + else + BOOST_CHECK(parsedCBORMetadata.count("experimental") == 0); }; check(sourceCode, true); From 94086e734b420f63271492809d43d2bcfceee5f2 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Mon, 13 Sep 2021 11:22:26 +0200 Subject: [PATCH 085/232] Do not use std::iterator that is deprecated in c++17. --- libevmasm/BlockDeduplicator.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libevmasm/BlockDeduplicator.h b/libevmasm/BlockDeduplicator.h index ef131ae52..9069b70ce 100644 --- a/libevmasm/BlockDeduplicator.h +++ b/libevmasm/BlockDeduplicator.h @@ -64,9 +64,14 @@ private: /// Iterator that skips tags and skips to the end if (all branches of) the control /// flow does not continue to the next instruction. /// If the arguments are supplied to the constructor, replaces items on the fly. - struct BlockIterator: std::iterator + struct BlockIterator { public: + using iterator_category = std::forward_iterator_tag; + using value_type = AssemblyItem const; + using difference_type = std::ptrdiff_t; + using pointer = AssemblyItem const*; + using reference = AssemblyItem const&; BlockIterator( AssemblyItems::const_iterator _it, AssemblyItems::const_iterator _end, From 3e86598bfda9bdd611633ba9006ffa41ee051366 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Mon, 13 Sep 2021 09:41:45 +0200 Subject: [PATCH 086/232] Docker: Update ossfuzz docker image to pull in clang-14. --- .../Dockerfile.ubuntu1604.clang.ossfuzz | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz index 5e32ef9bf..9f2d28271 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-2019 solidity contributors. #------------------------------------------------------------------------------ FROM gcr.io/oss-fuzz-base/base-clang as base -LABEL version="11" +LABEL version="12" ARG DEBIAN_FRONTEND=noninteractive @@ -35,10 +35,11 @@ RUN apt-get update; \ pkg-config openjdk-8-jdk liblzma-dev unzip mlton m4; \ apt-get install -qy python-pip python-sphinx; -# Install cmake 3.14 (minimum requirement is cmake 3.10) -RUN wget https://github.com/Kitware/CMake/releases/download/v3.14.5/cmake-3.14.5-Linux-x86_64.sh; \ - chmod +x cmake-3.14.5-Linux-x86_64.sh; \ - ./cmake-3.14.5-Linux-x86_64.sh --skip-license --prefix="/usr" +# Install cmake 3.21.2 (minimum requirement is cmake 3.10) +RUN wget https://github.com/Kitware/CMake/releases/download/v3.21.2/cmake-3.21.2-Linux-x86_64.sh; \ + test "$(sha256sum cmake-3.21.2-Linux-x86_64.sh)" = "3310362c6fe4d4b2dc00823835f3d4a7171bbd73deb7d059738494761f1c908c cmake-3.21.2-Linux-x86_64.sh"; \ + chmod +x cmake-3.21.2-Linux-x86_64.sh; \ + ./cmake-3.21.2-Linux-x86_64.sh --skip-license --prefix="/usr" FROM base AS libraries @@ -92,7 +93,7 @@ RUN set -ex; \ # EVMONE RUN set -ex; \ cd /usr/src; \ - git clone --branch="v0.8.0" --recurse-submodules https://github.com/ethereum/evmone.git; \ + git clone --branch="v0.8.2" --recurse-submodules https://github.com/ethereum/evmone.git; \ cd evmone; \ mkdir build; \ cd build; \ From 08a7eaca477311459416b3a9d66e89d0ad6512be Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Mon, 13 Sep 2021 09:48:29 +0200 Subject: [PATCH 087/232] Upgrade python pip and sphinx --- .../docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz index 9f2d28271..563def75d 100644 --- a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz +++ b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz @@ -33,7 +33,7 @@ RUN apt-get update; \ ninja-build git wget \ libbz2-dev zlib1g-dev git curl uuid-dev \ pkg-config openjdk-8-jdk liblzma-dev unzip mlton m4; \ - apt-get install -qy python-pip python-sphinx; + apt-get install -qy python3-pip sphinx-doc sphinx-common; # Install cmake 3.21.2 (minimum requirement is cmake 3.10) RUN wget https://github.com/Kitware/CMake/releases/download/v3.21.2/cmake-3.21.2-Linux-x86_64.sh; \ From be29ef70a7edae102afbf03905bba700d9b03832 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Tue, 14 Sep 2021 16:13:36 +0200 Subject: [PATCH 088/232] Allow accessing user defined value type members via contract name. --- libsolidity/ast/AST.h | 1 + .../wrap_unwrap_via_contract_name.sol | 24 +++++++++++++++++++ .../wrap_unwrap_via_contract_name.sol | 9 +++++++ ...rap_unwrap_via_contract_name_different.sol | 8 +++++++ 4 files changed, 42 insertions(+) create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/wrap_unwrap_via_contract_name.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_via_contract_name.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_via_contract_name_different.sol diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index e1e5fc596..dce384cdf 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -751,6 +751,7 @@ public: Type const* type() const override; TypeName const* underlyingType() const { return m_underlyingType.get(); } + bool isVisibleViaContractTypeAccess() const override { return true; } private: /// The name of the underlying type diff --git a/test/libsolidity/semanticTests/userDefinedValueType/wrap_unwrap_via_contract_name.sol b/test/libsolidity/semanticTests/userDefinedValueType/wrap_unwrap_via_contract_name.sol new file mode 100644 index 000000000..f6103c596 --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/wrap_unwrap_via_contract_name.sol @@ -0,0 +1,24 @@ +contract C { + type T is uint; +} +contract D { + function f(C.T x) public pure returns(uint) { + return C.T.unwrap(x); + } + function g(uint x) public pure returns(C.T) { + return C.T.wrap(x); + } + function h(uint x) public pure returns(uint) { + return f(g(x)); + } + function i(C.T x) public pure returns(C.T) { + return g(f(x)); + } +} +// ==== +// compileViaYul: also +// ---- +// f(uint256): 0x42 -> 0x42 +// g(uint256): 0x42 -> 0x42 +// h(uint256): 0x42 -> 0x42 +// i(uint256): 0x42 -> 0x42 diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_via_contract_name.sol b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_via_contract_name.sol new file mode 100644 index 000000000..1d9c6eb13 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_via_contract_name.sol @@ -0,0 +1,9 @@ +contract C { type T is uint; } +library L { type T is uint; } +interface I { type T is uint; } +contract D +{ + C.T x = C.T.wrap(uint(1)); + L.T y = L.T.wrap(uint(1)); + I.T z = I.T.wrap(uint(1)); +} diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_via_contract_name_different.sol b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_via_contract_name_different.sol new file mode 100644 index 000000000..f983a9d20 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_via_contract_name_different.sol @@ -0,0 +1,8 @@ +contract C { type T is uint; } +library L { type T is uint; } +contract D +{ + C.T x = L.T.wrap(uint(1)); +} +// ---- +// TypeError 7407: (86-103): Type user defined type T is not implicitly convertible to expected type user defined type T. From d1465dd0f704bb507a641f01ec07147d04c1242d Mon Sep 17 00:00:00 2001 From: istareatscreens Date: Tue, 14 Sep 2021 14:55:24 -0400 Subject: [PATCH 089/232] Reword External Function Calls paragraph in docs Reword External Function Calls opening paragraph to improve clarity --- docs/control-structures.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/control-structures.rst b/docs/control-structures.rst index 37a4fcd12..1de35cf6b 100644 --- a/docs/control-structures.rst +++ b/docs/control-structures.rst @@ -65,9 +65,10 @@ uses up at least one stack slot and there are only 1024 slots available. External Function Calls ----------------------- -The expressions ``this.g(8);`` and ``c.g(2);`` (where ``c`` is a contract -instance) are also valid function calls, but this time, the function -will be called "externally", via a message call and not directly via jumps. +Functions can also be called using the ``this.g(8);`` and ``c.g(2);`` notation, where +``c`` is a contract instance and ``g`` is a function belonging to ``c``. +Calling the function ``g`` via either way results in it being called "externally", using a +message call and not directly via jumps. Please note that function calls on ``this`` cannot be used in the constructor, as the actual contract has not been created yet. From de0182299939c559904cc29da372087498809b8e Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Tue, 14 Sep 2021 17:31:00 +0200 Subject: [PATCH 090/232] UserDefinedValueType: from simple name to canonical name. --- libsolidity/analysis/NameAndTypeResolver.cpp | 41 ++++++++++---------- libsolidity/analysis/NameAndTypeResolver.h | 3 -- libsolidity/ast/AST.cpp | 5 +++ libsolidity/ast/AST.h | 2 + libsolidity/ast/Types.cpp | 2 +- 5 files changed, 28 insertions(+), 25 deletions(-) diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 001221bc5..74834a0cb 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -612,13 +612,31 @@ bool DeclarationRegistrationHelper::visitNode(ASTNode& _node) if (auto* declaration = dynamic_cast(&_node)) registerDeclaration(*declaration); + + if (auto* annotation = dynamic_cast(&_node.annotation())) + { + string canonicalName = dynamic_cast(_node).name(); + solAssert(!canonicalName.empty(), ""); + + for ( + ASTNode const* scope = m_currentScope; + scope != nullptr; + scope = m_scopes[scope]->enclosingNode() + ) + if (auto decl = dynamic_cast(scope)) + { + solAssert(!decl->name().empty(), ""); + canonicalName = decl->name() + "." + canonicalName; + } + + annotation->canonicalName = canonicalName; + } + if (dynamic_cast(&_node)) enterNewSubScope(_node); if (auto* variableScope = dynamic_cast(&_node)) m_currentFunction = variableScope; - if (auto* annotation = dynamic_cast(&_node.annotation())) - annotation->canonicalName = currentCanonicalName(); return true; } @@ -668,23 +686,4 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio solAssert(_declaration.annotation().contract == m_currentContract, ""); } -string DeclarationRegistrationHelper::currentCanonicalName() const -{ - string ret; - for ( - ASTNode const* scope = m_currentScope; - scope != nullptr; - scope = m_scopes[scope]->enclosingNode() - ) - { - if (auto decl = dynamic_cast(scope)) - { - if (!ret.empty()) - ret = "." + ret; - ret = decl->name() + ret; - } - } - return ret; -} - } diff --git a/libsolidity/analysis/NameAndTypeResolver.h b/libsolidity/analysis/NameAndTypeResolver.h index 919e84a66..36a22ed2e 100644 --- a/libsolidity/analysis/NameAndTypeResolver.h +++ b/libsolidity/analysis/NameAndTypeResolver.h @@ -176,9 +176,6 @@ private: static bool isOverloadedFunction(Declaration const& _declaration1, Declaration const& _declaration2); - /// @returns the canonical name of the current scope. - std::string currentCanonicalName() const; - std::map>& m_scopes; ASTNode const* m_currentScope = nullptr; VariableScope* m_currentFunction = nullptr; diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 3201d60ff..3e2376a4f 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -341,6 +341,11 @@ Type const* UserDefinedValueTypeDefinition::type() const return TypeProvider::typeType(TypeProvider::userDefinedValueType(*this)); } +TypeDeclarationAnnotation& UserDefinedValueTypeDefinition::annotation() const +{ + return initAnnotation(); +} + Type const* StructDefinition::type() const { solAssert(annotation().recursive.has_value(), "Requested struct type before DeclarationTypeChecker."); diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index dce384cdf..c229252a8 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -750,6 +750,8 @@ public: Type const* type() const override; + TypeDeclarationAnnotation& annotation() const override; + TypeName const* underlyingType() const { return m_underlyingType.get(); } bool isVisibleViaContractTypeAccess() const override { return true; } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index da6f7d196..467d48c5b 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2555,7 +2555,7 @@ bool UserDefinedValueType::operator==(Type const& _other) const string UserDefinedValueType::toString(bool /* _short */) const { - return "user defined type " + definition().name(); + return "user defined type " + *definition().annotation().canonicalName; } vector> UserDefinedValueType::makeStackItems() const From 42c8310a6382f76af9c299574d0b34cdcc6e944d Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Tue, 14 Sep 2021 17:36:18 +0200 Subject: [PATCH 091/232] Updated tests. --- test/libsolidity/ABIJson/user_defined_value_type.sol | 12 ++++++------ test/libsolidity/ASTJSON/userDefinedValueType.json | 8 ++++---- .../wrap_unwrap_via_contract_name_different.sol | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/test/libsolidity/ABIJson/user_defined_value_type.sol b/test/libsolidity/ABIJson/user_defined_value_type.sol index da10f7c44..b5e565dbb 100644 --- a/test/libsolidity/ABIJson/user_defined_value_type.sol +++ b/test/libsolidity/ABIJson/user_defined_value_type.sol @@ -36,7 +36,7 @@ contract C { // "outputs": // [ // { -// "internalType": "user defined type MyAddress", +// "internalType": "user defined type C.MyAddress", // "name": "", // "type": "address" // } @@ -64,7 +64,7 @@ contract C { // "outputs": // [ // { -// "internalType": "user defined type MyBytes32", +// "internalType": "user defined type C.MyBytes32", // "name": "", // "type": "bytes32" // } @@ -92,7 +92,7 @@ contract C { // "outputs": // [ // { -// "internalType": "user defined type MyUInt8", +// "internalType": "user defined type C.MyUInt8", // "name": "", // "type": "uint8" // } @@ -104,7 +104,7 @@ contract C { // "inputs": // [ // { -// "internalType": "user defined type MyAddress", +// "internalType": "user defined type C.MyAddress", // "name": "a", // "type": "address" // } @@ -132,7 +132,7 @@ contract C { // "inputs": // [ // { -// "internalType": "user defined type MyBytes32", +// "internalType": "user defined type C.MyBytes32", // "name": "a", // "type": "bytes32" // } @@ -160,7 +160,7 @@ contract C { // "inputs": // [ // { -// "internalType": "user defined type MyUInt8", +// "internalType": "user defined type C.MyUInt8", // "name": "a", // "type": "uint8" // } diff --git a/test/libsolidity/ASTJSON/userDefinedValueType.json b/test/libsolidity/ASTJSON/userDefinedValueType.json index f929122b1..4f8dc9306 100644 --- a/test/libsolidity/ASTJSON/userDefinedValueType.json +++ b/test/libsolidity/ASTJSON/userDefinedValueType.json @@ -269,7 +269,7 @@ "typeDescriptions": { "typeIdentifier": "t_mapping$_t_userDefinedValueType$_MyAddress_$18_$_t_userDefinedValueType$_MyUInt_$20_$", - "typeString": "mapping(user defined type MyAddress => user defined type MyUInt)" + "typeString": "mapping(user defined type C.MyAddress => user defined type C.MyUInt)" }, "typeName": { @@ -291,7 +291,7 @@ "typeDescriptions": { "typeIdentifier": "t_userDefinedValueType$_MyAddress_$18", - "typeString": "user defined type MyAddress" + "typeString": "user defined type C.MyAddress" } }, "nodeType": "Mapping", @@ -299,7 +299,7 @@ "typeDescriptions": { "typeIdentifier": "t_mapping$_t_userDefinedValueType$_MyAddress_$18_$_t_userDefinedValueType$_MyUInt_$20_$", - "typeString": "mapping(user defined type MyAddress => user defined type MyUInt)" + "typeString": "mapping(user defined type C.MyAddress => user defined type C.MyUInt)" }, "valueType": { @@ -318,7 +318,7 @@ "typeDescriptions": { "typeIdentifier": "t_userDefinedValueType$_MyUInt_$20", - "typeString": "user defined type MyUInt" + "typeString": "user defined type C.MyUInt" } } }, diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_via_contract_name_different.sol b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_via_contract_name_different.sol index f983a9d20..64d19c627 100644 --- a/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_via_contract_name_different.sol +++ b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_via_contract_name_different.sol @@ -5,4 +5,4 @@ contract D C.T x = L.T.wrap(uint(1)); } // ---- -// TypeError 7407: (86-103): Type user defined type T is not implicitly convertible to expected type user defined type T. +// TypeError 7407: (86-103): Type user defined type L.T is not implicitly convertible to expected type user defined type C.T. From 479cd33e6ff01a5cdf8d4b3ea760ddc6bb4a7647 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Wed, 15 Sep 2021 12:57:46 +0200 Subject: [PATCH 092/232] Update scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kamil Śliwak --- .../docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz index 563def75d..965d08669 100644 --- a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz +++ b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz @@ -19,7 +19,7 @@ # You should have received a copy of the GNU General Public License # along with solidity. If not, see # -# (c) 2016-2019 solidity contributors. +# (c) 2016-2021 solidity contributors. #------------------------------------------------------------------------------ FROM gcr.io/oss-fuzz-base/base-clang as base LABEL version="12" From 9a8fc605b270ba5e8e8fcd54fc309ac38747df7e Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Wed, 15 Sep 2021 12:57:55 +0200 Subject: [PATCH 093/232] Update scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kamil Śliwak --- .../docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz index 965d08669..fcf8a0dc4 100644 --- a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz +++ b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz @@ -33,7 +33,7 @@ RUN apt-get update; \ ninja-build git wget \ libbz2-dev zlib1g-dev git curl uuid-dev \ pkg-config openjdk-8-jdk liblzma-dev unzip mlton m4; \ - apt-get install -qy python3-pip sphinx-doc sphinx-common; + apt-get install -qy python3-pip; # Install cmake 3.21.2 (minimum requirement is cmake 3.10) RUN wget https://github.com/Kitware/CMake/releases/download/v3.21.2/cmake-3.21.2-Linux-x86_64.sh; \ From d1c0b428fc53d0b7433d7ef1f66388729e7c9bb0 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Wed, 15 Sep 2021 12:28:20 +0200 Subject: [PATCH 094/232] Improve abi decoding functions for arrays. --- libsolidity/codegen/ABIFunctions.cpp | 8 ++++---- test/cmdlineTests/name_simplifier/output | 11 +++++------ test/cmdlineTests/revert_strings/output | 14 ++++++-------- .../standard_function_debug_info/output.json | 2 +- .../standard_generatedSources/output.json | 9 ++++----- .../output.json | 9 ++++----- test/libsolidity/gasTests/abiv2.sol | 6 +++--- test/libsolidity/gasTests/abiv2_optimised.sol | 6 +++--- .../abiEncoderV1/abi_decode_v2_storage.sol | 6 +++--- ...ode_v2_in_function_inherited_in_v1_contract.sol | 6 +++--- .../semanticTests/abiEncoderV2/calldata_array.sol | 2 +- .../array/arrays_complex_from_and_to_storage.sol | 6 +++--- .../array/copying/arrays_from_and_to_storage.sol | 6 +++--- .../array/fixed_arrays_as_return_type.sol | 6 +++--- .../array/function_array_cross_calls.sol | 6 +++--- .../constructor/arrays_in_constructors.sol | 6 +++--- ...nherited_function_calldata_memory_interface.sol | 6 +++--- .../userDefinedValueType/calldata.sol | 6 +++--- 18 files changed, 58 insertions(+), 63 deletions(-) diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index d964c1f14..97cf3425d 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -1170,6 +1170,7 @@ string ABIFunctions::abiDecodingFunctionArrayAvailableLength(ArrayType const& _t solAssert(_type.dataStoredIn(DataLocation::Memory), ""); if (_type.isByteArray()) return abiDecodingFunctionByteArrayAvailableLength(_type, _fromMemory); + solAssert(_type.calldataStride() > 0, ""); string functionName = "abi_decode_available_length_" + @@ -1186,11 +1187,11 @@ string ABIFunctions::abiDecodingFunctionArrayAvailableLength(ArrayType const& _t mstore(array, length) dst := add(array, 0x20) - let src := offset - if gt(add(src, mul(length, )), end) { + let srcEnd := add(offset, mul(length, )) + if gt(srcEnd, end) { () } - for { let i := 0 } lt(i, length) { i := add(i, 1) } + for { let src := offset } lt(src, srcEnd) { src := add(src, ) } { let innerOffset := (src) @@ -1201,7 +1202,6 @@ string ABIFunctions::abiDecodingFunctionArrayAvailableLength(ArrayType const& _t mstore(dst, (elementPos, end)) dst := add(dst, 0x20) - src := add(src, ) } } )"); diff --git a/test/cmdlineTests/name_simplifier/output b/test/cmdlineTests/name_simplifier/output index 36d68bfd9..703ddc2dc 100644 --- a/test/cmdlineTests/name_simplifier/output +++ b/test/cmdlineTests/name_simplifier/output @@ -43,17 +43,16 @@ object "C_59" { let dst_1 := dst mstore(dst, _4) dst := add(dst, _2) + let srcEnd := add(add(offset, _5), 36) + if gt(srcEnd, calldatasize()) { revert(_1, _1) } let src := add(offset, 36) - if gt(add(add(offset, _5), 36), calldatasize()) { revert(_1, _1) } - let i := _1 - for { } lt(i, _4) { i := add(i, 1) } + for { } lt(src, srcEnd) { src := add(src, _2) } { if slt(sub(calldatasize(), src), _2) { revert(_1, _1) } - let value := allocate_memory_1236() + let value := allocate_memory_1174() mstore(value, calldataload(src)) mstore(dst, value) dst := add(dst, _2) - src := add(src, _2) } let ret, ret_1 := fun_sumArray(dst_1) let memPos := mload(64) @@ -68,7 +67,7 @@ object "C_59" { mstore(4, 0x41) revert(0, 0x24) } - function allocate_memory_1236() -> memPtr + function allocate_memory_1174() -> memPtr { memPtr := mload(64) let newFreePtr := add(memPtr, 32) diff --git a/test/cmdlineTests/revert_strings/output b/test/cmdlineTests/revert_strings/output index 989d7594c..df0029e63 100644 --- a/test/cmdlineTests/revert_strings/output +++ b/test/cmdlineTests/revert_strings/output @@ -252,18 +252,17 @@ object "C_15" { mstore(array, length) dst := add(array, 0x20) - let src := offset - if gt(add(src, mul(length, 0x20)), end) { + let srcEnd := add(offset, mul(length, 0x20)) + if gt(srcEnd, end) { revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef() } - for { let i := 0 } lt(i, length) { i := add(i, 1) } + for { let src := offset } lt(src, srcEnd) { src := add(src, 0x20) } { let elementPos := src mstore(dst, abi_decode_t_uint256(elementPos, end)) dst := add(dst, 0x20) - src := add(src, 0x20) } } @@ -282,11 +281,11 @@ object "C_15" { mstore(array, length) dst := add(array, 0x20) - let src := offset - if gt(add(src, mul(length, 0x20)), end) { + let srcEnd := add(offset, mul(length, 0x20)) + if gt(srcEnd, end) { revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef() } - for { let i := 0 } lt(i, length) { i := add(i, 1) } + for { let src := offset } lt(src, srcEnd) { src := add(src, 0x20) } { let innerOffset := calldataload(src) @@ -295,7 +294,6 @@ object "C_15" { mstore(dst, abi_decode_t_array$_t_uint256_$dyn_memory_ptr(elementPos, end)) dst := add(dst, 0x20) - src := add(src, 0x20) } } diff --git a/test/cmdlineTests/standard_function_debug_info/output.json b/test/cmdlineTests/standard_function_debug_info/output.json index ed0de9572..bb86d0924 100644 --- a/test/cmdlineTests/standard_function_debug_info/output.json +++ b/test/cmdlineTests/standard_function_debug_info/output.json @@ -1 +1 @@ -{"contracts":{"a.sol":{"A":{"evm":{"bytecode":{"functionDebugData":{}},"deployedBytecode":{"functionDebugData":{"@f_19":{"entryPoint":96,"id":19,"parameterSlots":1,"returnSlots":1},"abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":439,"id":null,"parameterSlots":3,"returnSlots":1},"abi_decode_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":551,"id":null,"parameterSlots":2,"returnSlots":1},"abi_decode_t_uint256":{"entryPoint":418,"id":null,"parameterSlots":2,"returnSlots":1},"abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":597,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_t_uint256_to_t_uint256_fromStack":{"entryPoint":670,"id":null,"parameterSlots":2,"returnSlots":0},"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed":{"entryPoint":685,"id":null,"parameterSlots":2,"returnSlots":1},"allocate_memory":{"entryPoint":309,"id":null,"parameterSlots":1,"returnSlots":1},"allocate_unbounded":{"entryPoint":171,"id":null,"parameterSlots":0,"returnSlots":1},"array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":336,"id":null,"parameterSlots":1,"returnSlots":1},"checked_add_t_uint256":{"entryPoint":806,"id":null,"parameterSlots":2,"returnSlots":1},"cleanup_t_uint256":{"entryPoint":385,"id":null,"parameterSlots":1,"returnSlots":1},"finalize_allocation":{"entryPoint":260,"id":null,"parameterSlots":2,"returnSlots":0},"panic_error_0x11":{"entryPoint":759,"id":null,"parameterSlots":0,"returnSlots":0},"panic_error_0x32":{"entryPoint":712,"id":null,"parameterSlots":0,"returnSlots":0},"panic_error_0x41":{"entryPoint":213,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d":{"entryPoint":191,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef":{"entryPoint":380,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db":{"entryPoint":186,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b":{"entryPoint":181,"id":null,"parameterSlots":0,"returnSlots":0},"round_up_to_mul_of_32":{"entryPoint":196,"id":null,"parameterSlots":1,"returnSlots":1},"validator_revert_t_uint256":{"entryPoint":395,"id":null,"parameterSlots":1,"returnSlots":0}}}}}}},"sources":{"a.sol":{"id":0}}} +{"contracts":{"a.sol":{"A":{"evm":{"bytecode":{"functionDebugData":{}},"deployedBytecode":{"functionDebugData":{"@f_19":{"entryPoint":96,"id":19,"parameterSlots":1,"returnSlots":1},"abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":439,"id":null,"parameterSlots":3,"returnSlots":1},"abi_decode_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":544,"id":null,"parameterSlots":2,"returnSlots":1},"abi_decode_t_uint256":{"entryPoint":418,"id":null,"parameterSlots":2,"returnSlots":1},"abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":590,"id":null,"parameterSlots":2,"returnSlots":1},"abi_encode_t_uint256_to_t_uint256_fromStack":{"entryPoint":663,"id":null,"parameterSlots":2,"returnSlots":0},"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed":{"entryPoint":678,"id":null,"parameterSlots":2,"returnSlots":1},"allocate_memory":{"entryPoint":309,"id":null,"parameterSlots":1,"returnSlots":1},"allocate_unbounded":{"entryPoint":171,"id":null,"parameterSlots":0,"returnSlots":1},"array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr":{"entryPoint":336,"id":null,"parameterSlots":1,"returnSlots":1},"checked_add_t_uint256":{"entryPoint":799,"id":null,"parameterSlots":2,"returnSlots":1},"cleanup_t_uint256":{"entryPoint":385,"id":null,"parameterSlots":1,"returnSlots":1},"finalize_allocation":{"entryPoint":260,"id":null,"parameterSlots":2,"returnSlots":0},"panic_error_0x11":{"entryPoint":752,"id":null,"parameterSlots":0,"returnSlots":0},"panic_error_0x32":{"entryPoint":705,"id":null,"parameterSlots":0,"returnSlots":0},"panic_error_0x41":{"entryPoint":213,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d":{"entryPoint":191,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef":{"entryPoint":380,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db":{"entryPoint":186,"id":null,"parameterSlots":0,"returnSlots":0},"revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b":{"entryPoint":181,"id":null,"parameterSlots":0,"returnSlots":0},"round_up_to_mul_of_32":{"entryPoint":196,"id":null,"parameterSlots":1,"returnSlots":1},"validator_revert_t_uint256":{"entryPoint":395,"id":null,"parameterSlots":1,"returnSlots":0}}}}}}},"sources":{"a.sol":{"id":0}}} diff --git a/test/cmdlineTests/standard_generatedSources/output.json b/test/cmdlineTests/standard_generatedSources/output.json index 6c7f72b6a..05405ceab 100644 --- a/test/cmdlineTests/standard_generatedSources/output.json +++ b/test/cmdlineTests/standard_generatedSources/output.json @@ -1,4 +1,4 @@ -{"contracts":{"a.sol":{"A":{"evm":{"bytecode":{"generatedSources":[],"object":""},"deployedBytecode":{"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:4001:1","statements":[{"body":{"nodeType":"YulBlock","src":"47:35:1","statements":[{"nodeType":"YulAssignment","src":"57:19:1","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"73:2:1","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"67:5:1"},"nodeType":"YulFunctionCall","src":"67:9:1"},"variableNames":[{"name":"memPtr","nodeType":"YulIdentifier","src":"57:6:1"}]}]},"name":"allocate_unbounded","nodeType":"YulFunctionDefinition","returnVariables":[{"name":"memPtr","nodeType":"YulTypedName","src":"40:6:1","type":""}],"src":"7:75:1"},{"body":{"nodeType":"YulBlock","src":"177:28:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"194:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"197:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"187:6:1"},"nodeType":"YulFunctionCall","src":"187:12:1"},"nodeType":"YulExpressionStatement","src":"187:12:1"}]},"name":"revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b","nodeType":"YulFunctionDefinition","src":"88:117:1"},{"body":{"nodeType":"YulBlock","src":"300:28:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"317:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"320:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"310:6:1"},"nodeType":"YulFunctionCall","src":"310:12:1"},"nodeType":"YulExpressionStatement","src":"310:12:1"}]},"name":"revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db","nodeType":"YulFunctionDefinition","src":"211:117:1"},{"body":{"nodeType":"YulBlock","src":"423:28:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"440:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"443:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"433:6:1"},"nodeType":"YulFunctionCall","src":"433:12:1"},"nodeType":"YulExpressionStatement","src":"433:12:1"}]},"name":"revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d","nodeType":"YulFunctionDefinition","src":"334:117:1"},{"body":{"nodeType":"YulBlock","src":"505:54:1","statements":[{"nodeType":"YulAssignment","src":"515:38:1","value":{"arguments":[{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"533:5:1"},{"kind":"number","nodeType":"YulLiteral","src":"540:2:1","type":"","value":"31"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"529:3:1"},"nodeType":"YulFunctionCall","src":"529:14:1"},{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"549:2:1","type":"","value":"31"}],"functionName":{"name":"not","nodeType":"YulIdentifier","src":"545:3:1"},"nodeType":"YulFunctionCall","src":"545:7:1"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"525:3:1"},"nodeType":"YulFunctionCall","src":"525:28:1"},"variableNames":[{"name":"result","nodeType":"YulIdentifier","src":"515:6:1"}]}]},"name":"round_up_to_mul_of_32","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"488:5:1","type":""}],"returnVariables":[{"name":"result","nodeType":"YulTypedName","src":"498:6:1","type":""}],"src":"457:102:1"},{"body":{"nodeType":"YulBlock","src":"593:152:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"610:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"613:77:1","type":"","value":"35408467139433450592217433187231851964531694900788300625387963629091585785856"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"603:6:1"},"nodeType":"YulFunctionCall","src":"603:88:1"},"nodeType":"YulExpressionStatement","src":"603:88:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"707:1:1","type":"","value":"4"},{"kind":"number","nodeType":"YulLiteral","src":"710:4:1","type":"","value":"0x41"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"700:6:1"},"nodeType":"YulFunctionCall","src":"700:15:1"},"nodeType":"YulExpressionStatement","src":"700:15:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"731:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"734:4:1","type":"","value":"0x24"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"724:6:1"},"nodeType":"YulFunctionCall","src":"724:15:1"},"nodeType":"YulExpressionStatement","src":"724:15:1"}]},"name":"panic_error_0x41","nodeType":"YulFunctionDefinition","src":"565:180:1"},{"body":{"nodeType":"YulBlock","src":"794:238:1","statements":[{"nodeType":"YulVariableDeclaration","src":"804:58:1","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"826:6:1"},{"arguments":[{"name":"size","nodeType":"YulIdentifier","src":"856:4:1"}],"functionName":{"name":"round_up_to_mul_of_32","nodeType":"YulIdentifier","src":"834:21:1"},"nodeType":"YulFunctionCall","src":"834:27:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"822:3:1"},"nodeType":"YulFunctionCall","src":"822:40:1"},"variables":[{"name":"newFreePtr","nodeType":"YulTypedName","src":"808:10:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"973:22:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"975:16:1"},"nodeType":"YulFunctionCall","src":"975:18:1"},"nodeType":"YulExpressionStatement","src":"975:18:1"}]},"condition":{"arguments":[{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"916:10:1"},{"kind":"number","nodeType":"YulLiteral","src":"928:18:1","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"913:2:1"},"nodeType":"YulFunctionCall","src":"913:34:1"},{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"952:10:1"},{"name":"memPtr","nodeType":"YulIdentifier","src":"964:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"949:2:1"},"nodeType":"YulFunctionCall","src":"949:22:1"}],"functionName":{"name":"or","nodeType":"YulIdentifier","src":"910:2:1"},"nodeType":"YulFunctionCall","src":"910:62:1"},"nodeType":"YulIf","src":"907:88:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1011:2:1","type":"","value":"64"},{"name":"newFreePtr","nodeType":"YulIdentifier","src":"1015:10:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1004:6:1"},"nodeType":"YulFunctionCall","src":"1004:22:1"},"nodeType":"YulExpressionStatement","src":"1004:22:1"}]},"name":"finalize_allocation","nodeType":"YulFunctionDefinition","parameters":[{"name":"memPtr","nodeType":"YulTypedName","src":"780:6:1","type":""},{"name":"size","nodeType":"YulTypedName","src":"788:4:1","type":""}],"src":"751:281:1"},{"body":{"nodeType":"YulBlock","src":"1079:88:1","statements":[{"nodeType":"YulAssignment","src":"1089:30:1","value":{"arguments":[],"functionName":{"name":"allocate_unbounded","nodeType":"YulIdentifier","src":"1099:18:1"},"nodeType":"YulFunctionCall","src":"1099:20:1"},"variableNames":[{"name":"memPtr","nodeType":"YulIdentifier","src":"1089:6:1"}]},{"expression":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"1148:6:1"},{"name":"size","nodeType":"YulIdentifier","src":"1156:4:1"}],"functionName":{"name":"finalize_allocation","nodeType":"YulIdentifier","src":"1128:19:1"},"nodeType":"YulFunctionCall","src":"1128:33:1"},"nodeType":"YulExpressionStatement","src":"1128:33:1"}]},"name":"allocate_memory","nodeType":"YulFunctionDefinition","parameters":[{"name":"size","nodeType":"YulTypedName","src":"1063:4:1","type":""}],"returnVariables":[{"name":"memPtr","nodeType":"YulTypedName","src":"1072:6:1","type":""}],"src":"1038:129:1"},{"body":{"nodeType":"YulBlock","src":"1255:229:1","statements":[{"body":{"nodeType":"YulBlock","src":"1360:22:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"1362:16:1"},"nodeType":"YulFunctionCall","src":"1362:18:1"},"nodeType":"YulExpressionStatement","src":"1362:18:1"}]},"condition":{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"1332:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"1340:18:1","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"1329:2:1"},"nodeType":"YulFunctionCall","src":"1329:30:1"},"nodeType":"YulIf","src":"1326:56:1"},{"nodeType":"YulAssignment","src":"1392:25:1","value":{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"1404:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"1412:4:1","type":"","value":"0x20"}],"functionName":{"name":"mul","nodeType":"YulIdentifier","src":"1400:3:1"},"nodeType":"YulFunctionCall","src":"1400:17:1"},"variableNames":[{"name":"size","nodeType":"YulIdentifier","src":"1392:4:1"}]},{"nodeType":"YulAssignment","src":"1454:23:1","value":{"arguments":[{"name":"size","nodeType":"YulIdentifier","src":"1466:4:1"},{"kind":"number","nodeType":"YulLiteral","src":"1472:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1462:3:1"},"nodeType":"YulFunctionCall","src":"1462:15:1"},"variableNames":[{"name":"size","nodeType":"YulIdentifier","src":"1454:4:1"}]}]},"name":"array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"length","nodeType":"YulTypedName","src":"1239:6:1","type":""}],"returnVariables":[{"name":"size","nodeType":"YulTypedName","src":"1250:4:1","type":""}],"src":"1173:311:1"},{"body":{"nodeType":"YulBlock","src":"1579:28:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1596:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1599:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"1589:6:1"},"nodeType":"YulFunctionCall","src":"1589:12:1"},"nodeType":"YulExpressionStatement","src":"1589:12:1"}]},"name":"revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef","nodeType":"YulFunctionDefinition","src":"1490:117:1"},{"body":{"nodeType":"YulBlock","src":"1658:32:1","statements":[{"nodeType":"YulAssignment","src":"1668:16:1","value":{"name":"value","nodeType":"YulIdentifier","src":"1679:5:1"},"variableNames":[{"name":"cleaned","nodeType":"YulIdentifier","src":"1668:7:1"}]}]},"name":"cleanup_t_uint256","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"1640:5:1","type":""}],"returnVariables":[{"name":"cleaned","nodeType":"YulTypedName","src":"1650:7:1","type":""}],"src":"1613:77:1"},{"body":{"nodeType":"YulBlock","src":"1739:79:1","statements":[{"body":{"nodeType":"YulBlock","src":"1796:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1805:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1808:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"1798:6:1"},"nodeType":"YulFunctionCall","src":"1798:12:1"},"nodeType":"YulExpressionStatement","src":"1798:12:1"}]},"condition":{"arguments":[{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"1762:5:1"},{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"1787:5:1"}],"functionName":{"name":"cleanup_t_uint256","nodeType":"YulIdentifier","src":"1769:17:1"},"nodeType":"YulFunctionCall","src":"1769:24:1"}],"functionName":{"name":"eq","nodeType":"YulIdentifier","src":"1759:2:1"},"nodeType":"YulFunctionCall","src":"1759:35:1"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"1752:6:1"},"nodeType":"YulFunctionCall","src":"1752:43:1"},"nodeType":"YulIf","src":"1749:63:1"}]},"name":"validator_revert_t_uint256","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"1732:5:1","type":""}],"src":"1696:122:1"},{"body":{"nodeType":"YulBlock","src":"1876:87:1","statements":[{"nodeType":"YulAssignment","src":"1886:29:1","value":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"1908:6:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"1895:12:1"},"nodeType":"YulFunctionCall","src":"1895:20:1"},"variableNames":[{"name":"value","nodeType":"YulIdentifier","src":"1886:5:1"}]},{"expression":{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"1951:5:1"}],"functionName":{"name":"validator_revert_t_uint256","nodeType":"YulIdentifier","src":"1924:26:1"},"nodeType":"YulFunctionCall","src":"1924:33:1"},"nodeType":"YulExpressionStatement","src":"1924:33:1"}]},"name":"abi_decode_t_uint256","nodeType":"YulFunctionDefinition","parameters":[{"name":"offset","nodeType":"YulTypedName","src":"1854:6:1","type":""},{"name":"end","nodeType":"YulTypedName","src":"1862:3:1","type":""}],"returnVariables":[{"name":"value","nodeType":"YulTypedName","src":"1870:5:1","type":""}],"src":"1824:139:1"},{"body":{"nodeType":"YulBlock","src":"2088:620:1","statements":[{"nodeType":"YulAssignment","src":"2098:90:1","value":{"arguments":[{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"2180:6:1"}],"functionName":{"name":"array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulIdentifier","src":"2123:56:1"},"nodeType":"YulFunctionCall","src":"2123:64:1"}],"functionName":{"name":"allocate_memory","nodeType":"YulIdentifier","src":"2107:15:1"},"nodeType":"YulFunctionCall","src":"2107:81:1"},"variableNames":[{"name":"array","nodeType":"YulIdentifier","src":"2098:5:1"}]},{"nodeType":"YulVariableDeclaration","src":"2197:16:1","value":{"name":"array","nodeType":"YulIdentifier","src":"2208:5:1"},"variables":[{"name":"dst","nodeType":"YulTypedName","src":"2201:3:1","type":""}]},{"expression":{"arguments":[{"name":"array","nodeType":"YulIdentifier","src":"2230:5:1"},{"name":"length","nodeType":"YulIdentifier","src":"2237:6:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2223:6:1"},"nodeType":"YulFunctionCall","src":"2223:21:1"},"nodeType":"YulExpressionStatement","src":"2223:21:1"},{"nodeType":"YulAssignment","src":"2253:23:1","value":{"arguments":[{"name":"array","nodeType":"YulIdentifier","src":"2264:5:1"},{"kind":"number","nodeType":"YulLiteral","src":"2271:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2260:3:1"},"nodeType":"YulFunctionCall","src":"2260:16:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"2253:3:1"}]},{"nodeType":"YulVariableDeclaration","src":"2286:17:1","value":{"name":"offset","nodeType":"YulIdentifier","src":"2297:6:1"},"variables":[{"name":"src","nodeType":"YulTypedName","src":"2290:3:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"2352:103:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef","nodeType":"YulIdentifier","src":"2366:77:1"},"nodeType":"YulFunctionCall","src":"2366:79:1"},"nodeType":"YulExpressionStatement","src":"2366:79:1"}]},"condition":{"arguments":[{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"2322:3:1"},{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"2331:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"2339:4:1","type":"","value":"0x20"}],"functionName":{"name":"mul","nodeType":"YulIdentifier","src":"2327:3:1"},"nodeType":"YulFunctionCall","src":"2327:17:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2318:3:1"},"nodeType":"YulFunctionCall","src":"2318:27:1"},{"name":"end","nodeType":"YulIdentifier","src":"2347:3:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"2315:2:1"},"nodeType":"YulFunctionCall","src":"2315:36:1"},"nodeType":"YulIf","src":"2312:143:1"},{"body":{"nodeType":"YulBlock","src":"2524:178:1","statements":[{"nodeType":"YulVariableDeclaration","src":"2539:21:1","value":{"name":"src","nodeType":"YulIdentifier","src":"2557:3:1"},"variables":[{"name":"elementPos","nodeType":"YulTypedName","src":"2543:10:1","type":""}]},{"expression":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"2581:3:1"},{"arguments":[{"name":"elementPos","nodeType":"YulIdentifier","src":"2607:10:1"},{"name":"end","nodeType":"YulIdentifier","src":"2619:3:1"}],"functionName":{"name":"abi_decode_t_uint256","nodeType":"YulIdentifier","src":"2586:20:1"},"nodeType":"YulFunctionCall","src":"2586:37:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2574:6:1"},"nodeType":"YulFunctionCall","src":"2574:50:1"},"nodeType":"YulExpressionStatement","src":"2574:50:1"},{"nodeType":"YulAssignment","src":"2637:21:1","value":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"2648:3:1"},{"kind":"number","nodeType":"YulLiteral","src":"2653:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2644:3:1"},"nodeType":"YulFunctionCall","src":"2644:14:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"2637:3:1"}]},{"nodeType":"YulAssignment","src":"2671:21:1","value":{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"2682:3:1"},{"kind":"number","nodeType":"YulLiteral","src":"2687:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2678:3:1"},"nodeType":"YulFunctionCall","src":"2678:14:1"},"variableNames":[{"name":"src","nodeType":"YulIdentifier","src":"2671:3:1"}]}]},"condition":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"2486:1:1"},{"name":"length","nodeType":"YulIdentifier","src":"2489:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"2483:2:1"},"nodeType":"YulFunctionCall","src":"2483:13:1"},"nodeType":"YulForLoop","post":{"nodeType":"YulBlock","src":"2497:18:1","statements":[{"nodeType":"YulAssignment","src":"2499:14:1","value":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"2508:1:1"},{"kind":"number","nodeType":"YulLiteral","src":"2511:1:1","type":"","value":"1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2504:3:1"},"nodeType":"YulFunctionCall","src":"2504:9:1"},"variableNames":[{"name":"i","nodeType":"YulIdentifier","src":"2499:1:1"}]}]},"pre":{"nodeType":"YulBlock","src":"2468:14:1","statements":[{"nodeType":"YulVariableDeclaration","src":"2470:10:1","value":{"kind":"number","nodeType":"YulLiteral","src":"2479:1:1","type":"","value":"0"},"variables":[{"name":"i","nodeType":"YulTypedName","src":"2474:1:1","type":""}]}]},"src":"2464:238:1"}]},"name":"abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"offset","nodeType":"YulTypedName","src":"2058:6:1","type":""},{"name":"length","nodeType":"YulTypedName","src":"2066:6:1","type":""},{"name":"end","nodeType":"YulTypedName","src":"2074:3:1","type":""}],"returnVariables":[{"name":"array","nodeType":"YulTypedName","src":"2082:5:1","type":""}],"src":"1986:722:1"},{"body":{"nodeType":"YulBlock","src":"2808:293:1","statements":[{"body":{"nodeType":"YulBlock","src":"2857:83:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d","nodeType":"YulIdentifier","src":"2859:77:1"},"nodeType":"YulFunctionCall","src":"2859:79:1"},"nodeType":"YulExpressionStatement","src":"2859:79:1"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"2836:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"2844:4:1","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2832:3:1"},"nodeType":"YulFunctionCall","src":"2832:17:1"},{"name":"end","nodeType":"YulIdentifier","src":"2851:3:1"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"2828:3:1"},"nodeType":"YulFunctionCall","src":"2828:27:1"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"2821:6:1"},"nodeType":"YulFunctionCall","src":"2821:35:1"},"nodeType":"YulIf","src":"2818:122:1"},{"nodeType":"YulVariableDeclaration","src":"2949:34:1","value":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"2976:6:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"2963:12:1"},"nodeType":"YulFunctionCall","src":"2963:20:1"},"variables":[{"name":"length","nodeType":"YulTypedName","src":"2953:6:1","type":""}]},{"nodeType":"YulAssignment","src":"2992:103:1","value":{"arguments":[{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"3068:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"3076:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3064:3:1"},"nodeType":"YulFunctionCall","src":"3064:17:1"},{"name":"length","nodeType":"YulIdentifier","src":"3083:6:1"},{"name":"end","nodeType":"YulIdentifier","src":"3091:3:1"}],"functionName":{"name":"abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulIdentifier","src":"3001:62:1"},"nodeType":"YulFunctionCall","src":"3001:94:1"},"variableNames":[{"name":"array","nodeType":"YulIdentifier","src":"2992:5:1"}]}]},"name":"abi_decode_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"offset","nodeType":"YulTypedName","src":"2786:6:1","type":""},{"name":"end","nodeType":"YulTypedName","src":"2794:3:1","type":""}],"returnVariables":[{"name":"array","nodeType":"YulTypedName","src":"2802:5:1","type":""}],"src":"2731:370:1"},{"body":{"nodeType":"YulBlock","src":"3198:448:1","statements":[{"body":{"nodeType":"YulBlock","src":"3244:83:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b","nodeType":"YulIdentifier","src":"3246:77:1"},"nodeType":"YulFunctionCall","src":"3246:79:1"},"nodeType":"YulExpressionStatement","src":"3246:79:1"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"3219:7:1"},{"name":"headStart","nodeType":"YulIdentifier","src":"3228:9:1"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"3215:3:1"},"nodeType":"YulFunctionCall","src":"3215:23:1"},{"kind":"number","nodeType":"YulLiteral","src":"3240:2:1","type":"","value":"32"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"3211:3:1"},"nodeType":"YulFunctionCall","src":"3211:32:1"},"nodeType":"YulIf","src":"3208:119:1"},{"nodeType":"YulBlock","src":"3337:302:1","statements":[{"nodeType":"YulVariableDeclaration","src":"3352:45:1","value":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3383:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"3394:1:1","type":"","value":"0"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3379:3:1"},"nodeType":"YulFunctionCall","src":"3379:17:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"3366:12:1"},"nodeType":"YulFunctionCall","src":"3366:31:1"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"3356:6:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"3444:83:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db","nodeType":"YulIdentifier","src":"3446:77:1"},"nodeType":"YulFunctionCall","src":"3446:79:1"},"nodeType":"YulExpressionStatement","src":"3446:79:1"}]},"condition":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"3416:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"3424:18:1","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"3413:2:1"},"nodeType":"YulFunctionCall","src":"3413:30:1"},"nodeType":"YulIf","src":"3410:117:1"},{"nodeType":"YulAssignment","src":"3541:88:1","value":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3601:9:1"},{"name":"offset","nodeType":"YulIdentifier","src":"3612:6:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3597:3:1"},"nodeType":"YulFunctionCall","src":"3597:22:1"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"3621:7:1"}],"functionName":{"name":"abi_decode_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulIdentifier","src":"3551:45:1"},"nodeType":"YulFunctionCall","src":"3551:78:1"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"3541:6:1"}]}]}]},"name":"abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"3168:9:1","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"3179:7:1","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"3191:6:1","type":""}],"src":"3107:539:1"},{"body":{"nodeType":"YulBlock","src":"3717:53:1","statements":[{"expression":{"arguments":[{"name":"pos","nodeType":"YulIdentifier","src":"3734:3:1"},{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"3757:5:1"}],"functionName":{"name":"cleanup_t_uint256","nodeType":"YulIdentifier","src":"3739:17:1"},"nodeType":"YulFunctionCall","src":"3739:24:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3727:6:1"},"nodeType":"YulFunctionCall","src":"3727:37:1"},"nodeType":"YulExpressionStatement","src":"3727:37:1"}]},"name":"abi_encode_t_uint256_to_t_uint256_fromStack","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"3705:5:1","type":""},{"name":"pos","nodeType":"YulTypedName","src":"3712:3:1","type":""}],"src":"3652:118:1"},{"body":{"nodeType":"YulBlock","src":"3874:124:1","statements":[{"nodeType":"YulAssignment","src":"3884:26:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3896:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"3907:2:1","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3892:3:1"},"nodeType":"YulFunctionCall","src":"3892:18:1"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"3884:4:1"}]},{"expression":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"3964:6:1"},{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3977:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"3988:1:1","type":"","value":"0"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3973:3:1"},"nodeType":"YulFunctionCall","src":"3973:17:1"}],"functionName":{"name":"abi_encode_t_uint256_to_t_uint256_fromStack","nodeType":"YulIdentifier","src":"3920:43:1"},"nodeType":"YulFunctionCall","src":"3920:71:1"},"nodeType":"YulExpressionStatement","src":"3920:71:1"}]},"name":"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"3846:9:1","type":""},{"name":"value0","nodeType":"YulTypedName","src":"3858:6:1","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"3869:4:1","type":""}],"src":"3776:222:1"}]},"contents":"{ +{"contracts":{"a.sol":{"A":{"evm":{"bytecode":{"generatedSources":[],"object":""},"deployedBytecode":{"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:3989:1","statements":[{"body":{"nodeType":"YulBlock","src":"47:35:1","statements":[{"nodeType":"YulAssignment","src":"57:19:1","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"73:2:1","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"67:5:1"},"nodeType":"YulFunctionCall","src":"67:9:1"},"variableNames":[{"name":"memPtr","nodeType":"YulIdentifier","src":"57:6:1"}]}]},"name":"allocate_unbounded","nodeType":"YulFunctionDefinition","returnVariables":[{"name":"memPtr","nodeType":"YulTypedName","src":"40:6:1","type":""}],"src":"7:75:1"},{"body":{"nodeType":"YulBlock","src":"177:28:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"194:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"197:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"187:6:1"},"nodeType":"YulFunctionCall","src":"187:12:1"},"nodeType":"YulExpressionStatement","src":"187:12:1"}]},"name":"revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b","nodeType":"YulFunctionDefinition","src":"88:117:1"},{"body":{"nodeType":"YulBlock","src":"300:28:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"317:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"320:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"310:6:1"},"nodeType":"YulFunctionCall","src":"310:12:1"},"nodeType":"YulExpressionStatement","src":"310:12:1"}]},"name":"revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db","nodeType":"YulFunctionDefinition","src":"211:117:1"},{"body":{"nodeType":"YulBlock","src":"423:28:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"440:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"443:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"433:6:1"},"nodeType":"YulFunctionCall","src":"433:12:1"},"nodeType":"YulExpressionStatement","src":"433:12:1"}]},"name":"revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d","nodeType":"YulFunctionDefinition","src":"334:117:1"},{"body":{"nodeType":"YulBlock","src":"505:54:1","statements":[{"nodeType":"YulAssignment","src":"515:38:1","value":{"arguments":[{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"533:5:1"},{"kind":"number","nodeType":"YulLiteral","src":"540:2:1","type":"","value":"31"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"529:3:1"},"nodeType":"YulFunctionCall","src":"529:14:1"},{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"549:2:1","type":"","value":"31"}],"functionName":{"name":"not","nodeType":"YulIdentifier","src":"545:3:1"},"nodeType":"YulFunctionCall","src":"545:7:1"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"525:3:1"},"nodeType":"YulFunctionCall","src":"525:28:1"},"variableNames":[{"name":"result","nodeType":"YulIdentifier","src":"515:6:1"}]}]},"name":"round_up_to_mul_of_32","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"488:5:1","type":""}],"returnVariables":[{"name":"result","nodeType":"YulTypedName","src":"498:6:1","type":""}],"src":"457:102:1"},{"body":{"nodeType":"YulBlock","src":"593:152:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"610:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"613:77:1","type":"","value":"35408467139433450592217433187231851964531694900788300625387963629091585785856"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"603:6:1"},"nodeType":"YulFunctionCall","src":"603:88:1"},"nodeType":"YulExpressionStatement","src":"603:88:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"707:1:1","type":"","value":"4"},{"kind":"number","nodeType":"YulLiteral","src":"710:4:1","type":"","value":"0x41"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"700:6:1"},"nodeType":"YulFunctionCall","src":"700:15:1"},"nodeType":"YulExpressionStatement","src":"700:15:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"731:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"734:4:1","type":"","value":"0x24"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"724:6:1"},"nodeType":"YulFunctionCall","src":"724:15:1"},"nodeType":"YulExpressionStatement","src":"724:15:1"}]},"name":"panic_error_0x41","nodeType":"YulFunctionDefinition","src":"565:180:1"},{"body":{"nodeType":"YulBlock","src":"794:238:1","statements":[{"nodeType":"YulVariableDeclaration","src":"804:58:1","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"826:6:1"},{"arguments":[{"name":"size","nodeType":"YulIdentifier","src":"856:4:1"}],"functionName":{"name":"round_up_to_mul_of_32","nodeType":"YulIdentifier","src":"834:21:1"},"nodeType":"YulFunctionCall","src":"834:27:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"822:3:1"},"nodeType":"YulFunctionCall","src":"822:40:1"},"variables":[{"name":"newFreePtr","nodeType":"YulTypedName","src":"808:10:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"973:22:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"975:16:1"},"nodeType":"YulFunctionCall","src":"975:18:1"},"nodeType":"YulExpressionStatement","src":"975:18:1"}]},"condition":{"arguments":[{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"916:10:1"},{"kind":"number","nodeType":"YulLiteral","src":"928:18:1","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"913:2:1"},"nodeType":"YulFunctionCall","src":"913:34:1"},{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"952:10:1"},{"name":"memPtr","nodeType":"YulIdentifier","src":"964:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"949:2:1"},"nodeType":"YulFunctionCall","src":"949:22:1"}],"functionName":{"name":"or","nodeType":"YulIdentifier","src":"910:2:1"},"nodeType":"YulFunctionCall","src":"910:62:1"},"nodeType":"YulIf","src":"907:88:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1011:2:1","type":"","value":"64"},{"name":"newFreePtr","nodeType":"YulIdentifier","src":"1015:10:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1004:6:1"},"nodeType":"YulFunctionCall","src":"1004:22:1"},"nodeType":"YulExpressionStatement","src":"1004:22:1"}]},"name":"finalize_allocation","nodeType":"YulFunctionDefinition","parameters":[{"name":"memPtr","nodeType":"YulTypedName","src":"780:6:1","type":""},{"name":"size","nodeType":"YulTypedName","src":"788:4:1","type":""}],"src":"751:281:1"},{"body":{"nodeType":"YulBlock","src":"1079:88:1","statements":[{"nodeType":"YulAssignment","src":"1089:30:1","value":{"arguments":[],"functionName":{"name":"allocate_unbounded","nodeType":"YulIdentifier","src":"1099:18:1"},"nodeType":"YulFunctionCall","src":"1099:20:1"},"variableNames":[{"name":"memPtr","nodeType":"YulIdentifier","src":"1089:6:1"}]},{"expression":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"1148:6:1"},{"name":"size","nodeType":"YulIdentifier","src":"1156:4:1"}],"functionName":{"name":"finalize_allocation","nodeType":"YulIdentifier","src":"1128:19:1"},"nodeType":"YulFunctionCall","src":"1128:33:1"},"nodeType":"YulExpressionStatement","src":"1128:33:1"}]},"name":"allocate_memory","nodeType":"YulFunctionDefinition","parameters":[{"name":"size","nodeType":"YulTypedName","src":"1063:4:1","type":""}],"returnVariables":[{"name":"memPtr","nodeType":"YulTypedName","src":"1072:6:1","type":""}],"src":"1038:129:1"},{"body":{"nodeType":"YulBlock","src":"1255:229:1","statements":[{"body":{"nodeType":"YulBlock","src":"1360:22:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"1362:16:1"},"nodeType":"YulFunctionCall","src":"1362:18:1"},"nodeType":"YulExpressionStatement","src":"1362:18:1"}]},"condition":{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"1332:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"1340:18:1","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"1329:2:1"},"nodeType":"YulFunctionCall","src":"1329:30:1"},"nodeType":"YulIf","src":"1326:56:1"},{"nodeType":"YulAssignment","src":"1392:25:1","value":{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"1404:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"1412:4:1","type":"","value":"0x20"}],"functionName":{"name":"mul","nodeType":"YulIdentifier","src":"1400:3:1"},"nodeType":"YulFunctionCall","src":"1400:17:1"},"variableNames":[{"name":"size","nodeType":"YulIdentifier","src":"1392:4:1"}]},{"nodeType":"YulAssignment","src":"1454:23:1","value":{"arguments":[{"name":"size","nodeType":"YulIdentifier","src":"1466:4:1"},{"kind":"number","nodeType":"YulLiteral","src":"1472:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1462:3:1"},"nodeType":"YulFunctionCall","src":"1462:15:1"},"variableNames":[{"name":"size","nodeType":"YulIdentifier","src":"1454:4:1"}]}]},"name":"array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"length","nodeType":"YulTypedName","src":"1239:6:1","type":""}],"returnVariables":[{"name":"size","nodeType":"YulTypedName","src":"1250:4:1","type":""}],"src":"1173:311:1"},{"body":{"nodeType":"YulBlock","src":"1579:28:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1596:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1599:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"1589:6:1"},"nodeType":"YulFunctionCall","src":"1589:12:1"},"nodeType":"YulExpressionStatement","src":"1589:12:1"}]},"name":"revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef","nodeType":"YulFunctionDefinition","src":"1490:117:1"},{"body":{"nodeType":"YulBlock","src":"1658:32:1","statements":[{"nodeType":"YulAssignment","src":"1668:16:1","value":{"name":"value","nodeType":"YulIdentifier","src":"1679:5:1"},"variableNames":[{"name":"cleaned","nodeType":"YulIdentifier","src":"1668:7:1"}]}]},"name":"cleanup_t_uint256","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"1640:5:1","type":""}],"returnVariables":[{"name":"cleaned","nodeType":"YulTypedName","src":"1650:7:1","type":""}],"src":"1613:77:1"},{"body":{"nodeType":"YulBlock","src":"1739:79:1","statements":[{"body":{"nodeType":"YulBlock","src":"1796:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1805:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1808:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"1798:6:1"},"nodeType":"YulFunctionCall","src":"1798:12:1"},"nodeType":"YulExpressionStatement","src":"1798:12:1"}]},"condition":{"arguments":[{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"1762:5:1"},{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"1787:5:1"}],"functionName":{"name":"cleanup_t_uint256","nodeType":"YulIdentifier","src":"1769:17:1"},"nodeType":"YulFunctionCall","src":"1769:24:1"}],"functionName":{"name":"eq","nodeType":"YulIdentifier","src":"1759:2:1"},"nodeType":"YulFunctionCall","src":"1759:35:1"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"1752:6:1"},"nodeType":"YulFunctionCall","src":"1752:43:1"},"nodeType":"YulIf","src":"1749:63:1"}]},"name":"validator_revert_t_uint256","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"1732:5:1","type":""}],"src":"1696:122:1"},{"body":{"nodeType":"YulBlock","src":"1876:87:1","statements":[{"nodeType":"YulAssignment","src":"1886:29:1","value":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"1908:6:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"1895:12:1"},"nodeType":"YulFunctionCall","src":"1895:20:1"},"variableNames":[{"name":"value","nodeType":"YulIdentifier","src":"1886:5:1"}]},{"expression":{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"1951:5:1"}],"functionName":{"name":"validator_revert_t_uint256","nodeType":"YulIdentifier","src":"1924:26:1"},"nodeType":"YulFunctionCall","src":"1924:33:1"},"nodeType":"YulExpressionStatement","src":"1924:33:1"}]},"name":"abi_decode_t_uint256","nodeType":"YulFunctionDefinition","parameters":[{"name":"offset","nodeType":"YulTypedName","src":"1854:6:1","type":""},{"name":"end","nodeType":"YulTypedName","src":"1862:3:1","type":""}],"returnVariables":[{"name":"value","nodeType":"YulTypedName","src":"1870:5:1","type":""}],"src":"1824:139:1"},{"body":{"nodeType":"YulBlock","src":"2088:608:1","statements":[{"nodeType":"YulAssignment","src":"2098:90:1","value":{"arguments":[{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"2180:6:1"}],"functionName":{"name":"array_allocation_size_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulIdentifier","src":"2123:56:1"},"nodeType":"YulFunctionCall","src":"2123:64:1"}],"functionName":{"name":"allocate_memory","nodeType":"YulIdentifier","src":"2107:15:1"},"nodeType":"YulFunctionCall","src":"2107:81:1"},"variableNames":[{"name":"array","nodeType":"YulIdentifier","src":"2098:5:1"}]},{"nodeType":"YulVariableDeclaration","src":"2197:16:1","value":{"name":"array","nodeType":"YulIdentifier","src":"2208:5:1"},"variables":[{"name":"dst","nodeType":"YulTypedName","src":"2201:3:1","type":""}]},{"expression":{"arguments":[{"name":"array","nodeType":"YulIdentifier","src":"2230:5:1"},{"name":"length","nodeType":"YulIdentifier","src":"2237:6:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2223:6:1"},"nodeType":"YulFunctionCall","src":"2223:21:1"},"nodeType":"YulExpressionStatement","src":"2223:21:1"},{"nodeType":"YulAssignment","src":"2253:23:1","value":{"arguments":[{"name":"array","nodeType":"YulIdentifier","src":"2264:5:1"},{"kind":"number","nodeType":"YulLiteral","src":"2271:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2260:3:1"},"nodeType":"YulFunctionCall","src":"2260:16:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"2253:3:1"}]},{"nodeType":"YulVariableDeclaration","src":"2286:44:1","value":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"2304:6:1"},{"arguments":[{"name":"length","nodeType":"YulIdentifier","src":"2316:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"2324:4:1","type":"","value":"0x20"}],"functionName":{"name":"mul","nodeType":"YulIdentifier","src":"2312:3:1"},"nodeType":"YulFunctionCall","src":"2312:17:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2300:3:1"},"nodeType":"YulFunctionCall","src":"2300:30:1"},"variables":[{"name":"srcEnd","nodeType":"YulTypedName","src":"2290:6:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"2358:103:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef","nodeType":"YulIdentifier","src":"2372:77:1"},"nodeType":"YulFunctionCall","src":"2372:79:1"},"nodeType":"YulExpressionStatement","src":"2372:79:1"}]},"condition":{"arguments":[{"name":"srcEnd","nodeType":"YulIdentifier","src":"2345:6:1"},{"name":"end","nodeType":"YulIdentifier","src":"2353:3:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"2342:2:1"},"nodeType":"YulFunctionCall","src":"2342:15:1"},"nodeType":"YulIf","src":"2339:122:1"},{"body":{"nodeType":"YulBlock","src":"2546:144:1","statements":[{"nodeType":"YulVariableDeclaration","src":"2561:21:1","value":{"name":"src","nodeType":"YulIdentifier","src":"2579:3:1"},"variables":[{"name":"elementPos","nodeType":"YulTypedName","src":"2565:10:1","type":""}]},{"expression":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"2603:3:1"},{"arguments":[{"name":"elementPos","nodeType":"YulIdentifier","src":"2629:10:1"},{"name":"end","nodeType":"YulIdentifier","src":"2641:3:1"}],"functionName":{"name":"abi_decode_t_uint256","nodeType":"YulIdentifier","src":"2608:20:1"},"nodeType":"YulFunctionCall","src":"2608:37:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"2596:6:1"},"nodeType":"YulFunctionCall","src":"2596:50:1"},"nodeType":"YulExpressionStatement","src":"2596:50:1"},{"nodeType":"YulAssignment","src":"2659:21:1","value":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"2670:3:1"},{"kind":"number","nodeType":"YulLiteral","src":"2675:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2666:3:1"},"nodeType":"YulFunctionCall","src":"2666:14:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"2659:3:1"}]}]},"condition":{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"2499:3:1"},{"name":"srcEnd","nodeType":"YulIdentifier","src":"2504:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"2496:2:1"},"nodeType":"YulFunctionCall","src":"2496:15:1"},"nodeType":"YulForLoop","post":{"nodeType":"YulBlock","src":"2512:25:1","statements":[{"nodeType":"YulAssignment","src":"2514:21:1","value":{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"2525:3:1"},{"kind":"number","nodeType":"YulLiteral","src":"2530:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2521:3:1"},"nodeType":"YulFunctionCall","src":"2521:14:1"},"variableNames":[{"name":"src","nodeType":"YulIdentifier","src":"2514:3:1"}]}]},"pre":{"nodeType":"YulBlock","src":"2474:21:1","statements":[{"nodeType":"YulVariableDeclaration","src":"2476:17:1","value":{"name":"offset","nodeType":"YulIdentifier","src":"2487:6:1"},"variables":[{"name":"src","nodeType":"YulTypedName","src":"2480:3:1","type":""}]}]},"src":"2470:220:1"}]},"name":"abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"offset","nodeType":"YulTypedName","src":"2058:6:1","type":""},{"name":"length","nodeType":"YulTypedName","src":"2066:6:1","type":""},{"name":"end","nodeType":"YulTypedName","src":"2074:3:1","type":""}],"returnVariables":[{"name":"array","nodeType":"YulTypedName","src":"2082:5:1","type":""}],"src":"1986:710:1"},{"body":{"nodeType":"YulBlock","src":"2796:293:1","statements":[{"body":{"nodeType":"YulBlock","src":"2845:83:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"revert_error_1b9f4a0a5773e33b91aa01db23bf8c55fce1411167c872835e7fa00a4f17d46d","nodeType":"YulIdentifier","src":"2847:77:1"},"nodeType":"YulFunctionCall","src":"2847:79:1"},"nodeType":"YulExpressionStatement","src":"2847:79:1"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"2824:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"2832:4:1","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"2820:3:1"},"nodeType":"YulFunctionCall","src":"2820:17:1"},{"name":"end","nodeType":"YulIdentifier","src":"2839:3:1"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"2816:3:1"},"nodeType":"YulFunctionCall","src":"2816:27:1"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"2809:6:1"},"nodeType":"YulFunctionCall","src":"2809:35:1"},"nodeType":"YulIf","src":"2806:122:1"},{"nodeType":"YulVariableDeclaration","src":"2937:34:1","value":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"2964:6:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"2951:12:1"},"nodeType":"YulFunctionCall","src":"2951:20:1"},"variables":[{"name":"length","nodeType":"YulTypedName","src":"2941:6:1","type":""}]},{"nodeType":"YulAssignment","src":"2980:103:1","value":{"arguments":[{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"3056:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"3064:4:1","type":"","value":"0x20"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3052:3:1"},"nodeType":"YulFunctionCall","src":"3052:17:1"},{"name":"length","nodeType":"YulIdentifier","src":"3071:6:1"},{"name":"end","nodeType":"YulIdentifier","src":"3079:3:1"}],"functionName":{"name":"abi_decode_available_length_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulIdentifier","src":"2989:62:1"},"nodeType":"YulFunctionCall","src":"2989:94:1"},"variableNames":[{"name":"array","nodeType":"YulIdentifier","src":"2980:5:1"}]}]},"name":"abi_decode_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"offset","nodeType":"YulTypedName","src":"2774:6:1","type":""},{"name":"end","nodeType":"YulTypedName","src":"2782:3:1","type":""}],"returnVariables":[{"name":"array","nodeType":"YulTypedName","src":"2790:5:1","type":""}],"src":"2719:370:1"},{"body":{"nodeType":"YulBlock","src":"3186:448:1","statements":[{"body":{"nodeType":"YulBlock","src":"3232:83:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"revert_error_dbdddcbe895c83990c08b3492a0e83918d802a52331272ac6fdb6a7c4aea3b1b","nodeType":"YulIdentifier","src":"3234:77:1"},"nodeType":"YulFunctionCall","src":"3234:79:1"},"nodeType":"YulExpressionStatement","src":"3234:79:1"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"3207:7:1"},{"name":"headStart","nodeType":"YulIdentifier","src":"3216:9:1"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"3203:3:1"},"nodeType":"YulFunctionCall","src":"3203:23:1"},{"kind":"number","nodeType":"YulLiteral","src":"3228:2:1","type":"","value":"32"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"3199:3:1"},"nodeType":"YulFunctionCall","src":"3199:32:1"},"nodeType":"YulIf","src":"3196:119:1"},{"nodeType":"YulBlock","src":"3325:302:1","statements":[{"nodeType":"YulVariableDeclaration","src":"3340:45:1","value":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3371:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"3382:1:1","type":"","value":"0"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3367:3:1"},"nodeType":"YulFunctionCall","src":"3367:17:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"3354:12:1"},"nodeType":"YulFunctionCall","src":"3354:31:1"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"3344:6:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"3432:83:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"revert_error_c1322bf8034eace5e0b5c7295db60986aa89aae5e0ea0873e4689e076861a5db","nodeType":"YulIdentifier","src":"3434:77:1"},"nodeType":"YulFunctionCall","src":"3434:79:1"},"nodeType":"YulExpressionStatement","src":"3434:79:1"}]},"condition":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"3404:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"3412:18:1","type":"","value":"0xffffffffffffffff"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"3401:2:1"},"nodeType":"YulFunctionCall","src":"3401:30:1"},"nodeType":"YulIf","src":"3398:117:1"},{"nodeType":"YulAssignment","src":"3529:88:1","value":{"arguments":[{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3589:9:1"},{"name":"offset","nodeType":"YulIdentifier","src":"3600:6:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3585:3:1"},"nodeType":"YulFunctionCall","src":"3585:22:1"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"3609:7:1"}],"functionName":{"name":"abi_decode_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulIdentifier","src":"3539:45:1"},"nodeType":"YulFunctionCall","src":"3539:78:1"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"3529:6:1"}]}]}]},"name":"abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"3156:9:1","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"3167:7:1","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"3179:6:1","type":""}],"src":"3095:539:1"},{"body":{"nodeType":"YulBlock","src":"3705:53:1","statements":[{"expression":{"arguments":[{"name":"pos","nodeType":"YulIdentifier","src":"3722:3:1"},{"arguments":[{"name":"value","nodeType":"YulIdentifier","src":"3745:5:1"}],"functionName":{"name":"cleanup_t_uint256","nodeType":"YulIdentifier","src":"3727:17:1"},"nodeType":"YulFunctionCall","src":"3727:24:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"3715:6:1"},"nodeType":"YulFunctionCall","src":"3715:37:1"},"nodeType":"YulExpressionStatement","src":"3715:37:1"}]},"name":"abi_encode_t_uint256_to_t_uint256_fromStack","nodeType":"YulFunctionDefinition","parameters":[{"name":"value","nodeType":"YulTypedName","src":"3693:5:1","type":""},{"name":"pos","nodeType":"YulTypedName","src":"3700:3:1","type":""}],"src":"3640:118:1"},{"body":{"nodeType":"YulBlock","src":"3862:124:1","statements":[{"nodeType":"YulAssignment","src":"3872:26:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3884:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"3895:2:1","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3880:3:1"},"nodeType":"YulFunctionCall","src":"3880:18:1"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"3872:4:1"}]},{"expression":{"arguments":[{"name":"value0","nodeType":"YulIdentifier","src":"3952:6:1"},{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"3965:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"3976:1:1","type":"","value":"0"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"3961:3:1"},"nodeType":"YulFunctionCall","src":"3961:17:1"}],"functionName":{"name":"abi_encode_t_uint256_to_t_uint256_fromStack","nodeType":"YulIdentifier","src":"3908:43:1"},"nodeType":"YulFunctionCall","src":"3908:71:1"},"nodeType":"YulExpressionStatement","src":"3908:71:1"}]},"name":"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"3834:9:1","type":""},{"name":"value0","nodeType":"YulTypedName","src":"3846:6:1","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"3857:4:1","type":""}],"src":"3764:222:1"}]},"contents":"{ function allocate_unbounded() -> memPtr { memPtr := mload(64) @@ -74,18 +74,17 @@ mstore(array, length) dst := add(array, 0x20) - let src := offset - if gt(add(src, mul(length, 0x20)), end) { + let srcEnd := add(offset, mul(length, 0x20)) + if gt(srcEnd, end) { revert_error_81385d8c0b31fffe14be1da910c8bd3a80be4cfa248e04f42ec0faea3132a8ef() } - for { let i := 0 } lt(i, length) { i := add(i, 1) } + for { let src := offset } lt(src, srcEnd) { src := add(src, 0x20) } { let elementPos := src mstore(dst, abi_decode_t_uint256(elementPos, end)) dst := add(dst, 0x20) - src := add(src, 0x20) } } diff --git a/test/cmdlineTests/standard_optimizer_generatedSources/output.json b/test/cmdlineTests/standard_optimizer_generatedSources/output.json index fba776458..940450827 100644 --- a/test/cmdlineTests/standard_optimizer_generatedSources/output.json +++ b/test/cmdlineTests/standard_optimizer_generatedSources/output.json @@ -1,4 +1,4 @@ -{"contracts":{"a.sol":{"A":{"evm":{"bytecode":{"generatedSources":[],"object":""},"deployedBytecode":{"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:1456:1","statements":[{"nodeType":"YulBlock","src":"6:3:1","statements":[]},{"body":{"nodeType":"YulBlock","src":"46:95:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"63:1:1","type":"","value":"0"},{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"70:3:1","type":"","value":"224"},{"kind":"number","nodeType":"YulLiteral","src":"75:10:1","type":"","value":"0x4e487b71"}],"functionName":{"name":"shl","nodeType":"YulIdentifier","src":"66:3:1"},"nodeType":"YulFunctionCall","src":"66:20:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"56:6:1"},"nodeType":"YulFunctionCall","src":"56:31:1"},"nodeType":"YulExpressionStatement","src":"56:31:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"103:1:1","type":"","value":"4"},{"kind":"number","nodeType":"YulLiteral","src":"106:4:1","type":"","value":"0x41"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"96:6:1"},"nodeType":"YulFunctionCall","src":"96:15:1"},"nodeType":"YulExpressionStatement","src":"96:15:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"127:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"130:4:1","type":"","value":"0x24"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"120:6:1"},"nodeType":"YulFunctionCall","src":"120:15:1"},"nodeType":"YulExpressionStatement","src":"120:15:1"}]},"name":"panic_error_0x41","nodeType":"YulFunctionDefinition","src":"14:127:1"},{"body":{"nodeType":"YulBlock","src":"241:1031:1","statements":[{"nodeType":"YulVariableDeclaration","src":"251:12:1","value":{"kind":"number","nodeType":"YulLiteral","src":"261:2:1","type":"","value":"32"},"variables":[{"name":"_1","nodeType":"YulTypedName","src":"255:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"308:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"317:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"320:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"310:6:1"},"nodeType":"YulFunctionCall","src":"310:12:1"},"nodeType":"YulExpressionStatement","src":"310:12:1"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"283:7:1"},{"name":"headStart","nodeType":"YulIdentifier","src":"292:9:1"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"279:3:1"},"nodeType":"YulFunctionCall","src":"279:23:1"},{"name":"_1","nodeType":"YulIdentifier","src":"304:2:1"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"275:3:1"},"nodeType":"YulFunctionCall","src":"275:32:1"},"nodeType":"YulIf","src":"272:52:1"},{"nodeType":"YulVariableDeclaration","src":"333:37:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"360:9:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"347:12:1"},"nodeType":"YulFunctionCall","src":"347:23:1"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"337:6:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"379:28:1","value":{"kind":"number","nodeType":"YulLiteral","src":"389:18:1","type":"","value":"0xffffffffffffffff"},"variables":[{"name":"_2","nodeType":"YulTypedName","src":"383:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"434:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"443:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"446:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"436:6:1"},"nodeType":"YulFunctionCall","src":"436:12:1"},"nodeType":"YulExpressionStatement","src":"436:12:1"}]},"condition":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"422:6:1"},{"name":"_2","nodeType":"YulIdentifier","src":"430:2:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"419:2:1"},"nodeType":"YulFunctionCall","src":"419:14:1"},"nodeType":"YulIf","src":"416:34:1"},{"nodeType":"YulVariableDeclaration","src":"459:32:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"473:9:1"},{"name":"offset","nodeType":"YulIdentifier","src":"484:6:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"469:3:1"},"nodeType":"YulFunctionCall","src":"469:22:1"},"variables":[{"name":"_3","nodeType":"YulTypedName","src":"463:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"539:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"548:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"551:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"541:6:1"},"nodeType":"YulFunctionCall","src":"541:12:1"},"nodeType":"YulExpressionStatement","src":"541:12:1"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"518:2:1"},{"kind":"number","nodeType":"YulLiteral","src":"522:4:1","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"514:3:1"},"nodeType":"YulFunctionCall","src":"514:13:1"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"529:7:1"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"510:3:1"},"nodeType":"YulFunctionCall","src":"510:27:1"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"503:6:1"},"nodeType":"YulFunctionCall","src":"503:35:1"},"nodeType":"YulIf","src":"500:55:1"},{"nodeType":"YulVariableDeclaration","src":"564:26:1","value":{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"587:2:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"574:12:1"},"nodeType":"YulFunctionCall","src":"574:16:1"},"variables":[{"name":"_4","nodeType":"YulTypedName","src":"568:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"613:22:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"615:16:1"},"nodeType":"YulFunctionCall","src":"615:18:1"},"nodeType":"YulExpressionStatement","src":"615:18:1"}]},"condition":{"arguments":[{"name":"_4","nodeType":"YulIdentifier","src":"605:2:1"},{"name":"_2","nodeType":"YulIdentifier","src":"609:2:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"602:2:1"},"nodeType":"YulFunctionCall","src":"602:10:1"},"nodeType":"YulIf","src":"599:36:1"},{"nodeType":"YulVariableDeclaration","src":"644:20:1","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"658:1:1","type":"","value":"5"},{"name":"_4","nodeType":"YulIdentifier","src":"661:2:1"}],"functionName":{"name":"shl","nodeType":"YulIdentifier","src":"654:3:1"},"nodeType":"YulFunctionCall","src":"654:10:1"},"variables":[{"name":"_5","nodeType":"YulTypedName","src":"648:2:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"673:23:1","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"693:2:1","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"687:5:1"},"nodeType":"YulFunctionCall","src":"687:9:1"},"variables":[{"name":"memPtr","nodeType":"YulTypedName","src":"677:6:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"705:56:1","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"727:6:1"},{"arguments":[{"arguments":[{"name":"_5","nodeType":"YulIdentifier","src":"743:2:1"},{"kind":"number","nodeType":"YulLiteral","src":"747:2:1","type":"","value":"63"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"739:3:1"},"nodeType":"YulFunctionCall","src":"739:11:1"},{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"756:2:1","type":"","value":"31"}],"functionName":{"name":"not","nodeType":"YulIdentifier","src":"752:3:1"},"nodeType":"YulFunctionCall","src":"752:7:1"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"735:3:1"},"nodeType":"YulFunctionCall","src":"735:25:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"723:3:1"},"nodeType":"YulFunctionCall","src":"723:38:1"},"variables":[{"name":"newFreePtr","nodeType":"YulTypedName","src":"709:10:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"820:22:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"822:16:1"},"nodeType":"YulFunctionCall","src":"822:18:1"},"nodeType":"YulExpressionStatement","src":"822:18:1"}]},"condition":{"arguments":[{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"779:10:1"},{"name":"_2","nodeType":"YulIdentifier","src":"791:2:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"776:2:1"},"nodeType":"YulFunctionCall","src":"776:18:1"},{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"799:10:1"},{"name":"memPtr","nodeType":"YulIdentifier","src":"811:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"796:2:1"},"nodeType":"YulFunctionCall","src":"796:22:1"}],"functionName":{"name":"or","nodeType":"YulIdentifier","src":"773:2:1"},"nodeType":"YulFunctionCall","src":"773:46:1"},"nodeType":"YulIf","src":"770:72:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"858:2:1","type":"","value":"64"},{"name":"newFreePtr","nodeType":"YulIdentifier","src":"862:10:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"851:6:1"},"nodeType":"YulFunctionCall","src":"851:22:1"},"nodeType":"YulExpressionStatement","src":"851:22:1"},{"nodeType":"YulVariableDeclaration","src":"882:17:1","value":{"name":"memPtr","nodeType":"YulIdentifier","src":"893:6:1"},"variables":[{"name":"dst","nodeType":"YulTypedName","src":"886:3:1","type":""}]},{"expression":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"915:6:1"},{"name":"_4","nodeType":"YulIdentifier","src":"923:2:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"908:6:1"},"nodeType":"YulFunctionCall","src":"908:18:1"},"nodeType":"YulExpressionStatement","src":"908:18:1"},{"nodeType":"YulAssignment","src":"935:22:1","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"946:6:1"},{"name":"_1","nodeType":"YulIdentifier","src":"954:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"942:3:1"},"nodeType":"YulFunctionCall","src":"942:15:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"935:3:1"}]},{"nodeType":"YulVariableDeclaration","src":"966:22:1","value":{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"981:2:1"},{"name":"_1","nodeType":"YulIdentifier","src":"985:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"977:3:1"},"nodeType":"YulFunctionCall","src":"977:11:1"},"variables":[{"name":"src","nodeType":"YulTypedName","src":"970:3:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"1034:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1043:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1046:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"1036:6:1"},"nodeType":"YulFunctionCall","src":"1036:12:1"},"nodeType":"YulExpressionStatement","src":"1036:12:1"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"1011:2:1"},{"name":"_5","nodeType":"YulIdentifier","src":"1015:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1007:3:1"},"nodeType":"YulFunctionCall","src":"1007:11:1"},{"name":"_1","nodeType":"YulIdentifier","src":"1020:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1003:3:1"},"nodeType":"YulFunctionCall","src":"1003:20:1"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"1025:7:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"1000:2:1"},"nodeType":"YulFunctionCall","src":"1000:33:1"},"nodeType":"YulIf","src":"997:53:1"},{"nodeType":"YulVariableDeclaration","src":"1059:10:1","value":{"kind":"number","nodeType":"YulLiteral","src":"1068:1:1","type":"","value":"0"},"variables":[{"name":"i","nodeType":"YulTypedName","src":"1063:1:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"1123:118:1","statements":[{"expression":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"1144:3:1"},{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"1162:3:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"1149:12:1"},"nodeType":"YulFunctionCall","src":"1149:17:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1137:6:1"},"nodeType":"YulFunctionCall","src":"1137:30:1"},"nodeType":"YulExpressionStatement","src":"1137:30:1"},{"nodeType":"YulAssignment","src":"1180:19:1","value":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"1191:3:1"},{"name":"_1","nodeType":"YulIdentifier","src":"1196:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1187:3:1"},"nodeType":"YulFunctionCall","src":"1187:12:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"1180:3:1"}]},{"nodeType":"YulAssignment","src":"1212:19:1","value":{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"1223:3:1"},{"name":"_1","nodeType":"YulIdentifier","src":"1228:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1219:3:1"},"nodeType":"YulFunctionCall","src":"1219:12:1"},"variableNames":[{"name":"src","nodeType":"YulIdentifier","src":"1212:3:1"}]}]},"condition":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"1089:1:1"},{"name":"_4","nodeType":"YulIdentifier","src":"1092:2:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"1086:2:1"},"nodeType":"YulFunctionCall","src":"1086:9:1"},"nodeType":"YulForLoop","post":{"nodeType":"YulBlock","src":"1096:18:1","statements":[{"nodeType":"YulAssignment","src":"1098:14:1","value":{"arguments":[{"name":"i","nodeType":"YulIdentifier","src":"1107:1:1"},{"kind":"number","nodeType":"YulLiteral","src":"1110:1:1","type":"","value":"1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1103:3:1"},"nodeType":"YulFunctionCall","src":"1103:9:1"},"variableNames":[{"name":"i","nodeType":"YulIdentifier","src":"1098:1:1"}]}]},"pre":{"nodeType":"YulBlock","src":"1082:3:1","statements":[]},"src":"1078:163:1"},{"nodeType":"YulAssignment","src":"1250:16:1","value":{"name":"memPtr","nodeType":"YulIdentifier","src":"1260:6:1"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"1250:6:1"}]}]},"name":"abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"207:9:1","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"218:7:1","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"230:6:1","type":""}],"src":"146:1126:1"},{"body":{"nodeType":"YulBlock","src":"1378:76:1","statements":[{"nodeType":"YulAssignment","src":"1388:26:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1400:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"1411:2:1","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1396:3:1"},"nodeType":"YulFunctionCall","src":"1396:18:1"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"1388:4:1"}]},{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1430:9:1"},{"name":"value0","nodeType":"YulIdentifier","src":"1441:6:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1423:6:1"},"nodeType":"YulFunctionCall","src":"1423:25:1"},"nodeType":"YulExpressionStatement","src":"1423:25:1"}]},"name":"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"1347:9:1","type":""},{"name":"value0","nodeType":"YulTypedName","src":"1358:6:1","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"1369:4:1","type":""}],"src":"1277:177:1"}]},"contents":"{ +{"contracts":{"a.sol":{"A":{"evm":{"bytecode":{"generatedSources":[],"object":""},"deployedBytecode":{"generatedSources":[{"ast":{"nodeType":"YulBlock","src":"0:1445:1","statements":[{"nodeType":"YulBlock","src":"6:3:1","statements":[]},{"body":{"nodeType":"YulBlock","src":"46:95:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"63:1:1","type":"","value":"0"},{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"70:3:1","type":"","value":"224"},{"kind":"number","nodeType":"YulLiteral","src":"75:10:1","type":"","value":"0x4e487b71"}],"functionName":{"name":"shl","nodeType":"YulIdentifier","src":"66:3:1"},"nodeType":"YulFunctionCall","src":"66:20:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"56:6:1"},"nodeType":"YulFunctionCall","src":"56:31:1"},"nodeType":"YulExpressionStatement","src":"56:31:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"103:1:1","type":"","value":"4"},{"kind":"number","nodeType":"YulLiteral","src":"106:4:1","type":"","value":"0x41"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"96:6:1"},"nodeType":"YulFunctionCall","src":"96:15:1"},"nodeType":"YulExpressionStatement","src":"96:15:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"127:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"130:4:1","type":"","value":"0x24"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"120:6:1"},"nodeType":"YulFunctionCall","src":"120:15:1"},"nodeType":"YulExpressionStatement","src":"120:15:1"}]},"name":"panic_error_0x41","nodeType":"YulFunctionDefinition","src":"14:127:1"},{"body":{"nodeType":"YulBlock","src":"241:1020:1","statements":[{"nodeType":"YulVariableDeclaration","src":"251:12:1","value":{"kind":"number","nodeType":"YulLiteral","src":"261:2:1","type":"","value":"32"},"variables":[{"name":"_1","nodeType":"YulTypedName","src":"255:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"308:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"317:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"320:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"310:6:1"},"nodeType":"YulFunctionCall","src":"310:12:1"},"nodeType":"YulExpressionStatement","src":"310:12:1"}]},"condition":{"arguments":[{"arguments":[{"name":"dataEnd","nodeType":"YulIdentifier","src":"283:7:1"},{"name":"headStart","nodeType":"YulIdentifier","src":"292:9:1"}],"functionName":{"name":"sub","nodeType":"YulIdentifier","src":"279:3:1"},"nodeType":"YulFunctionCall","src":"279:23:1"},{"name":"_1","nodeType":"YulIdentifier","src":"304:2:1"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"275:3:1"},"nodeType":"YulFunctionCall","src":"275:32:1"},"nodeType":"YulIf","src":"272:52:1"},{"nodeType":"YulVariableDeclaration","src":"333:37:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"360:9:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"347:12:1"},"nodeType":"YulFunctionCall","src":"347:23:1"},"variables":[{"name":"offset","nodeType":"YulTypedName","src":"337:6:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"379:28:1","value":{"kind":"number","nodeType":"YulLiteral","src":"389:18:1","type":"","value":"0xffffffffffffffff"},"variables":[{"name":"_2","nodeType":"YulTypedName","src":"383:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"434:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"443:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"446:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"436:6:1"},"nodeType":"YulFunctionCall","src":"436:12:1"},"nodeType":"YulExpressionStatement","src":"436:12:1"}]},"condition":{"arguments":[{"name":"offset","nodeType":"YulIdentifier","src":"422:6:1"},{"name":"_2","nodeType":"YulIdentifier","src":"430:2:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"419:2:1"},"nodeType":"YulFunctionCall","src":"419:14:1"},"nodeType":"YulIf","src":"416:34:1"},{"nodeType":"YulVariableDeclaration","src":"459:32:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"473:9:1"},{"name":"offset","nodeType":"YulIdentifier","src":"484:6:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"469:3:1"},"nodeType":"YulFunctionCall","src":"469:22:1"},"variables":[{"name":"_3","nodeType":"YulTypedName","src":"463:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"539:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"548:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"551:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"541:6:1"},"nodeType":"YulFunctionCall","src":"541:12:1"},"nodeType":"YulExpressionStatement","src":"541:12:1"}]},"condition":{"arguments":[{"arguments":[{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"518:2:1"},{"kind":"number","nodeType":"YulLiteral","src":"522:4:1","type":"","value":"0x1f"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"514:3:1"},"nodeType":"YulFunctionCall","src":"514:13:1"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"529:7:1"}],"functionName":{"name":"slt","nodeType":"YulIdentifier","src":"510:3:1"},"nodeType":"YulFunctionCall","src":"510:27:1"}],"functionName":{"name":"iszero","nodeType":"YulIdentifier","src":"503:6:1"},"nodeType":"YulFunctionCall","src":"503:35:1"},"nodeType":"YulIf","src":"500:55:1"},{"nodeType":"YulVariableDeclaration","src":"564:26:1","value":{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"587:2:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"574:12:1"},"nodeType":"YulFunctionCall","src":"574:16:1"},"variables":[{"name":"_4","nodeType":"YulTypedName","src":"568:2:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"613:22:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"615:16:1"},"nodeType":"YulFunctionCall","src":"615:18:1"},"nodeType":"YulExpressionStatement","src":"615:18:1"}]},"condition":{"arguments":[{"name":"_4","nodeType":"YulIdentifier","src":"605:2:1"},{"name":"_2","nodeType":"YulIdentifier","src":"609:2:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"602:2:1"},"nodeType":"YulFunctionCall","src":"602:10:1"},"nodeType":"YulIf","src":"599:36:1"},{"nodeType":"YulVariableDeclaration","src":"644:20:1","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"658:1:1","type":"","value":"5"},{"name":"_4","nodeType":"YulIdentifier","src":"661:2:1"}],"functionName":{"name":"shl","nodeType":"YulIdentifier","src":"654:3:1"},"nodeType":"YulFunctionCall","src":"654:10:1"},"variables":[{"name":"_5","nodeType":"YulTypedName","src":"648:2:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"673:23:1","value":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"693:2:1","type":"","value":"64"}],"functionName":{"name":"mload","nodeType":"YulIdentifier","src":"687:5:1"},"nodeType":"YulFunctionCall","src":"687:9:1"},"variables":[{"name":"memPtr","nodeType":"YulTypedName","src":"677:6:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"705:56:1","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"727:6:1"},{"arguments":[{"arguments":[{"name":"_5","nodeType":"YulIdentifier","src":"743:2:1"},{"kind":"number","nodeType":"YulLiteral","src":"747:2:1","type":"","value":"63"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"739:3:1"},"nodeType":"YulFunctionCall","src":"739:11:1"},{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"756:2:1","type":"","value":"31"}],"functionName":{"name":"not","nodeType":"YulIdentifier","src":"752:3:1"},"nodeType":"YulFunctionCall","src":"752:7:1"}],"functionName":{"name":"and","nodeType":"YulIdentifier","src":"735:3:1"},"nodeType":"YulFunctionCall","src":"735:25:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"723:3:1"},"nodeType":"YulFunctionCall","src":"723:38:1"},"variables":[{"name":"newFreePtr","nodeType":"YulTypedName","src":"709:10:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"820:22:1","statements":[{"expression":{"arguments":[],"functionName":{"name":"panic_error_0x41","nodeType":"YulIdentifier","src":"822:16:1"},"nodeType":"YulFunctionCall","src":"822:18:1"},"nodeType":"YulExpressionStatement","src":"822:18:1"}]},"condition":{"arguments":[{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"779:10:1"},{"name":"_2","nodeType":"YulIdentifier","src":"791:2:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"776:2:1"},"nodeType":"YulFunctionCall","src":"776:18:1"},{"arguments":[{"name":"newFreePtr","nodeType":"YulIdentifier","src":"799:10:1"},{"name":"memPtr","nodeType":"YulIdentifier","src":"811:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"796:2:1"},"nodeType":"YulFunctionCall","src":"796:22:1"}],"functionName":{"name":"or","nodeType":"YulIdentifier","src":"773:2:1"},"nodeType":"YulFunctionCall","src":"773:46:1"},"nodeType":"YulIf","src":"770:72:1"},{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"858:2:1","type":"","value":"64"},{"name":"newFreePtr","nodeType":"YulIdentifier","src":"862:10:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"851:6:1"},"nodeType":"YulFunctionCall","src":"851:22:1"},"nodeType":"YulExpressionStatement","src":"851:22:1"},{"nodeType":"YulVariableDeclaration","src":"882:17:1","value":{"name":"memPtr","nodeType":"YulIdentifier","src":"893:6:1"},"variables":[{"name":"dst","nodeType":"YulTypedName","src":"886:3:1","type":""}]},{"expression":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"915:6:1"},{"name":"_4","nodeType":"YulIdentifier","src":"923:2:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"908:6:1"},"nodeType":"YulFunctionCall","src":"908:18:1"},"nodeType":"YulExpressionStatement","src":"908:18:1"},{"nodeType":"YulAssignment","src":"935:22:1","value":{"arguments":[{"name":"memPtr","nodeType":"YulIdentifier","src":"946:6:1"},{"name":"_1","nodeType":"YulIdentifier","src":"954:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"942:3:1"},"nodeType":"YulFunctionCall","src":"942:15:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"935:3:1"}]},{"nodeType":"YulVariableDeclaration","src":"966:34:1","value":{"arguments":[{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"988:2:1"},{"name":"_5","nodeType":"YulIdentifier","src":"992:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"984:3:1"},"nodeType":"YulFunctionCall","src":"984:11:1"},{"name":"_1","nodeType":"YulIdentifier","src":"997:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"980:3:1"},"nodeType":"YulFunctionCall","src":"980:20:1"},"variables":[{"name":"srcEnd","nodeType":"YulTypedName","src":"970:6:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"1032:16:1","statements":[{"expression":{"arguments":[{"kind":"number","nodeType":"YulLiteral","src":"1041:1:1","type":"","value":"0"},{"kind":"number","nodeType":"YulLiteral","src":"1044:1:1","type":"","value":"0"}],"functionName":{"name":"revert","nodeType":"YulIdentifier","src":"1034:6:1"},"nodeType":"YulFunctionCall","src":"1034:12:1"},"nodeType":"YulExpressionStatement","src":"1034:12:1"}]},"condition":{"arguments":[{"name":"srcEnd","nodeType":"YulIdentifier","src":"1015:6:1"},{"name":"dataEnd","nodeType":"YulIdentifier","src":"1023:7:1"}],"functionName":{"name":"gt","nodeType":"YulIdentifier","src":"1012:2:1"},"nodeType":"YulFunctionCall","src":"1012:19:1"},"nodeType":"YulIf","src":"1009:39:1"},{"nodeType":"YulVariableDeclaration","src":"1057:22:1","value":{"arguments":[{"name":"_3","nodeType":"YulIdentifier","src":"1072:2:1"},{"name":"_1","nodeType":"YulIdentifier","src":"1076:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1068:3:1"},"nodeType":"YulFunctionCall","src":"1068:11:1"},"variables":[{"name":"src","nodeType":"YulTypedName","src":"1061:3:1","type":""}]},{"body":{"nodeType":"YulBlock","src":"1144:86:1","statements":[{"expression":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"1165:3:1"},{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"1183:3:1"}],"functionName":{"name":"calldataload","nodeType":"YulIdentifier","src":"1170:12:1"},"nodeType":"YulFunctionCall","src":"1170:17:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1158:6:1"},"nodeType":"YulFunctionCall","src":"1158:30:1"},"nodeType":"YulExpressionStatement","src":"1158:30:1"},{"nodeType":"YulAssignment","src":"1201:19:1","value":{"arguments":[{"name":"dst","nodeType":"YulIdentifier","src":"1212:3:1"},{"name":"_1","nodeType":"YulIdentifier","src":"1217:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1208:3:1"},"nodeType":"YulFunctionCall","src":"1208:12:1"},"variableNames":[{"name":"dst","nodeType":"YulIdentifier","src":"1201:3:1"}]}]},"condition":{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"1099:3:1"},{"name":"srcEnd","nodeType":"YulIdentifier","src":"1104:6:1"}],"functionName":{"name":"lt","nodeType":"YulIdentifier","src":"1096:2:1"},"nodeType":"YulFunctionCall","src":"1096:15:1"},"nodeType":"YulForLoop","post":{"nodeType":"YulBlock","src":"1112:23:1","statements":[{"nodeType":"YulAssignment","src":"1114:19:1","value":{"arguments":[{"name":"src","nodeType":"YulIdentifier","src":"1125:3:1"},{"name":"_1","nodeType":"YulIdentifier","src":"1130:2:1"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1121:3:1"},"nodeType":"YulFunctionCall","src":"1121:12:1"},"variableNames":[{"name":"src","nodeType":"YulIdentifier","src":"1114:3:1"}]}]},"pre":{"nodeType":"YulBlock","src":"1092:3:1","statements":[]},"src":"1088:142:1"},{"nodeType":"YulAssignment","src":"1239:16:1","value":{"name":"memPtr","nodeType":"YulIdentifier","src":"1249:6:1"},"variableNames":[{"name":"value0","nodeType":"YulIdentifier","src":"1239:6:1"}]}]},"name":"abi_decode_tuple_t_array$_t_uint256_$dyn_memory_ptr","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"207:9:1","type":""},{"name":"dataEnd","nodeType":"YulTypedName","src":"218:7:1","type":""}],"returnVariables":[{"name":"value0","nodeType":"YulTypedName","src":"230:6:1","type":""}],"src":"146:1115:1"},{"body":{"nodeType":"YulBlock","src":"1367:76:1","statements":[{"nodeType":"YulAssignment","src":"1377:26:1","value":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1389:9:1"},{"kind":"number","nodeType":"YulLiteral","src":"1400:2:1","type":"","value":"32"}],"functionName":{"name":"add","nodeType":"YulIdentifier","src":"1385:3:1"},"nodeType":"YulFunctionCall","src":"1385:18:1"},"variableNames":[{"name":"tail","nodeType":"YulIdentifier","src":"1377:4:1"}]},{"expression":{"arguments":[{"name":"headStart","nodeType":"YulIdentifier","src":"1419:9:1"},{"name":"value0","nodeType":"YulIdentifier","src":"1430:6:1"}],"functionName":{"name":"mstore","nodeType":"YulIdentifier","src":"1412:6:1"},"nodeType":"YulFunctionCall","src":"1412:25:1"},"nodeType":"YulExpressionStatement","src":"1412:25:1"}]},"name":"abi_encode_tuple_t_uint256__to_t_uint256__fromStack_reversed","nodeType":"YulFunctionDefinition","parameters":[{"name":"headStart","nodeType":"YulTypedName","src":"1336:9:1","type":""},{"name":"value0","nodeType":"YulTypedName","src":"1347:6:1","type":""}],"returnVariables":[{"name":"tail","nodeType":"YulTypedName","src":"1358:4:1","type":""}],"src":"1266:177:1"}]},"contents":"{ { } function panic_error_0x41() { @@ -25,14 +25,13 @@ let dst := memPtr mstore(memPtr, _4) dst := add(memPtr, _1) + let srcEnd := add(add(_3, _5), _1) + if gt(srcEnd, dataEnd) { revert(0, 0) } let src := add(_3, _1) - if gt(add(add(_3, _5), _1), dataEnd) { revert(0, 0) } - let i := 0 - for { } lt(i, _4) { i := add(i, 1) } + for { } lt(src, srcEnd) { src := add(src, _1) } { mstore(dst, calldataload(src)) dst := add(dst, _1) - src := add(src, _1) } value0 := memPtr } diff --git a/test/libsolidity/gasTests/abiv2.sol b/test/libsolidity/gasTests/abiv2.sol index 8d84e0a29..2dbe334b3 100644 --- a/test/libsolidity/gasTests/abiv2.sol +++ b/test/libsolidity/gasTests/abiv2.sol @@ -14,9 +14,9 @@ contract C { } // ---- // creation: -// codeDepositCost: 1259800 -// executionCost: 1308 -// totalCost: 1261108 +// codeDepositCost: 1243000 +// executionCost: 1295 +// totalCost: 1244295 // external: // a(): 2430 // b(uint256): infinite diff --git a/test/libsolidity/gasTests/abiv2_optimised.sol b/test/libsolidity/gasTests/abiv2_optimised.sol index 093acf49a..ca344afd0 100644 --- a/test/libsolidity/gasTests/abiv2_optimised.sol +++ b/test/libsolidity/gasTests/abiv2_optimised.sol @@ -17,9 +17,9 @@ contract C { // optimize-yul: true // ---- // creation: -// codeDepositCost: 680600 -// executionCost: 715 -// totalCost: 681315 +// codeDepositCost: 660800 +// executionCost: 696 +// totalCost: 661496 // external: // a(): 2285 // b(uint256): 4652 diff --git a/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol index 91d8447a9..4161cb7d8 100644 --- a/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol +++ b/test/libsolidity/semanticTests/abiEncoderV1/abi_decode_v2_storage.sol @@ -24,6 +24,6 @@ contract C { // compileViaYul: also // ---- // f() -> 0x20, 0x8, 0x40, 0x3, 0x9, 0xa, 0xb -// gas irOptimized: 203556 -// gas legacy: 206126 -// gas legacyOptimized: 203105 +// gas irOptimized: 203522 +// gas legacy: 206084 +// gas legacyOptimized: 203068 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol index a216efec1..bf57dbe6f 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/abi_encode_v2_in_function_inherited_in_v1_contract.sol @@ -32,6 +32,6 @@ contract C is B { // compileViaYul: also // ---- // test() -> 77 -// gas irOptimized: 121752 -// gas legacy: 155249 -// gas legacyOptimized: 111743 +// gas irOptimized: 121699 +// gas legacy: 155221 +// gas legacyOptimized: 111678 diff --git a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array.sol b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array.sol index 95070c2fb..2841ef243 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/calldata_array.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/calldata_array.sol @@ -21,6 +21,6 @@ contract C { // f(uint256[][1]): 32, 32, 0 -> true // f(uint256[][1]): 32, 32, 1, 42 -> true // f(uint256[][1]): 32, 32, 8, 421, 422, 423, 424, 425, 426, 427, 428 -> true -// gas irOptimized: 177719 +// gas irOptimized: 177581 // gas legacy: 141900 // gas legacyOptimized: 121788 diff --git a/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol b/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol index 7a9eae673..596e76a66 100644 --- a/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol +++ b/test/libsolidity/semanticTests/array/arrays_complex_from_and_to_storage.sol @@ -14,9 +14,9 @@ contract Test { // compileViaYul: also // ---- // set(uint24[3][]): 0x20, 0x06, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12 -> 0x06 -// gas irOptimized: 189567 -// gas legacy: 211485 -// gas legacyOptimized: 206394 +// gas irOptimized: 189239 +// gas legacy: 211149 +// gas legacyOptimized: 206054 // data(uint256,uint256): 0x02, 0x02 -> 0x09 // data(uint256,uint256): 0x05, 0x01 -> 0x11 // data(uint256,uint256): 0x06, 0x00 -> FAILURE diff --git a/test/libsolidity/semanticTests/array/copying/arrays_from_and_to_storage.sol b/test/libsolidity/semanticTests/array/copying/arrays_from_and_to_storage.sol index 388a0d168..cee56c23b 100644 --- a/test/libsolidity/semanticTests/array/copying/arrays_from_and_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/arrays_from_and_to_storage.sol @@ -12,9 +12,9 @@ contract Test { // compileViaYul: also // ---- // set(uint24[]): 0x20, 18, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 -> 18 -// gas irOptimized: 100066 -// gas legacy: 103815 -// gas legacyOptimized: 101614 +// gas irOptimized: 99873 +// gas legacy: 103563 +// gas legacyOptimized: 101397 // data(uint256): 7 -> 8 // data(uint256): 15 -> 16 // data(uint256): 18 -> FAILURE diff --git a/test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol b/test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol index a4c808b57..ab9ae1640 100644 --- a/test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol +++ b/test/libsolidity/semanticTests/array/fixed_arrays_as_return_type.sol @@ -21,6 +21,6 @@ contract B { // compileViaYul: also // ---- // f() -> 2, 3, 4, 5, 6, 1000, 1001, 1002, 1003, 1004 -// gas irOptimized: 121038 -// gas legacy: 235339 -// gas legacyOptimized: 133299 +// gas irOptimized: 120848 +// gas legacy: 235199 +// gas legacyOptimized: 133119 diff --git a/test/libsolidity/semanticTests/array/function_array_cross_calls.sol b/test/libsolidity/semanticTests/array/function_array_cross_calls.sol index b8b4d4e00..6545dc900 100644 --- a/test/libsolidity/semanticTests/array/function_array_cross_calls.sol +++ b/test/libsolidity/semanticTests/array/function_array_cross_calls.sol @@ -45,6 +45,6 @@ contract C { // compileViaYul: also // ---- // test() -> 5, 6, 7 -// gas irOptimized: 299965 -// gas legacy: 463662 -// gas legacyOptimized: 296513 +// gas irOptimized: 297690 +// gas legacy: 462080 +// gas legacyOptimized: 294938 diff --git a/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol b/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol index bc0afd393..c55ce061d 100644 --- a/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol +++ b/test/libsolidity/semanticTests/constructor/arrays_in_constructors.sol @@ -26,6 +26,6 @@ contract Creator { // compileViaYul: also // ---- // f(uint256,address[]): 7, 0x40, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 -> 7, 8 -// gas irOptimized: 459815 -// gas legacy: 592626 -// gas legacyOptimized: 450224 +// gas irOptimized: 458295 +// gas legacy: 590939 +// gas legacyOptimized: 448582 diff --git a/test/libsolidity/semanticTests/inheritance/inherited_function_calldata_memory_interface.sol b/test/libsolidity/semanticTests/inheritance/inherited_function_calldata_memory_interface.sol index c78627cbc..b4f03446c 100644 --- a/test/libsolidity/semanticTests/inheritance/inherited_function_calldata_memory_interface.sol +++ b/test/libsolidity/semanticTests/inheritance/inherited_function_calldata_memory_interface.sol @@ -25,6 +25,6 @@ contract B { // compileViaYul: also // ---- // g() -> 42 -// gas irOptimized: 110833 -// gas legacy: 186609 -// gas legacyOptimized: 116151 +// gas irOptimized: 105784 +// gas legacy: 185181 +// gas legacyOptimized: 114726 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol b/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol index 3dc662947..98b73acc2 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol @@ -55,9 +55,9 @@ contract C { // gas legacy: 125037 // gas legacyOptimized: 122605 // test_g() -> true -// gas irOptimized: 95969 -// gas legacy: 100656 -// gas legacyOptimized: 96057 +// gas irOptimized: 95908 +// gas legacy: 100586 +// gas legacyOptimized: 95996 // addresses(uint256): 0 -> 0x18 // addresses(uint256): 1 -> 0x19 // addresses(uint256): 3 -> 0x1b From b731957e65a64cf087d050edb0dc4345459b2bcf Mon Sep 17 00:00:00 2001 From: Leo Alt Date: Tue, 7 Sep 2021 00:14:28 +0200 Subject: [PATCH 095/232] Fix BMCs constraints on internal functions --- Changelog.md | 1 + libsolidity/formal/BMC.cpp | 3 +- .../smtCheckerTests/functions/payable_1.sol | 15 ++++++++ .../smtCheckerTests/functions/payable_2.sol | 27 ++++++++++++++ .../special/block_vars_bmc_internal.sol | 37 +++++++++++++++++++ .../special/block_vars_chc_internal.sol | 32 ++++++++++++++++ .../smtCheckerTests/special/many_internal.sol | 30 +++++++++++++++ .../special/msg_vars_bmc_internal.sol | 32 ++++++++++++++++ .../special/msg_vars_chc_internal.sol | 28 ++++++++++++++ .../special/tx_vars_bmc_internal.sol | 22 +++++++++++ .../special/tx_vars_chc_internal.sol | 20 ++++++++++ 11 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 test/libsolidity/smtCheckerTests/functions/payable_1.sol create mode 100644 test/libsolidity/smtCheckerTests/functions/payable_2.sol create mode 100644 test/libsolidity/smtCheckerTests/special/block_vars_bmc_internal.sol create mode 100644 test/libsolidity/smtCheckerTests/special/block_vars_chc_internal.sol create mode 100644 test/libsolidity/smtCheckerTests/special/many_internal.sol create mode 100644 test/libsolidity/smtCheckerTests/special/msg_vars_bmc_internal.sol create mode 100644 test/libsolidity/smtCheckerTests/special/msg_vars_chc_internal.sol create mode 100644 test/libsolidity/smtCheckerTests/special/tx_vars_bmc_internal.sol create mode 100644 test/libsolidity/smtCheckerTests/special/tx_vars_chc_internal.sol diff --git a/Changelog.md b/Changelog.md index bd62be0ce..b4cd2187c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -25,6 +25,7 @@ Bugfixes: * SMTChecker: Fix false negative caused by ``push`` on storage array references returned by internal functions. * SMTChecker: Fix false positive in external calls from constructors. * SMTChecker: Fix internal error on some multi-source uses of ``abi.*``, cryptographic functions and constants. + * SMTChecker: Fix BMC's constraints regarding internal functions. * Type Checker: Disallow modifier declarations and definitions in interfaces. * Yul Optimizer: Fix a crash in LoadResolver, when ``keccak256`` has particular non-identifier arguments. diff --git a/libsolidity/formal/BMC.cpp b/libsolidity/formal/BMC.cpp index dc7547433..24c6a5231 100644 --- a/libsolidity/formal/BMC.cpp +++ b/libsolidity/formal/BMC.cpp @@ -188,7 +188,8 @@ bool BMC::visit(FunctionDefinition const& _function) { reset(); initFunction(_function); - m_context.addAssertion(state().txTypeConstraints() && state().txFunctionConstraints(_function)); + if (_function.isConstructor() || _function.isPublic()) + m_context.addAssertion(state().txTypeConstraints() && state().txFunctionConstraints(_function)); resetStateVariables(); } diff --git a/test/libsolidity/smtCheckerTests/functions/payable_1.sol b/test/libsolidity/smtCheckerTests/functions/payable_1.sol new file mode 100644 index 000000000..c17691fa5 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/functions/payable_1.sol @@ -0,0 +1,15 @@ +contract C { + function g() external { + f(); + } + + function h() external payable { + f(); + } + + function f() internal { + require(msg.value == 0); + } +} +// ==== +// SMTEngine: all diff --git a/test/libsolidity/smtCheckerTests/functions/payable_2.sol b/test/libsolidity/smtCheckerTests/functions/payable_2.sol new file mode 100644 index 000000000..6411eae62 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/functions/payable_2.sol @@ -0,0 +1,27 @@ +contract C { + function g() external { + f(); + h(); + i(); + } + + function g2() external payable { + i(); + } + + function f() internal { + require(msg.value == 0); + } + + function h() internal { + assert(msg.value == 0); // should hold + } + + function i() internal { + assert(msg.value == 0); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (261-283): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.g2(){ value: 35 }\n C.i(){ value: 35 } -- internal call diff --git a/test/libsolidity/smtCheckerTests/special/block_vars_bmc_internal.sol b/test/libsolidity/smtCheckerTests/special/block_vars_bmc_internal.sol new file mode 100644 index 000000000..51a330d8e --- /dev/null +++ b/test/libsolidity/smtCheckerTests/special/block_vars_bmc_internal.sol @@ -0,0 +1,37 @@ +contract C { + address coin; + uint dif; + uint gas; + uint number; + uint timestamp; + function f() public { + coin = block.coinbase; + dif = block.difficulty; + gas = block.gaslimit; + number = block.number; + timestamp = block.timestamp; + + g(); + } + function g() internal view { + assert(uint160(coin) >= 0); // should hold + assert(dif >= 0); // should hold + assert(gas >= 0); // should hold + assert(number >= 0); // should hold + assert(timestamp >= 0); // should hold + + assert(coin == block.coinbase); // should fail with BMC + assert(dif == block.difficulty); // should fail with BMC + assert(gas == block.gaslimit); // should fail with BMC + assert(number == block.number); // should fail with BMC + assert(timestamp == block.timestamp); // should fail with BMC + } +} +// ==== +// SMTEngine: bmc +// ---- +// Warning 4661: (473-503): BMC: Assertion violation happens here. +// Warning 4661: (531-562): BMC: Assertion violation happens here. +// Warning 4661: (590-619): BMC: Assertion violation happens here. +// Warning 4661: (647-677): BMC: Assertion violation happens here. +// Warning 4661: (705-741): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/special/block_vars_chc_internal.sol b/test/libsolidity/smtCheckerTests/special/block_vars_chc_internal.sol new file mode 100644 index 000000000..ca4873d67 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/special/block_vars_chc_internal.sol @@ -0,0 +1,32 @@ +contract C { + address coin; + uint dif; + uint gas; + uint number; + uint timestamp; + function f() public { + coin = block.coinbase; + dif = block.difficulty; + gas = block.gaslimit; + number = block.number; + timestamp = block.timestamp; + + g(); + } + function g() internal view { + assert(uint160(coin) >= 0); // should hold + assert(dif >= 0); // should hold + assert(gas >= 0); // should hold + assert(number >= 0); // should hold + assert(timestamp >= 0); // should hold + + assert(coin == block.coinbase); // should hold with CHC + assert(dif == block.difficulty); // should hold with CHC + assert(gas == block.gaslimit); // should hold with CHC + assert(number == block.number); // should hold with CHC + assert(timestamp == block.timestamp); // should hold with CHC + } +} +// ==== +// SMTEngine: chc +// ---- diff --git a/test/libsolidity/smtCheckerTests/special/many_internal.sol b/test/libsolidity/smtCheckerTests/special/many_internal.sol new file mode 100644 index 000000000..eb68fd9ac --- /dev/null +++ b/test/libsolidity/smtCheckerTests/special/many_internal.sol @@ -0,0 +1,30 @@ +contract C +{ + function f() public payable { + g(); + } + function g() internal { + assert(msg.sender == block.coinbase); + assert(block.difficulty == block.gaslimit); + assert(block.number == block.timestamp); + assert(tx.gasprice == msg.value); + assert(tx.origin == msg.sender); + uint x = block.number; + unchecked { x += 2; } + assert(x > block.number); + assert(block.timestamp > 10); + assert(gasleft() > 100); + } +} +// ==== +// SMTEngine: all +// SMTIgnoreCex: yes +// ---- +// Warning 6328: (81-117): CHC: Assertion violation happens here. +// Warning 6328: (121-163): CHC: Assertion violation happens here. +// Warning 6328: (167-206): CHC: Assertion violation happens here. +// Warning 6328: (210-242): CHC: Assertion violation happens here. +// Warning 6328: (246-277): CHC: Assertion violation happens here. +// Warning 6328: (330-354): CHC: Assertion violation happens here. +// Warning 6328: (358-386): CHC: Assertion violation happens here. +// Warning 6328: (390-413): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/special/msg_vars_bmc_internal.sol b/test/libsolidity/smtCheckerTests/special/msg_vars_bmc_internal.sol new file mode 100644 index 000000000..100284dd7 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/special/msg_vars_bmc_internal.sol @@ -0,0 +1,32 @@ +contract C { + bytes data; + address sender; + bytes4 sig; + uint value; + function f() public payable { + data = msg.data; + sender = msg.sender; + sig = msg.sig; + value = msg.value; + + g(); + } + function g() internal view { + assert(data.length >= 0); // should hold + assert(uint160(sender) >= 0); // should hold + assert(uint32(sig) >= 0); // should hold + assert(value >= 0); // should hold + + assert(data.length == msg.data.length); // should fail with BMC + assert(sender == msg.sender); // should fail with BMC + assert(sig == msg.sig); // should fail with BMC + assert(value == msg.value); // should fail with BMC + } +} +// ==== +// SMTEngine: bmc +// ---- +// Warning 4661: (394-432): BMC: Assertion violation happens here. +// Warning 4661: (460-488): BMC: Assertion violation happens here. +// Warning 4661: (516-538): BMC: Assertion violation happens here. +// Warning 4661: (566-592): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/special/msg_vars_chc_internal.sol b/test/libsolidity/smtCheckerTests/special/msg_vars_chc_internal.sol new file mode 100644 index 000000000..e8190ce3a --- /dev/null +++ b/test/libsolidity/smtCheckerTests/special/msg_vars_chc_internal.sol @@ -0,0 +1,28 @@ +contract C { + bytes data; + address sender; + bytes4 sig; + uint value; + function f() public payable { + data = msg.data; + sender = msg.sender; + sig = msg.sig; + value = msg.value; + + g(); + } + function g() internal view { + assert(data.length >= 0); // should hold + assert(uint160(sender) >= 0); // should hold + assert(uint32(sig) >= 0); // should hold + assert(value >= 0); // should hold + + assert(data.length == msg.data.length); // should hold with CHC + assert(sender == msg.sender); // should hold with CHC + assert(sig == msg.sig); // should hold with CHC + assert(value == msg.value); // should hold with CHC + } +} +// ==== +// SMTEngine: chc +// ---- diff --git a/test/libsolidity/smtCheckerTests/special/tx_vars_bmc_internal.sol b/test/libsolidity/smtCheckerTests/special/tx_vars_bmc_internal.sol new file mode 100644 index 000000000..137864a33 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/special/tx_vars_bmc_internal.sol @@ -0,0 +1,22 @@ +contract C { + uint gas; + address origin; + function f() public { + gas = tx.gasprice; + origin = tx.origin; + + g(); + } + function g() internal view { + assert(gas >= 0); // should hold + assert(uint160(origin) >= 0); // should hold + + assert(gas == tx.gasprice); // should fail with BMC + assert(origin == tx.origin); // should fail with BMC + } +} +// ==== +// SMTEngine: bmc +// ---- +// Warning 4661: (233-259): BMC: Assertion violation happens here. +// Warning 4661: (287-314): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/special/tx_vars_chc_internal.sol b/test/libsolidity/smtCheckerTests/special/tx_vars_chc_internal.sol new file mode 100644 index 000000000..53ce010aa --- /dev/null +++ b/test/libsolidity/smtCheckerTests/special/tx_vars_chc_internal.sol @@ -0,0 +1,20 @@ +contract C { + uint gas; + address origin; + function f() public { + gas = tx.gasprice; + origin = tx.origin; + + g(); + } + function g() internal view { + assert(gas >= 0); // should hold + assert(uint160(origin) >= 0); // should hold + + assert(gas == tx.gasprice); // should hold with CHC + assert(origin == tx.origin); // should hold with CHC + } +} +// ==== +// SMTEngine: chc +// ---- From 67eed76aacca9fd54c02575c2da26da60e8238fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 15 Sep 2021 15:30:40 +0200 Subject: [PATCH 096/232] cmdlineTests.sh: Fix running only tests matching patterns given on the command line --- test/cmdlineTests.sh | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 4d72040a6..458db10a7 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -37,9 +37,11 @@ source "${REPO_ROOT}/scripts/common.sh" # shellcheck source=scripts/common_cmdline.sh source "${REPO_ROOT}/scripts/common_cmdline.sh" +pushd "${REPO_ROOT}/test/cmdlineTests" > /dev/null autoupdate=false no_smt=false declare -a selected_tests +declare -a patterns_with_no_matches while [[ $# -gt 0 ]] do case "$1" in @@ -52,12 +54,26 @@ do shift ;; *) - selected_tests+=("$1") + matching_tests=$(find . -mindepth 1 -maxdepth 1 -type d -name "$1" | cut --characters 3- | sort) + + if [[ $matching_tests == "" ]]; then + patterns_with_no_matches+=("$1") + printWarning "No tests matching pattern '$1' found." + else + # shellcheck disable=SC2206 # We do not support test names containing spaces. + selected_tests+=($matching_tests) + fi + shift ;; esac done +if (( ${#selected_tests[@]} == 0 && ${#patterns_with_no_matches[@]} == 0 )); then + selected_tests=(*) +fi +popd > /dev/null + case "$OSTYPE" in msys) SOLC="${SOLIDITY_BUILD_DIR}/solc/Release/solc.exe" @@ -320,7 +336,6 @@ test_solc_behaviour "${0}" "ctx:=/some/remapping/target" "" "" 1 "" "Invalid rem printTask "Running general commandline tests..." ( cd "$REPO_ROOT"/test/cmdlineTests/ - (( ${#selected_tests[@]} > 0 )) || selected_tests=(*) for tdir in "${selected_tests[@]}" do if ! [[ -d $tdir ]]; then From b077ef46e2f7ad69e456ea1ab0fc4deb358774eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 15 Sep 2021 15:31:20 +0200 Subject: [PATCH 097/232] cmdlineTests.sh: More descriptive message about used binary path --- test/cmdlineTests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 458db10a7..d6c335067 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -85,7 +85,7 @@ case "$OSTYPE" in SOLC="${SOLIDITY_BUILD_DIR}/solc/solc" ;; esac -echo "${SOLC}" +echo "Using solc binary at ${SOLC}" INTERACTIVE=true if ! tty -s || [ "$CI" ] From 48e16ceb88d0568e46c3d02ec636aaf437019d53 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Wed, 15 Sep 2021 11:59:13 +0200 Subject: [PATCH 098/232] Changing the UserDefinedValueType::toString to `userdefined ` --- libsolidity/ast/Types.cpp | 2 +- .../ABIJson/user_defined_value_type.sol | 20 +++++++++---------- .../ASTJSON/userDefinedValueType.json | 16 +++++++-------- .../explicit_conversions_err.sol | 16 +++++++-------- .../implicit_conversion_err.sol | 12 +++++------ .../wrap_unwrap_assign_err.sol | 4 ++-- .../wrap_unwrap_calls_err.sol | 2 +- ...rap_unwrap_via_contract_name_different.sol | 2 +- 8 files changed, 37 insertions(+), 37 deletions(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 467d48c5b..67e8e5168 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2555,7 +2555,7 @@ bool UserDefinedValueType::operator==(Type const& _other) const string UserDefinedValueType::toString(bool /* _short */) const { - return "user defined type " + *definition().annotation().canonicalName; + return *definition().annotation().canonicalName; } vector> UserDefinedValueType::makeStackItems() const diff --git a/test/libsolidity/ABIJson/user_defined_value_type.sol b/test/libsolidity/ABIJson/user_defined_value_type.sol index b5e565dbb..3bd034e6a 100644 --- a/test/libsolidity/ABIJson/user_defined_value_type.sol +++ b/test/libsolidity/ABIJson/user_defined_value_type.sol @@ -36,7 +36,7 @@ contract C { // "outputs": // [ // { -// "internalType": "user defined type C.MyAddress", +// "internalType": "C.MyAddress", // "name": "", // "type": "address" // } @@ -50,7 +50,7 @@ contract C { // "outputs": // [ // { -// "internalType": "user defined type MyByte1", +// "internalType": "MyByte1", // "name": "", // "type": "bytes1" // } @@ -64,7 +64,7 @@ contract C { // "outputs": // [ // { -// "internalType": "user defined type C.MyBytes32", +// "internalType": "C.MyBytes32", // "name": "", // "type": "bytes32" // } @@ -78,7 +78,7 @@ contract C { // "outputs": // [ // { -// "internalType": "user defined type MyInt", +// "internalType": "MyInt", // "name": "", // "type": "int256" // } @@ -92,7 +92,7 @@ contract C { // "outputs": // [ // { -// "internalType": "user defined type C.MyUInt8", +// "internalType": "C.MyUInt8", // "name": "", // "type": "uint8" // } @@ -104,7 +104,7 @@ contract C { // "inputs": // [ // { -// "internalType": "user defined type C.MyAddress", +// "internalType": "C.MyAddress", // "name": "a", // "type": "address" // } @@ -118,7 +118,7 @@ contract C { // "inputs": // [ // { -// "internalType": "user defined type MyByte1", +// "internalType": "MyByte1", // "name": "a", // "type": "bytes1" // } @@ -132,7 +132,7 @@ contract C { // "inputs": // [ // { -// "internalType": "user defined type C.MyBytes32", +// "internalType": "C.MyBytes32", // "name": "a", // "type": "bytes32" // } @@ -146,7 +146,7 @@ contract C { // "inputs": // [ // { -// "internalType": "user defined type MyInt", +// "internalType": "MyInt", // "name": "a", // "type": "int256" // } @@ -160,7 +160,7 @@ contract C { // "inputs": // [ // { -// "internalType": "user defined type C.MyUInt8", +// "internalType": "C.MyUInt8", // "name": "a", // "type": "uint8" // } diff --git a/test/libsolidity/ASTJSON/userDefinedValueType.json b/test/libsolidity/ASTJSON/userDefinedValueType.json index 4f8dc9306..4cd72c4f8 100644 --- a/test/libsolidity/ASTJSON/userDefinedValueType.json +++ b/test/libsolidity/ASTJSON/userDefinedValueType.json @@ -91,7 +91,7 @@ "typeDescriptions": { "typeIdentifier": "t_userDefinedValueType$_MyAddress_$2", - "typeString": "user defined type MyAddress" + "typeString": "MyAddress" }, "typeName": { @@ -110,7 +110,7 @@ "typeDescriptions": { "typeIdentifier": "t_userDefinedValueType$_MyAddress_$2", - "typeString": "user defined type MyAddress" + "typeString": "MyAddress" } }, "visibility": "internal" @@ -141,7 +141,7 @@ "typeDescriptions": { "typeIdentifier": "t_userDefinedValueType$_MyUInt_$4", - "typeString": "user defined type MyUInt" + "typeString": "MyUInt" }, "typeName": { @@ -160,7 +160,7 @@ "typeDescriptions": { "typeIdentifier": "t_userDefinedValueType$_MyUInt_$4", - "typeString": "user defined type MyUInt" + "typeString": "MyUInt" } }, "visibility": "internal" @@ -269,7 +269,7 @@ "typeDescriptions": { "typeIdentifier": "t_mapping$_t_userDefinedValueType$_MyAddress_$18_$_t_userDefinedValueType$_MyUInt_$20_$", - "typeString": "mapping(user defined type C.MyAddress => user defined type C.MyUInt)" + "typeString": "mapping(C.MyAddress => C.MyUInt)" }, "typeName": { @@ -291,7 +291,7 @@ "typeDescriptions": { "typeIdentifier": "t_userDefinedValueType$_MyAddress_$18", - "typeString": "user defined type C.MyAddress" + "typeString": "C.MyAddress" } }, "nodeType": "Mapping", @@ -299,7 +299,7 @@ "typeDescriptions": { "typeIdentifier": "t_mapping$_t_userDefinedValueType$_MyAddress_$18_$_t_userDefinedValueType$_MyUInt_$20_$", - "typeString": "mapping(user defined type C.MyAddress => user defined type C.MyUInt)" + "typeString": "mapping(C.MyAddress => C.MyUInt)" }, "valueType": { @@ -318,7 +318,7 @@ "typeDescriptions": { "typeIdentifier": "t_userDefinedValueType$_MyUInt_$20", - "typeString": "user defined type C.MyUInt" + "typeString": "C.MyUInt" } } }, diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversions_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversions_err.sol index 876a3e282..24a7a071e 100644 --- a/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversions_err.sol +++ b/test/libsolidity/syntaxTests/userDefinedValueType/explicit_conversions_err.sol @@ -14,11 +14,11 @@ function f() pure { MyUInt.unwrap(AnotherUInt.wrap(10)); } // ---- -// TypeError 9640: (99-109): Explicit type conversion not allowed from "int_const -1" to "user defined type MyUInt". -// TypeError 9640: (115-128): Explicit type conversion not allowed from "int_const -1" to "user defined type MyAddress". -// TypeError 9640: (134-143): Explicit type conversion not allowed from "int_const 5" to "user defined type MyUInt". -// TypeError 9640: (149-170): Explicit type conversion not allowed from "address" to "user defined type MyAddress". -// TypeError 9640: (177-204): Explicit type conversion not allowed from "user defined type MyUInt" to "user defined type AnotherUInt". -// TypeError 9640: (210-238): Explicit type conversion not allowed from "user defined type AnotherUInt" to "user defined type MyUInt". -// TypeError 9553: (263-277): Invalid type for argument in function call. Invalid implicit conversion from user defined type MyUInt to user defined type AnotherUInt requested. -// TypeError 9553: (298-318): Invalid type for argument in function call. Invalid implicit conversion from user defined type AnotherUInt to user defined type MyUInt requested. +// TypeError 9640: (99-109): Explicit type conversion not allowed from "int_const -1" to "MyUInt". +// TypeError 9640: (115-128): Explicit type conversion not allowed from "int_const -1" to "MyAddress". +// TypeError 9640: (134-143): Explicit type conversion not allowed from "int_const 5" to "MyUInt". +// TypeError 9640: (149-170): Explicit type conversion not allowed from "address" to "MyAddress". +// TypeError 9640: (177-204): Explicit type conversion not allowed from "MyUInt" to "AnotherUInt". +// TypeError 9640: (210-238): Explicit type conversion not allowed from "AnotherUInt" to "MyUInt". +// TypeError 9553: (263-277): Invalid type for argument in function call. Invalid implicit conversion from MyUInt to AnotherUInt requested. +// TypeError 9553: (298-318): Invalid type for argument in function call. Invalid implicit conversion from AnotherUInt to MyUInt requested. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/implicit_conversion_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/implicit_conversion_err.sol index ad115051e..3b6179845 100644 --- a/test/libsolidity/syntaxTests/userDefinedValueType/implicit_conversion_err.sol +++ b/test/libsolidity/syntaxTests/userDefinedValueType/implicit_conversion_err.sol @@ -14,9 +14,9 @@ function f(int a) pure returns (int) { return e; } // ---- -// TypeError 9574: (62-73): Type int256 is not implicitly convertible to expected type user defined type MyInt. -// TypeError 9574: (80-89): Type user defined type MyInt is not implicitly convertible to expected type int256. -// TypeError 9574: (96-109): Type user defined type MyInt is not implicitly convertible to expected type address. -// TypeError 9574: (116-127): Type address is not implicitly convertible to expected type user defined type MyInt. -// TypeError 9640: (160-168): Explicit type conversion not allowed from "uint256" to "user defined type MyInt". -// TypeError 6359: (182-183): Return argument type user defined type MyInt is not implicitly convertible to expected type (type of first return variable) int256. +// TypeError 9574: (62-73): Type int256 is not implicitly convertible to expected type MyInt. +// TypeError 9574: (80-89): Type MyInt is not implicitly convertible to expected type int256. +// TypeError 9574: (96-109): Type MyInt is not implicitly convertible to expected type address. +// TypeError 9574: (116-127): Type address is not implicitly convertible to expected type MyInt. +// TypeError 9640: (160-168): Explicit type conversion not allowed from "uint256" to "MyInt". +// TypeError 6359: (182-183): Return argument type MyInt is not implicitly convertible to expected type (type of first return variable) int256. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_assign_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_assign_err.sol index 67ce77331..15bc15fa0 100644 --- a/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_assign_err.sol +++ b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_assign_err.sol @@ -4,5 +4,5 @@ function test() pure { function (int) returns (MyInt) g = MyInt.wrap; } // ---- -// TypeError 9574: (46-93): Type function (user defined type MyInt) pure returns (int256) is not implicitly convertible to expected type function (user defined type MyInt) returns (int256). Special functions can not be converted to function types. -// TypeError 9574: (99-144): Type function (int256) pure returns (user defined type MyInt) is not implicitly convertible to expected type function (int256) returns (user defined type MyInt). Special functions can not be converted to function types. +// TypeError 9574: (46-93): Type function (MyInt) pure returns (int256) is not implicitly convertible to expected type function (MyInt) returns (int256). Special functions can not be converted to function types. +// TypeError 9574: (99-144): Type function (int256) pure returns (MyInt) is not implicitly convertible to expected type function (int256) returns (MyInt). Special functions can not be converted to function types. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_calls_err.sol b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_calls_err.sol index 470a42b0a..d4ee407fd 100644 --- a/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_calls_err.sol +++ b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_calls_err.sol @@ -11,6 +11,6 @@ function f() { // TypeError 6160: (38-57): Wrong argument count for function call: 3 arguments given but expected 1. // TypeError 4974: (63-84): Named argument "test" does not match function declaration. // TypeError 6160: (90-102): Wrong argument count for function call: 0 arguments given but expected 1. -// TypeError 9553: (121-122): Invalid type for argument in function call. Invalid implicit conversion from int_const 5 to user defined type MyInt requested. +// TypeError 9553: (121-122): Invalid type for argument in function call. Invalid implicit conversion from int_const 5 to MyInt requested. // TypeError 4974: (129-152): Named argument "test" does not match function declaration. // TypeError 6160: (158-200): Wrong argument count for function call: 2 arguments given but expected 1. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_via_contract_name_different.sol b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_via_contract_name_different.sol index 64d19c627..334cb9fb0 100644 --- a/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_via_contract_name_different.sol +++ b/test/libsolidity/syntaxTests/userDefinedValueType/wrap_unwrap_via_contract_name_different.sol @@ -5,4 +5,4 @@ contract D C.T x = L.T.wrap(uint(1)); } // ---- -// TypeError 7407: (86-103): Type user defined type L.T is not implicitly convertible to expected type user defined type C.T. +// TypeError 7407: (86-103): Type L.T is not implicitly convertible to expected type C.T. From 15fb427a998314520f80ec56309d10de5ea34165 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Tue, 14 Sep 2021 16:02:42 +0200 Subject: [PATCH 099/232] Added a multisource test for UserDefinedValueTypes and imports Testing if `import {MyType} from "source";` works --- .../userDefinedValueType/multisource.sol | 14 ++++++++++++++ .../userDefinedValueType/multisource_module.sol | 13 +++++++++++++ .../userDefinedValueType/multisource1.sol | 10 ++++++++++ .../userDefinedValueType/multisource2.sol | 10 ++++++++++ .../userDefinedValueType/multisource3.sol | 9 +++++++++ .../userDefinedValueType/multisource4.sol | 9 +++++++++ 6 files changed, 65 insertions(+) create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/multisource.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/multisource_module.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/multisource1.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/multisource2.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/multisource3.sol create mode 100644 test/libsolidity/syntaxTests/userDefinedValueType/multisource4.sol diff --git a/test/libsolidity/semanticTests/userDefinedValueType/multisource.sol b/test/libsolidity/semanticTests/userDefinedValueType/multisource.sol new file mode 100644 index 000000000..67069157c --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/multisource.sol @@ -0,0 +1,14 @@ +==== Source: A ==== +type MyInt is int; +type MyAddress is address; +==== Source: B ==== +import {MyInt, MyAddress as OurAddress} from "A"; +contract A { + function f(int x) external view returns(MyInt) { return MyInt.wrap(x); } + function f(address x) external view returns(OurAddress) { return OurAddress.wrap(x); } +} +// ==== +// compileViaYul: also +// ---- +// f(int256): 5 -> 5 +// f(address): 1 -> 1 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/multisource_module.sol b/test/libsolidity/semanticTests/userDefinedValueType/multisource_module.sol new file mode 100644 index 000000000..2d2833059 --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/multisource_module.sol @@ -0,0 +1,13 @@ +==== Source: s1.sol ==== +type MyInt is int; +==== Source: s2.sol ==== +import "s1.sol" as M; +contract C { + function f(int x) public pure returns (M.MyInt) { return M.MyInt.wrap(x); } + function g(M.MyInt x) public pure returns (int) { return M.MyInt.unwrap(x); } +} +// ==== +// compileViaYul: also +// ---- +// f(int256): 5 -> 5 +// g(int256): 1 -> 1 diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/multisource1.sol b/test/libsolidity/syntaxTests/userDefinedValueType/multisource1.sol new file mode 100644 index 000000000..b6a7b5bcc --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/multisource1.sol @@ -0,0 +1,10 @@ +==== Source: A ==== +type MyInt is int; +type MyAddress is address; +==== Source: B ==== +import {MyAddress as OurAddress} from "A"; +contract A { + function f(int x) external view returns(MyInt) { return MyInt.wrap(x); } +} +// ---- +// DeclarationError 7920: (B:100-105): Identifier not found or not unique. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/multisource2.sol b/test/libsolidity/syntaxTests/userDefinedValueType/multisource2.sol new file mode 100644 index 000000000..a0e7f9ec0 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/multisource2.sol @@ -0,0 +1,10 @@ +==== Source: A ==== +type MyInt is int; +type MyAddress is address; +==== Source: B ==== +import {MyAddress as OurAddress} from "A"; +contract A { + function f(address x) external view returns(MyAddress) { return MyAddress.wrap(x); } +} +// ---- +// DeclarationError 7920: (B:104-113): Identifier not found or not unique. diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/multisource3.sol b/test/libsolidity/syntaxTests/userDefinedValueType/multisource3.sol new file mode 100644 index 000000000..ed2cbde28 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/multisource3.sol @@ -0,0 +1,9 @@ +==== Source: s1.sol ==== +type MyInt is int; +==== Source: s2.sol ==== +import "s1.sol" as M; +contract C { + function f(int x) public pure returns (M.MyInt) { return M.MyInt.wrap(x); } + function g(M.MyInt x) public pure returns (int) { return M.MyInt.unwrap(x); } +} +// ---- diff --git a/test/libsolidity/syntaxTests/userDefinedValueType/multisource4.sol b/test/libsolidity/syntaxTests/userDefinedValueType/multisource4.sol new file mode 100644 index 000000000..92a1e54f1 --- /dev/null +++ b/test/libsolidity/syntaxTests/userDefinedValueType/multisource4.sol @@ -0,0 +1,9 @@ +==== Source: s1.sol ==== +type MyInt is int; +==== Source: s2.sol ==== +import "s1.sol" as M; +contract C { + function f(int x) public pure returns (MyInt) { return MyInt.wrap(x); } +} +// ---- +// DeclarationError 7920: (s2.sol:76-81): Identifier not found or not unique. From 0dc1600fa57f70ebba6077bdb7e03858b36b0f9d Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Thu, 16 Sep 2021 10:14:13 +0200 Subject: [PATCH 100/232] Docker: Tag ossfuzz base clang image --- .../docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz index fcf8a0dc4..48e9839dd 100644 --- a/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz +++ b/scripts/docker/buildpack-deps/Dockerfile.ubuntu1604.clang.ossfuzz @@ -21,8 +21,8 @@ # # (c) 2016-2021 solidity contributors. #------------------------------------------------------------------------------ -FROM gcr.io/oss-fuzz-base/base-clang as base -LABEL version="12" +FROM gcr.io/oss-fuzz-base/base-clang:latest as base +LABEL version="13" ARG DEBIAN_FRONTEND=noninteractive From c81814915c06f6344b1c68ea00841962f7423612 Mon Sep 17 00:00:00 2001 From: Marenz Date: Thu, 2 Sep 2021 15:25:10 +0200 Subject: [PATCH 101/232] Properly detect multiple licenses and validate them. --- Changelog.md | 1 + libsolidity/parsing/Parser.cpp | 38 ++++++++++++------ scripts/test_antlr_grammar.sh | 6 ++- test/libsolidity/Metadata.cpp | 40 +++++-------------- .../syntaxTests/license/license_AND.sol | 3 ++ .../syntaxTests/license/license_OR.sol | 3 ++ .../syntaxTests/license/license_double2.sol | 5 +++ .../syntaxTests/license/license_double3.sol | 5 +++ .../syntaxTests/license/license_double4.sol | 5 +++ .../syntaxTests/license/license_double5.sol | 4 ++ .../license/license_hidden_unicode.sol | 2 +- .../syntaxTests/license/license_unicode.sol | 2 +- 12 files changed, 68 insertions(+), 46 deletions(-) create mode 100644 test/libsolidity/syntaxTests/license/license_AND.sol create mode 100644 test/libsolidity/syntaxTests/license/license_OR.sol create mode 100644 test/libsolidity/syntaxTests/license/license_double2.sol create mode 100644 test/libsolidity/syntaxTests/license/license_double3.sol create mode 100644 test/libsolidity/syntaxTests/license/license_double4.sol create mode 100644 test/libsolidity/syntaxTests/license/license_double5.sol diff --git a/Changelog.md b/Changelog.md index bd62be0ce..25da9ac42 100644 --- a/Changelog.md +++ b/Changelog.md @@ -22,6 +22,7 @@ Bugfixes: * Commandline Interface: Disallow the ``--experimental-via-ir`` option in Standard JSON, Assembler and Linker modes. * Opcode Optimizer: Prevent the optimizer from running multiple times to avoid potential bytecode differences for referenced code. * Name Resolver: Fix that when importing an aliased symbol using ``import {AliasedName} from "a.sol"`` it would use the original name of the symbol and not the aliased one. + * Parser: Properly check for multiple SPDX license identifiers next to each other and validate them. * SMTChecker: Fix false negative caused by ``push`` on storage array references returned by internal functions. * SMTChecker: Fix false positive in external calls from constructors. * SMTChecker: Fix internal error on some multi-source uses of ``abi.*``, cryptographic functions and constants. diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 3f5c975e3..1d16f7828 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -2078,7 +2079,8 @@ bool Parser::variableDeclarationStart() optional Parser::findLicenseString(std::vector> const& _nodes) { // We circumvent the scanner here, because it skips non-docstring comments. - static regex const licenseRegex("SPDX-License-Identifier:\\s*([a-zA-Z0-9 ()+.-]+)"); + static regex const licenseNameRegex("([a-zA-Z0-9 ()+.-]+)"); + static regex const licenseDeclarationRegex("SPDX-License-Identifier:\\s*(.+?)([\n\r]|(\\*/))"); // Search inside all parts of the source not covered by parsed nodes. // This will leave e.g. "global comments". @@ -2093,21 +2095,33 @@ optional Parser::findLicenseString(std::vector> cons sequencesToSearch.emplace_back(source.begin() + node->location().end, source.end()); } - vector matches; + vector licenseNames; for (auto const& [start, end]: sequencesToSearch) { - smatch match; - if (regex_search(start, end, match, licenseRegex)) - { - string license{boost::trim_copy(string(match[1]))}; - if (!license.empty()) - matches.emplace_back(std::move(license)); - } + auto declarationsBegin = std::sregex_iterator(start, end, licenseDeclarationRegex); + auto declarationsEnd = std::sregex_iterator(); + + for (std::sregex_iterator declIt = declarationsBegin; declIt != declarationsEnd; ++declIt) + if (!declIt->empty()) + { + string license = boost::trim_copy(string((*declIt)[1])); + licenseNames.emplace_back(std::move(license)); + } } - if (matches.size() == 1) - return matches.front(); - else if (matches.empty()) + if (licenseNames.size() == 1) + { + string const& license = licenseNames.front(); + if (regex_match(license, licenseNameRegex)) + return license; + else + parserError( + 1114_error, + {-1, -1, m_scanner->currentLocation().sourceName}, + "Invalid SPDX license identifier." + ); + } + else if (licenseNames.empty()) parserWarning( 1878_error, {-1, -1, m_scanner->currentLocation().sourceName}, diff --git a/scripts/test_antlr_grammar.sh b/scripts/test_antlr_grammar.sh index 333cea0df..04c1b08ac 100755 --- a/scripts/test_antlr_grammar.sh +++ b/scripts/test_antlr_grammar.sh @@ -120,7 +120,11 @@ done < <( # a variable declaration. grep -v -E 'revertStatement/non_called.sol' | # Skipping a test with "let basefee := ..." - grep -v -E 'inlineAssembly/basefee_berlin_function.sol' + grep -v -E 'inlineAssembly/basefee_berlin_function.sol' | + # Skipping license error, unrelated to the grammar + grep -v -E 'license/license_double5.sol' | + grep -v -E 'license/license_hidden_unicode.sol' | + grep -v -E 'license/license_unicode.sol' ) YUL_FILES=() diff --git a/test/libsolidity/Metadata.cpp b/test/libsolidity/Metadata.cpp index 8d0b65e4c..d37398637 100644 --- a/test/libsolidity/Metadata.cpp +++ b/test/libsolidity/Metadata.cpp @@ -457,28 +457,6 @@ BOOST_AUTO_TEST_CASE(metadata_license_gpl3_or_apache2) BOOST_CHECK(compileAndCheckLicenseMetadata("C", sourceCode) == "GPL-3.0 OR Apache-2.0"); } -BOOST_AUTO_TEST_CASE(metadata_license_ignored_unicode) -{ - char const* sourceCode = R"( - // SPDX-License-Identifier: ⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒ - pragma solidity >=0.0; - contract C { - } - )"; - BOOST_CHECK(compileAndCheckLicenseMetadata("C", sourceCode) == nullopt); -} - -BOOST_AUTO_TEST_CASE(metadata_license_ignored_stray_unicode) -{ - char const* sourceCode = R"( - // SPDX-License-Identifier: GPL-3.0 ⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒ - pragma solidity >=0.0; - contract C { - } - )"; - BOOST_CHECK(compileAndCheckLicenseMetadata("C", sourceCode) == "GPL-3.0"); -} - BOOST_AUTO_TEST_CASE(metadata_license_bidi_marks) { char const* sourceCode = @@ -570,15 +548,6 @@ BOOST_AUTO_TEST_CASE(metadata_license_natspec_multiline) BOOST_CHECK(compileAndCheckLicenseMetadata("C", sourceCode) == "GPL-3.0"); } -BOOST_AUTO_TEST_CASE(metadata_license_no_whitespace) -{ - char const* sourceCode = R"( - //SPDX-License-Identifier:GPL-3.0 - contract C {} - )"; - BOOST_CHECK(compileAndCheckLicenseMetadata("C", sourceCode) == "GPL-3.0"); -} - BOOST_AUTO_TEST_CASE(metadata_license_no_whitespace_multiline) { char const* sourceCode = R"( @@ -597,6 +566,15 @@ BOOST_AUTO_TEST_CASE(metadata_license_nonempty_line) BOOST_CHECK(compileAndCheckLicenseMetadata("C", sourceCode) == "GPL-3.0"); } +BOOST_AUTO_TEST_CASE(metadata_license_no_whitespace) +{ + char const* sourceCode = R"( + //SPDX-License-Identifier:GPL-3.0 + contract C {} + )"; + BOOST_CHECK(compileAndCheckLicenseMetadata("C", sourceCode) == "GPL-3.0"); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/syntaxTests/license/license_AND.sol b/test/libsolidity/syntaxTests/license/license_AND.sol new file mode 100644 index 000000000..eb996a948 --- /dev/null +++ b/test/libsolidity/syntaxTests/license/license_AND.sol @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: GPL-3.0 AND GPL-2.0 +contract C {} +// ---- diff --git a/test/libsolidity/syntaxTests/license/license_OR.sol b/test/libsolidity/syntaxTests/license/license_OR.sol new file mode 100644 index 000000000..9f36bb416 --- /dev/null +++ b/test/libsolidity/syntaxTests/license/license_OR.sol @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: GPL-3.0 OR GPL-2.0 +contract C {} +// ---- diff --git a/test/libsolidity/syntaxTests/license/license_double2.sol b/test/libsolidity/syntaxTests/license/license_double2.sol new file mode 100644 index 000000000..4c390a3d4 --- /dev/null +++ b/test/libsolidity/syntaxTests/license/license_double2.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-3.0 +// SPDX-License-Identifier: MIT +contract C {} +// ---- +// ParserError 3716: Multiple SPDX license identifiers found in source file. Use "AND" or "OR" to combine multiple licenses. Please see https://spdx.org for more information. diff --git a/test/libsolidity/syntaxTests/license/license_double3.sol b/test/libsolidity/syntaxTests/license/license_double3.sol new file mode 100644 index 000000000..10ade5d9d --- /dev/null +++ b/test/libsolidity/syntaxTests/license/license_double3.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-3.0 +// SPDX-License-Identifier: GPL-3.0 +contract C {} +// ---- +// ParserError 3716: Multiple SPDX license identifiers found in source file. Use "AND" or "OR" to combine multiple licenses. Please see https://spdx.org for more information. diff --git a/test/libsolidity/syntaxTests/license/license_double4.sol b/test/libsolidity/syntaxTests/license/license_double4.sol new file mode 100644 index 000000000..395a458ee --- /dev/null +++ b/test/libsolidity/syntaxTests/license/license_double4.sol @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: GPL-3.0 OR GPL-2.0 +SPDX-License-Identifier: GPL-3.0 OR GPL-2.0 */ +contract C {} +// ---- +// ParserError 3716: Multiple SPDX license identifiers found in source file. Use "AND" or "OR" to combine multiple licenses. Please see https://spdx.org for more information. diff --git a/test/libsolidity/syntaxTests/license/license_double5.sol b/test/libsolidity/syntaxTests/license/license_double5.sol new file mode 100644 index 000000000..efc22186b --- /dev/null +++ b/test/libsolidity/syntaxTests/license/license_double5.sol @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: GPL-3.0 OR GPL-2.0 */ /* SPDX-License-Identifier: GPL-3.0 OR GPL-2.0 */ +contract C {} +// ---- +// ParserError 3716: Multiple SPDX license identifiers found in source file. Use "AND" or "OR" to combine multiple licenses. Please see https://spdx.org for more information. diff --git a/test/libsolidity/syntaxTests/license/license_hidden_unicode.sol b/test/libsolidity/syntaxTests/license/license_hidden_unicode.sol index 5ce155f32..f93ef18c4 100644 --- a/test/libsolidity/syntaxTests/license/license_hidden_unicode.sol +++ b/test/libsolidity/syntaxTests/license/license_hidden_unicode.sol @@ -1,4 +1,4 @@ -// This is parsed as GPL-3.0: // SPDX-License-Identifier: GPL-3.0 ⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒ contract C {} // ---- +// ParserError 1114: Invalid SPDX license identifier. diff --git a/test/libsolidity/syntaxTests/license/license_unicode.sol b/test/libsolidity/syntaxTests/license/license_unicode.sol index 801c6e576..bcf2cdb77 100644 --- a/test/libsolidity/syntaxTests/license/license_unicode.sol +++ b/test/libsolidity/syntaxTests/license/license_unicode.sol @@ -1,4 +1,4 @@ // SPDX-License-Identifier: ⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒ contract C {} // ---- -// Warning 1878: SPDX license identifier not provided in source file. Before publishing, consider adding a comment containing "SPDX-License-Identifier: " to each source file. Use "SPDX-License-Identifier: UNLICENSED" for non-open-source code. Please see https://spdx.org for more information. +// ParserError 1114: Invalid SPDX license identifier. From d708612e277f7e87e9acc1a28647a5f0e59cd0ef Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 15 Sep 2021 15:23:22 +0200 Subject: [PATCH 102/232] Refactor source comment parsing. --- libyul/AsmParser.cpp | 154 +++++++++++++++++++++++-------------------- libyul/AsmParser.h | 13 +++- 2 files changed, 91 insertions(+), 76 deletions(-) diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 53b78aec8..19554a5cf 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -104,7 +104,7 @@ unique_ptr Parser::parseInline(std::shared_ptr const& _scanner) { m_scanner = _scanner; if (m_sourceNames) - fetchSourceLocationFromComment(); + fetchDebugDataFromComment(); return make_unique(parseBlock()); } catch (FatalError const&) @@ -119,99 +119,107 @@ langutil::Token Parser::advance() { auto const token = ParserBase::advance(); if (m_useSourceLocationFrom == UseSourceLocationFrom::Comments) - fetchSourceLocationFromComment(); + fetchDebugDataFromComment(); return token; } -void Parser::fetchSourceLocationFromComment() +void Parser::fetchDebugDataFromComment() { solAssert(m_sourceNames.has_value(), ""); - if (m_scanner->currentCommentLiteral().empty()) - return; - static regex const tagRegex = regex( R"~~((?:^|\s+)(@[a-zA-Z0-9\-_]+)(?:\s+|$))~~", // tag, e.g: @src regex_constants::ECMAScript | regex_constants::optimize ); - static regex const srcTagArgsRegex = regex( - R"~~(^(-1|\d+):(-1|\d+):(-1|\d+)(?:\s+|$))~~" // index and location, e.g.: 1:234:-1 - R"~~(("(?:[^"\\]|\\.)*"?)?)~~", // optional code snippet, e.g.: "string memory s = \"abc\";..." - regex_constants::ECMAScript | regex_constants::optimize - ); - string const commentLiteral = m_scanner->currentCommentLiteral(); - SourceLocation const commentLocation = m_scanner->currentCommentLocation(); - smatch tagMatch; - string::const_iterator position = commentLiteral.begin(); + string_view commentLiteral = m_scanner->currentCommentLiteral(); + match_results match; - while (regex_search(position, commentLiteral.end(), tagMatch, tagRegex)) + langutil::SourceLocation sourceLocation = m_debugDataOverride->location; + + while (regex_search(commentLiteral.cbegin(), commentLiteral.cend(), match, tagRegex)) { - solAssert(tagMatch.size() == 2, ""); - position += tagMatch.position() + tagMatch.length(); + solAssert(match.size() == 2, ""); + commentLiteral = commentLiteral.substr(static_cast(match.position() + match.length())); - if (tagMatch[1] == "@src") + if (match[1] == "@src") { - smatch srcTagArgsMatch; - if (!regex_search(position, commentLiteral.end(), srcTagArgsMatch, srcTagArgsRegex)) - { - m_errorReporter.syntaxError( - 8387_error, - commentLocation, - "Invalid values in source location mapping. Could not parse location specification." - ); - - // If the arguments to @src are malformed, we don't know where they end so we can't continue. - return; - } - - solAssert(srcTagArgsMatch.size() == 5, ""); - position += srcTagArgsMatch.position() + srcTagArgsMatch.length(); - - if (srcTagArgsMatch[4].matched && ( - !boost::algorithm::ends_with(srcTagArgsMatch[4].str(), "\"") || - boost::algorithm::ends_with(srcTagArgsMatch[4].str(), "\\\"") - )) - { - m_errorReporter.syntaxError( - 1544_error, - commentLocation, - "Invalid code snippet in source location mapping. Quote is not terminated." - ); - return; - } - - optional const sourceIndex = toInt(srcTagArgsMatch[1].str()); - optional const start = toInt(srcTagArgsMatch[2].str()); - optional const end = toInt(srcTagArgsMatch[3].str()); - - m_debugDataOverride = DebugData::create(); - if (!sourceIndex.has_value() || !start.has_value() || !end.has_value()) - m_errorReporter.syntaxError( - 6367_error, - commentLocation, - "Invalid value in source location mapping. " - "Expected non-negative integer values or -1 for source index and location." - ); - else if (sourceIndex == -1) - m_debugDataOverride = DebugData::create(SourceLocation{start.value(), end.value(), nullptr}); - else if (!(sourceIndex >= 0 && m_sourceNames->count(static_cast(sourceIndex.value())))) - m_errorReporter.syntaxError( - 2674_error, - commentLocation, - "Invalid source mapping. Source index not defined via @use-src." - ); + if (auto parseResult = parseSrcComment(commentLiteral, m_scanner->currentCommentLocation())) + tie(commentLiteral, sourceLocation) = *parseResult; else - { - shared_ptr sourceName = m_sourceNames->at(static_cast(sourceIndex.value())); - solAssert(sourceName, ""); - m_debugDataOverride = DebugData::create(SourceLocation{start.value(), end.value(), move(sourceName)}); - } + break; } else // Ignore unrecognized tags. continue; } + + m_debugDataOverride = DebugData::create(sourceLocation); +} + +optional> Parser::parseSrcComment( + string_view const _arguments, + langutil::SourceLocation const& _commentLocation +) +{ + static regex const argsRegex = regex( + R"~~(^(-1|\d+):(-1|\d+):(-1|\d+)(?:\s+|$))~~" // index and location, e.g.: 1:234:-1 + R"~~(("(?:[^"\\]|\\.)*"?)?)~~", // optional code snippet, e.g.: "string memory s = \"abc\";..." + regex_constants::ECMAScript | regex_constants::optimize + ); + match_results match; + if (!regex_search(_arguments.cbegin(), _arguments.cend(), match, argsRegex)) + { + m_errorReporter.syntaxError( + 8387_error, + _commentLocation, + "Invalid values in source location mapping. Could not parse location specification." + ); + return nullopt; + } + + solAssert(match.size() == 5, ""); + string_view tail = _arguments.substr(static_cast(match.position() + match.length())); + + if (match[4].matched && ( + !boost::algorithm::ends_with(match[4].str(), "\"") || + boost::algorithm::ends_with(match[4].str(), "\\\"") + )) + { + m_errorReporter.syntaxError( + 1544_error, + _commentLocation, + "Invalid code snippet in source location mapping. Quote is not terminated." + ); + return {{tail, SourceLocation{}}}; + } + + optional const sourceIndex = toInt(match[1].str()); + optional const start = toInt(match[2].str()); + optional const end = toInt(match[3].str()); + + if (!sourceIndex.has_value() || !start.has_value() || !end.has_value()) + m_errorReporter.syntaxError( + 6367_error, + _commentLocation, + "Invalid value in source location mapping. " + "Expected non-negative integer values or -1 for source index and location." + ); + else if (sourceIndex == -1) + return {{tail, SourceLocation{start.value(), end.value(), nullptr}}}; + else if (!(sourceIndex >= 0 && m_sourceNames->count(static_cast(sourceIndex.value())))) + m_errorReporter.syntaxError( + 2674_error, + _commentLocation, + "Invalid source mapping. Source index not defined via @use-src." + ); + else + { + shared_ptr sourceName = m_sourceNames->at(static_cast(sourceIndex.value())); + solAssert(sourceName, ""); + return {{tail, SourceLocation{start.value(), end.value(), move(sourceName)}}}; + } + return {{tail, SourceLocation{}}}; } Block Parser::parseBlock() diff --git a/libyul/AsmParser.h b/libyul/AsmParser.h index da6eb7226..57b91e1de 100644 --- a/libyul/AsmParser.h +++ b/libyul/AsmParser.h @@ -35,6 +35,7 @@ #include #include #include +#include namespace solidity::yul { @@ -68,8 +69,8 @@ public: } {} - /// Constructs a Yul parser that is using the source locations - /// from the comments (via @src). + /// Constructs a Yul parser that is using the debug data + /// from the comments (via @src and other tags). explicit Parser( langutil::ErrorReporter& _errorReporter, Dialect const& _dialect, @@ -105,7 +106,13 @@ protected: langutil::Token advance() override; - void fetchSourceLocationFromComment(); + void fetchDebugDataFromComment(); + + std::optional> + parseSrcComment( + std::string_view _arguments, + langutil::SourceLocation const& _commentLocation + ); /// Creates a DebugData object with the correct source location set. std::shared_ptr createDebugData() const; From a1bea368cb406afe0f94cb584e533f2379415cdb Mon Sep 17 00:00:00 2001 From: Leo Alt Date: Mon, 13 Sep 2021 13:57:14 +0200 Subject: [PATCH 103/232] [SMTChecker] Support constants via modules --- Changelog.md | 1 + libsolidity/formal/SMTEncoder.cpp | 66 ++++++++++++------- libsolidity/formal/SMTEncoder.h | 2 + .../file_level/file_level_call_via_module.sol | 2 - .../smtCheckerTests/file_level/import.sol | 1 - .../file_level/module_constants_1.sol | 26 ++++++++ .../module_constants_functions_1.sol | 46 +++++++++++++ .../same_constants_different_files.sol | 5 +- .../imports/import_as_module_2.sol | 2 - 9 files changed, 118 insertions(+), 33 deletions(-) create mode 100644 test/libsolidity/smtCheckerTests/file_level/module_constants_1.sol create mode 100644 test/libsolidity/smtCheckerTests/file_level/module_constants_functions_1.sol diff --git a/Changelog.md b/Changelog.md index 79f88b658..516f20b33 100644 --- a/Changelog.md +++ b/Changelog.md @@ -13,6 +13,7 @@ Compiler Features: * SMTChecker: Support low level ``call`` as external calls to unknown code. * SMTChecker: Add constraints to better correlate ``address(this).balance`` and ``msg.value``. * SMTChecker: Support the ``value`` option for external function calls. + * SMTChecker: Support constants via modules. Bugfixes: diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index fdf5db5ca..e0c440919 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -870,21 +870,7 @@ void SMTEncoder::endVisit(Identifier const& _identifier) if (auto decl = identifierToVariable(_identifier)) { if (decl->isConstant()) - { - if (RationalNumberType const* rationalType = isConstant(_identifier)) - { - if (rationalType->isNegative()) - defineExpr(_identifier, smtutil::Expression(u2s(rationalType->literalValue(nullptr)))); - else - defineExpr(_identifier, smtutil::Expression(rationalType->literalValue(nullptr))); - } - else - { - solAssert(decl->value(), ""); - decl->value()->accept(*this); - defineExpr(_identifier, expr(*decl->value(), _identifier.annotation().type)); - } - } + defineExpr(_identifier, constantExpr(_identifier, *decl)); else defineExpr(_identifier, currentValue(*decl)); } @@ -900,6 +886,9 @@ void SMTEncoder::endVisit(Identifier const& _identifier) // Ignore type identifiers else if (dynamic_cast(_identifier.annotation().type)) return; + // Ignore module identifiers + else if (dynamic_cast(_identifier.annotation().type)) + return; // Ignore the builtin abi, it is handled in FunctionCall. // TODO: ignore MagicType in general (abi, block, msg, tx, type) else if (auto magicType = dynamic_cast(_identifier.annotation().type); magicType && magicType->kind() == MagicType::Kind::ABI) @@ -1287,11 +1276,13 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess) createExpr(_memberAccess); - auto const& exprType = _memberAccess.expression().annotation().type; + Expression const* memberExpr = innermostTuple(_memberAccess.expression()); + + auto const& exprType = memberExpr->annotation().type; solAssert(exprType, ""); if (exprType->category() == Type::Category::Magic) { - if (auto const* identifier = dynamic_cast(&_memberAccess.expression())) + if (auto const* identifier = dynamic_cast(memberExpr)) { auto const& name = identifier->name(); solAssert(name == "block" || name == "msg" || name == "tx", ""); @@ -1328,14 +1319,14 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess) } else if (smt::isNonRecursiveStruct(*exprType)) { - _memberAccess.expression().accept(*this); - auto const& symbStruct = dynamic_pointer_cast(m_context.expression(_memberAccess.expression())); + memberExpr->accept(*this); + auto const& symbStruct = dynamic_pointer_cast(m_context.expression(*memberExpr)); defineExpr(_memberAccess, symbStruct->member(_memberAccess.memberName())); return false; } else if (exprType->category() == Type::Category::TypeType) { - auto const* decl = expressionToDeclaration(_memberAccess.expression()); + auto const* decl = expressionToDeclaration(*memberExpr); if (dynamic_cast(decl)) { auto enumType = dynamic_cast(accessType); @@ -1355,10 +1346,10 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess) } else if (exprType->category() == Type::Category::Address) { - _memberAccess.expression().accept(*this); + memberExpr->accept(*this); if (_memberAccess.memberName() == "balance") { - defineExpr(_memberAccess, state().balance(expr(_memberAccess.expression()))); + defineExpr(_memberAccess, state().balance(expr(*memberExpr))); setSymbolicUnknownValue(*m_context.expression(_memberAccess), m_context); m_uninterpretedTerms.insert(&_memberAccess); return false; @@ -1366,10 +1357,10 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess) } else if (exprType->category() == Type::Category::Array) { - _memberAccess.expression().accept(*this); + memberExpr->accept(*this); if (_memberAccess.memberName() == "length") { - auto symbArray = dynamic_pointer_cast(m_context.expression(_memberAccess.expression())); + auto symbArray = dynamic_pointer_cast(m_context.expression(*memberExpr)); solAssert(symbArray, ""); defineExpr(_memberAccess, symbArray->length()); m_uninterpretedTerms.insert(&_memberAccess); @@ -1391,6 +1382,15 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess) defineExpr(_memberAccess, functionType->externalIdentifier()); return false; } + else if (exprType->category() == Type::Category::Module) + { + if (auto const* var = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) + { + solAssert(var->isConstant(), ""); + defineExpr(_memberAccess, constantExpr(_memberAccess, *var)); + return false; + } + } else m_errorReporter.warning( 7650_error, @@ -3050,6 +3050,24 @@ vector SMTEncoder::symbolicArguments(FunctionCall const& _f return args; } +smtutil::Expression SMTEncoder::constantExpr(Expression const& _expr, VariableDeclaration const& _var) +{ + if (RationalNumberType const* rationalType = isConstant(_expr)) + { + if (rationalType->isNegative()) + return smtutil::Expression(u2s(rationalType->literalValue(nullptr))); + else + return smtutil::Expression(rationalType->literalValue(nullptr)); + } + else + { + solAssert(_var.value(), ""); + _var.value()->accept(*this); + return expr(*_var.value(), _expr.annotation().type); + } + solAssert(false, ""); +} + void SMTEncoder::collectFreeFunctions(set const& _sources) { for (auto source: _sources) diff --git a/libsolidity/formal/SMTEncoder.h b/libsolidity/formal/SMTEncoder.h index a567a0fbf..4852c6831 100644 --- a/libsolidity/formal/SMTEncoder.h +++ b/libsolidity/formal/SMTEncoder.h @@ -393,6 +393,8 @@ protected: /// type conversion. std::vector symbolicArguments(FunctionCall const& _funCall, ContractDefinition const* _contextContract); + smtutil::Expression constantExpr(Expression const& _expr, VariableDeclaration const& _var); + /// Traverses all source units available collecting free functions /// and internal library functions in m_freeFunctions. void collectFreeFunctions(std::set const& _sources); diff --git a/test/libsolidity/smtCheckerTests/file_level/file_level_call_via_module.sol b/test/libsolidity/smtCheckerTests/file_level/file_level_call_via_module.sol index 2392db620..9cea98f6b 100644 --- a/test/libsolidity/smtCheckerTests/file_level/file_level_call_via_module.sol +++ b/test/libsolidity/smtCheckerTests/file_level/file_level_call_via_module.sol @@ -18,7 +18,5 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 8364: (b.sol:95-96): Assertion checker does not yet implement type module "a.sol" -// Warning 8364: (b.sol:103-104): Assertion checker does not yet implement type module "a.sol" // Warning 6328: (b.sol:208-222): CHC: Assertion violation happens here.\nCounterexample:\n\na = 7\nb = 3\n\nTransaction trace:\nC.constructor()\nC.p()\n C.f() -- internal call\n a.sol:f(2) -- internal call\n a.sol:f([97, 98, 99]) -- internal call // Warning 6328: (b.sol:274-288): CHC: Assertion violation happens here.\nCounterexample:\n\na = 7\nb = 3\n\nTransaction trace:\nC.constructor()\nC.p()\n C.f() -- internal call\n a.sol:f(2) -- internal call\n a.sol:f([97, 98, 99]) -- internal call diff --git a/test/libsolidity/smtCheckerTests/file_level/import.sol b/test/libsolidity/smtCheckerTests/file_level/import.sol index 536e38fb1..a67ee4eb6 100644 --- a/test/libsolidity/smtCheckerTests/file_level/import.sol +++ b/test/libsolidity/smtCheckerTests/file_level/import.sol @@ -22,6 +22,5 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 8364: (B:115-116): Assertion checker does not yet implement type module "A" // Warning 6328: (B:238-252): CHC: Assertion violation happens here.\nCounterexample:\ndata = {x: 0}\nx = 0\ny = 0\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:308-322): CHC: Assertion violation happens here.\nCounterexample:\ndata = {x: 0}\nx = 0\ny = 0\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 diff --git a/test/libsolidity/smtCheckerTests/file_level/module_constants_1.sol b/test/libsolidity/smtCheckerTests/file_level/module_constants_1.sol new file mode 100644 index 000000000..5993f5e94 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/file_level/module_constants_1.sol @@ -0,0 +1,26 @@ +==== Source: s1.sol ==== +uint constant a = 89; +==== Source: s2.sol ==== +uint constant a = 88; + +==== Source: s3.sol ==== +import "s1.sol" as M; +import "s2.sol" as N; + +contract C { + function f() internal pure returns (uint, uint) { + return (M.a, N.a); + } + function p() public pure { + (uint x, uint y) = f(); + assert(x == 89); // should hold + assert(x == 88); // should fail + assert(y == 88); // should hold + assert(y == 89); // should fail + } +} +// ==== +// SMTEngine: chc +// ---- +// Warning 6328: (s3.sol:223-238): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 89\ny = 88\n\nTransaction trace:\nC.constructor()\nC.p()\n C.f() -- internal call +// Warning 6328: (s3.sol:291-306): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 89\ny = 88\n\nTransaction trace:\nC.constructor()\nC.p()\n C.f() -- internal call diff --git a/test/libsolidity/smtCheckerTests/file_level/module_constants_functions_1.sol b/test/libsolidity/smtCheckerTests/file_level/module_constants_functions_1.sol new file mode 100644 index 000000000..d3b0e4c6b --- /dev/null +++ b/test/libsolidity/smtCheckerTests/file_level/module_constants_functions_1.sol @@ -0,0 +1,46 @@ +==== Source: s1.sol ==== +uint constant a = 89; + +function fre() pure returns (uint) { + return a; +} + +==== Source: s2.sol ==== +function foo() pure returns (uint) { + return 42; +} + +==== Source: s3.sol ==== +import {fre as foo} from "s1.sol"; +import "s1.sol" as M; +import "s2.sol" as N; + +uint256 constant a = 13; + +contract C { + function f() internal pure returns (uint, uint, uint, uint) { + return (a, foo(), N.foo(), M.a); + } + function p() public pure { + (uint x, uint y, uint z, uint t) = f(); + + assert(x == 13); // should hold + assert(x == 89); // should fail + + assert(y == 89); // should hold + assert(y == 42); // should fail + + assert(z == 42); // should hold + assert(z == 89); // should fail + + assert(t == 89); // should hold + assert(t == 13); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (s3.sol:327-342): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 13\ny = 89\nz = 42\nt = 89\n\nTransaction trace:\nC.constructor()\nC.p()\n C.f() -- internal call\n s1.sol:fre() -- internal call\n s2.sol:foo() -- internal call +// Warning 6328: (s3.sol:396-411): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 13\ny = 89\nz = 42\nt = 89\n\nTransaction trace:\nC.constructor()\nC.p()\n C.f() -- internal call\n s1.sol:fre() -- internal call\n s2.sol:foo() -- internal call +// Warning 6328: (s3.sol:465-480): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 13\ny = 89\nz = 42\nt = 89\n\nTransaction trace:\nC.constructor()\nC.p()\n C.f() -- internal call\n s1.sol:fre() -- internal call\n s2.sol:foo() -- internal call +// Warning 6328: (s3.sol:534-549): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 13\ny = 89\nz = 42\nt = 89\n\nTransaction trace:\nC.constructor()\nC.p()\n C.f() -- internal call\n s1.sol:fre() -- internal call\n s2.sol:foo() -- internal call diff --git a/test/libsolidity/smtCheckerTests/file_level/same_constants_different_files.sol b/test/libsolidity/smtCheckerTests/file_level/same_constants_different_files.sol index 1d7760f25..948baf198 100644 --- a/test/libsolidity/smtCheckerTests/file_level/same_constants_different_files.sol +++ b/test/libsolidity/smtCheckerTests/file_level/same_constants_different_files.sol @@ -22,13 +22,10 @@ contract C { (uint x, uint y, uint z, uint t) = f(); assert(x == 13); // should hold assert(y == 89); // should hold - assert(z == 89); // should hold but the SMTChecker does not implement module access + assert(z == 89); // should hold assert(t == 89); // should hold } } // ==== // SMTEngine: all // ---- -// Warning 7650: (s2.sol:182-185): Assertion checker does not yet support this expression. -// Warning 8364: (s2.sol:182-183): Assertion checker does not yet implement type module "s1.sol" -// Warning 6328: (s2.sol:334-349): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 13\ny = 89\nz = 0\nt = 89\n\nTransaction trace:\nC.constructor()\nC.p()\n C.f() -- internal call\n s1.sol:fre() -- internal call diff --git a/test/libsolidity/smtCheckerTests/imports/import_as_module_2.sol b/test/libsolidity/smtCheckerTests/imports/import_as_module_2.sol index 7f109df23..8ddef2da9 100644 --- a/test/libsolidity/smtCheckerTests/imports/import_as_module_2.sol +++ b/test/libsolidity/smtCheckerTests/imports/import_as_module_2.sol @@ -18,7 +18,5 @@ function f(uint _x) pure { // ==== // SMTEngine: all // ---- -// Warning 8364: (A:118-119): Assertion checker does not yet implement type module "s1.sol" -// Warning 8364: (A:145-146): Assertion checker does not yet implement type module "s1.sol" // Warning 6328: (A:50-64): CHC: Assertion violation happens here.\nCounterexample:\n\n_y = 0\n\nTransaction trace:\nD.constructor()\nD.g(0)\n s1.sol:f(200) -- internal call\n s1.sol:f(0) -- internal call\n A:f(10) -- internal call\n A:f(0) -- internal call // Warning 6328: (s1.sol:28-44): CHC: Assertion violation happens here.\nCounterexample:\n\n_y = 0\n\nTransaction trace:\nD.constructor()\nD.g(0)\n s1.sol:f(200) -- internal call\n s1.sol:f(0) -- internal call From 280ff8cbd410304e9eff3c2fc47542a4d49a73cd Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 16 Sep 2021 15:34:48 +0200 Subject: [PATCH 104/232] Use iterateReplacing in StatementRemover. --- libyul/optimiser/RedundantStoreBase.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/libyul/optimiser/RedundantStoreBase.cpp b/libyul/optimiser/RedundantStoreBase.cpp index 4e7c21367..6fc0570b7 100644 --- a/libyul/optimiser/RedundantStoreBase.cpp +++ b/libyul/optimiser/RedundantStoreBase.cpp @@ -159,8 +159,15 @@ void RedundantStoreBase::merge(TrackedStores& _target, vector&& _ void StatementRemover::operator()(Block& _block) { - ranges::actions::remove_if(_block.statements, [&](Statement const& _statement) -> bool { - return m_toRemove.count(&_statement); - }); + util::iterateReplacing( + _block.statements, + [&](Statement& _statement) -> std::optional> + { + if (m_toRemove.count(&_statement)) + return {vector{}}; + else + return nullopt; + } + ); ASTModifier::operator()(_block); } From c892d1904b4a9cbfdb8ca6b91c8675ea908ae06e Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 16 Sep 2021 16:03:27 +0200 Subject: [PATCH 105/232] Simplify version.cpp --- libsolidity/interface/Version.cpp | 4 ---- libsolidity/interface/Version.h | 10 ++++++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/libsolidity/interface/Version.cpp b/libsolidity/interface/Version.cpp index 297333b6b..0017b6de1 100644 --- a/libsolidity/interface/Version.cpp +++ b/libsolidity/interface/Version.cpp @@ -23,11 +23,7 @@ #include -#include -#include -#include #include -#include using namespace std; diff --git a/libsolidity/interface/Version.h b/libsolidity/interface/Version.h index a5965d42e..bc05fb403 100644 --- a/libsolidity/interface/Version.h +++ b/libsolidity/interface/Version.h @@ -23,10 +23,15 @@ #pragma once -#include +#include +#include #include -namespace solidity::frontend +namespace solidity +{ +using bytes = std::vector; + +namespace frontend { extern char const* VersionNumber; @@ -36,3 +41,4 @@ extern bytes const VersionCompactBytes; extern bool const VersionIsRelease; } +} From 42739b73b19eeaa78b94d5a92d42e38af5e48456 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 31 Aug 2021 16:23:16 +0200 Subject: [PATCH 106/232] Extend debug info. --- libyul/AST.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libyul/AST.h b/libyul/AST.h index 01eece34d..bfc721ce5 100644 --- a/libyul/AST.h +++ b/libyul/AST.h @@ -29,6 +29,7 @@ #include #include +#include namespace solidity::yul { @@ -39,6 +40,8 @@ struct DebugData { explicit DebugData(langutil::SourceLocation _location): location(std::move(_location)) {} langutil::SourceLocation location; + /// ID in the (Solidity) source AST. + std::optional astID; static std::shared_ptr create(langutil::SourceLocation _location = {}) { return std::make_shared(_location); From 05d20446bbbbfecf28301c0753eb7f233112053d Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 15 Sep 2021 15:55:03 +0200 Subject: [PATCH 107/232] Parse @ast-id annotation. --- libyul/AST.h | 18 ++++++++++++----- libyul/AsmParser.cpp | 45 ++++++++++++++++++++++++++++++++++++++++-- libyul/AsmParser.h | 8 ++++++-- test/libyul/Parser.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 9 deletions(-) diff --git a/libyul/AST.h b/libyul/AST.h index bfc721ce5..04306c5a9 100644 --- a/libyul/AST.h +++ b/libyul/AST.h @@ -38,14 +38,22 @@ using Type = YulString; struct DebugData { - explicit DebugData(langutil::SourceLocation _location): location(std::move(_location)) {} + explicit DebugData(langutil::SourceLocation _location, std::optional _astID = {}): + location(std::move(_location)), + astID(std::move(_astID)) + {} + + static std::shared_ptr create( + langutil::SourceLocation _location = {}, + std::optional _astID = {} + ) + { + return std::make_shared(std::move(_location), std::move(_astID)); + } + langutil::SourceLocation location; /// ID in the (Solidity) source AST. std::optional astID; - static std::shared_ptr create(langutil::SourceLocation _location = {}) - { - return std::make_shared(_location); - } }; struct TypedName { std::shared_ptr debugData; YulString name; Type type; }; diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index 19554a5cf..d32d15143 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -103,7 +103,7 @@ unique_ptr Parser::parseInline(std::shared_ptr const& _scanner) try { m_scanner = _scanner; - if (m_sourceNames) + if (m_useSourceLocationFrom == UseSourceLocationFrom::Comments) fetchDebugDataFromComment(); return make_unique(parseBlock()); } @@ -136,6 +136,8 @@ void Parser::fetchDebugDataFromComment() match_results match; langutil::SourceLocation sourceLocation = m_debugDataOverride->location; + // Empty for each new node. + optional astID; while (regex_search(commentLiteral.cbegin(), commentLiteral.cend(), match, tagRegex)) { @@ -149,12 +151,19 @@ void Parser::fetchDebugDataFromComment() else break; } + else if (match[1] == "@ast-id") + { + if (auto parseResult = parseASTIDComment(commentLiteral, m_scanner->currentCommentLocation())) + tie(commentLiteral, astID) = *parseResult; + else + break; + } else // Ignore unrecognized tags. continue; } - m_debugDataOverride = DebugData::create(sourceLocation); + m_debugDataOverride = DebugData::create(sourceLocation, astID); } optional> Parser::parseSrcComment( @@ -222,6 +231,38 @@ optional> Parser::parseSrcComment( return {{tail, SourceLocation{}}}; } +optional>> Parser::parseASTIDComment( + string_view _arguments, + langutil::SourceLocation const& _commentLocation +) +{ + static regex const argRegex = regex( + R"~~(^(\d+)(?:\s|$))~~", + regex_constants::ECMAScript | regex_constants::optimize + ); + match_results match; + optional astID; + bool matched = regex_search(_arguments.cbegin(), _arguments.cend(), match, argRegex); + string_view tail = _arguments; + if (matched) + { + solAssert(match.size() == 2, ""); + tail = _arguments.substr(static_cast(match.position() + match.length())); + + astID = toInt(match[1].str()); + } + + if (!matched || !astID || *astID < 0 || static_cast(*astID) != *astID) + { + m_errorReporter.syntaxError(1749_error, _commentLocation, "Invalid argument for @ast-id."); + astID = nullopt; + } + if (matched) + return {{_arguments, astID}}; + else + return nullopt; +} + Block Parser::parseBlock() { RecursionGuard recursionGuard(*this); diff --git a/libyul/AsmParser.h b/libyul/AsmParser.h index 57b91e1de..2145fa93f 100644 --- a/libyul/AsmParser.h +++ b/libyul/AsmParser.h @@ -108,8 +108,12 @@ protected: void fetchDebugDataFromComment(); - std::optional> - parseSrcComment( + std::optional> parseSrcComment( + std::string_view _arguments, + langutil::SourceLocation const& _commentLocation + ); + + std::optional>> parseASTIDComment( std::string_view _arguments, langutil::SourceLocation const& _commentLocation ); diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index e0b4b29d4..932036b88 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -804,6 +804,51 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets_with_nested_locati CHECK_LOCATION(literal128.debugData->location, "source1", 96, 165); } +BOOST_AUTO_TEST_CASE(astid) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// @src -1:-1:-1 @ast-id 7 + { + /** @ast-id 2 */ + function f(x) -> y {} + mstore(1, 2) + } + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result); + BOOST_CHECK(result->debugData->astID == int64_t(7)); + auto const& funDef = get(result->statements.at(0)); + BOOST_CHECK(funDef.debugData->astID == int64_t(2)); + BOOST_CHECK(funDef.parameters.at(0).debugData->astID == nullopt); + BOOST_CHECK(debugDataOf(result->statements.at(1))->astID == nullopt); +} + +BOOST_AUTO_TEST_CASE(astid_reset) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// @src -1:-1:-1 @ast-id 7 @src 1:1:1 + { + /** @ast-id 2 */ + function f(x) -> y {} + mstore(1, 2) + } + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result); + BOOST_CHECK(result->debugData->astID == int64_t(7)); + auto const& funDef = get(result->statements.at(0)); + BOOST_CHECK(funDef.debugData->astID == int64_t(2)); + BOOST_CHECK(funDef.parameters.at(0).debugData->astID == nullopt); + BOOST_CHECK(debugDataOf(result->statements.at(1))->astID == nullopt); +} + + BOOST_AUTO_TEST_CASE(customSourceLocations_multiple_src_tags_on_one_line) { ErrorList errorList; From 63993387d6a664f21be1dee49c64aadd8b3c830b Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 15 Sep 2021 17:48:26 +0200 Subject: [PATCH 108/232] Add test for invalid ast id. --- scripts/error_codes.py | 1 + test/libyul/Parser.cpp | 78 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/scripts/error_codes.py b/scripts/error_codes.py index d696ff8cc..8d919e41b 100755 --- a/scripts/error_codes.py +++ b/scripts/error_codes.py @@ -193,6 +193,7 @@ def examine_id_coverage(top_dir, source_id_to_file_names, new_ids_only=False): white_ids = { "9804", # Tested in test/libyul/ObjectParser.cpp. "1544", + "1749", "2674", "6367", "8387", diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index 932036b88..0a16aaccb 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -848,6 +848,84 @@ BOOST_AUTO_TEST_CASE(astid_reset) BOOST_CHECK(debugDataOf(result->statements.at(1))->astID == nullopt); } +BOOST_AUTO_TEST_CASE(astid_multi) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// @src -1:-1:-1 @ast-id 7 @src 1:1:1 @ast-id 8 + {} + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result); + BOOST_CHECK(result->debugData->astID == int64_t(8)); +} + +BOOST_AUTO_TEST_CASE(astid_invalid) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// @src -1:-1:-1 @ast-id abc @src 1:1:1 + {} + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result); + BOOST_REQUIRE(errorList.size() == 1); + BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); + BOOST_TEST(errorList[0]->errorId() == 1749_error); + CHECK_LOCATION(result->debugData->location, "", -1, -1); +} + +BOOST_AUTO_TEST_CASE(astid_too_large) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// @ast-id 9223372036854775808 + {} + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result); + BOOST_REQUIRE(errorList.size() == 1); + BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); + BOOST_TEST(errorList[0]->errorId() == 1749_error); +} + +BOOST_AUTO_TEST_CASE(astid_way_too_large) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// @ast-id 999999999999999999999999999999999999999 + {} + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result); + BOOST_REQUIRE(errorList.size() == 1); + BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); + BOOST_TEST(errorList[0]->errorId() == 1749_error); +} + +BOOST_AUTO_TEST_CASE(astid_not_fully_numeric) +{ + ErrorList errorList; + ErrorReporter reporter(errorList); + auto const sourceText = R"( + /// @ast-id 9x + {} + )"; + EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); + shared_ptr result = parse(sourceText, dialect, reporter); + BOOST_REQUIRE(!!result); + BOOST_REQUIRE(errorList.size() == 1); + BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); + BOOST_TEST(errorList[0]->errorId() == 1749_error); +} BOOST_AUTO_TEST_CASE(customSourceLocations_multiple_src_tags_on_one_line) { From dafa6f552ba69175fb8c34975ffe3f44cdfe9c6b Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 6 Sep 2021 18:41:02 +0200 Subject: [PATCH 109/232] Rename formatting function. --- libyul/AsmPrinter.cpp | 32 ++++++++++++++++---------------- libyul/AsmPrinter.h | 6 +++--- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/libyul/AsmPrinter.cpp b/libyul/AsmPrinter.cpp index 9462bbd5a..6be9fc33f 100644 --- a/libyul/AsmPrinter.cpp +++ b/libyul/AsmPrinter.cpp @@ -45,7 +45,7 @@ using namespace solidity::yul; string AsmPrinter::operator()(Literal const& _literal) { - string const locationComment = formatSourceLocationComment(_literal); + string const locationComment = formatDebugData(_literal); switch (_literal.kind) { @@ -65,19 +65,19 @@ string AsmPrinter::operator()(Literal const& _literal) string AsmPrinter::operator()(Identifier const& _identifier) { yulAssert(!_identifier.name.empty(), "Invalid identifier."); - return formatSourceLocationComment(_identifier) + _identifier.name.str(); + return formatDebugData(_identifier) + _identifier.name.str(); } string AsmPrinter::operator()(ExpressionStatement const& _statement) { - string const locationComment = formatSourceLocationComment(_statement); + string const locationComment = formatDebugData(_statement); return locationComment + std::visit(*this, _statement.expression); } string AsmPrinter::operator()(Assignment const& _assignment) { - string const locationComment = formatSourceLocationComment(_assignment); + string const locationComment = formatDebugData(_assignment); yulAssert(_assignment.variableNames.size() >= 1, ""); string variables = (*this)(_assignment.variableNames.front()); @@ -89,7 +89,7 @@ string AsmPrinter::operator()(Assignment const& _assignment) string AsmPrinter::operator()(VariableDeclaration const& _variableDeclaration) { - string out = formatSourceLocationComment(_variableDeclaration); + string out = formatDebugData(_variableDeclaration); out += "let "; out += boost::algorithm::join( @@ -110,7 +110,7 @@ string AsmPrinter::operator()(FunctionDefinition const& _functionDefinition) { yulAssert(!_functionDefinition.name.empty(), "Invalid function name."); - string out = formatSourceLocationComment(_functionDefinition); + string out = formatDebugData(_functionDefinition); out += "function " + _functionDefinition.name.str() + "("; out += boost::algorithm::join( _functionDefinition.parameters | ranges::views::transform( @@ -135,7 +135,7 @@ string AsmPrinter::operator()(FunctionDefinition const& _functionDefinition) string AsmPrinter::operator()(FunctionCall const& _functionCall) { - string const locationComment = formatSourceLocationComment(_functionCall); + string const locationComment = formatDebugData(_functionCall); string const functionName = (*this)(_functionCall.functionName); return locationComment + @@ -150,7 +150,7 @@ string AsmPrinter::operator()(If const& _if) { yulAssert(_if.condition, "Invalid if condition."); - string out = formatSourceLocationComment(_if); + string out = formatDebugData(_if); out += "if " + std::visit(*this, *_if.condition); string body = (*this)(_if.body); @@ -165,7 +165,7 @@ string AsmPrinter::operator()(Switch const& _switch) { yulAssert(_switch.expression, "Invalid expression pointer."); - string out = formatSourceLocationComment(_switch); + string out = formatDebugData(_switch); out += "switch " + std::visit(*this, *_switch.expression); for (auto const& _case: _switch.cases) @@ -182,7 +182,7 @@ string AsmPrinter::operator()(Switch const& _switch) string AsmPrinter::operator()(ForLoop const& _forLoop) { yulAssert(_forLoop.condition, "Invalid for loop condition."); - string const locationComment = formatSourceLocationComment(_forLoop); + string const locationComment = formatDebugData(_forLoop); string pre = (*this)(_forLoop.pre); string condition = std::visit(*this, *_forLoop.condition); @@ -203,23 +203,23 @@ string AsmPrinter::operator()(ForLoop const& _forLoop) string AsmPrinter::operator()(Break const& _break) { - return formatSourceLocationComment(_break) + "break"; + return formatDebugData(_break) + "break"; } string AsmPrinter::operator()(Continue const& _continue) { - return formatSourceLocationComment(_continue) + "continue"; + return formatDebugData(_continue) + "continue"; } // '_leave' and '__leave' is reserved in VisualStudio string AsmPrinter::operator()(Leave const& leave_) { - return formatSourceLocationComment(leave_) + "leave"; + return formatDebugData(leave_) + "leave"; } string AsmPrinter::operator()(Block const& _block) { - string const locationComment = formatSourceLocationComment(_block); + string const locationComment = formatDebugData(_block); if (_block.statements.empty()) return locationComment + "{ }"; @@ -239,7 +239,7 @@ string AsmPrinter::operator()(Block const& _block) string AsmPrinter::formatTypedName(TypedName _variable) { yulAssert(!_variable.name.empty(), "Invalid variable name."); - return formatSourceLocationComment(_variable) + _variable.name.str() + appendTypeName(_variable.type); + return formatDebugData(_variable) + _variable.name.str() + appendTypeName(_variable.type); } string AsmPrinter::appendTypeName(YulString _type, bool _isBoolLiteral) const @@ -300,7 +300,7 @@ string AsmPrinter::formatSourceLocationComment( "/** " + joinHumanReadable(vector{sourceLocation, solidityCodeSnippet}, " ") + " */ "; } -string AsmPrinter::formatSourceLocationComment(shared_ptr const& _debugData, bool _statement) +string AsmPrinter::formatDebugData(shared_ptr const& _debugData, bool _statement) { if ( !_debugData || diff --git a/libyul/AsmPrinter.h b/libyul/AsmPrinter.h index de9e8fe90..73a878958 100644 --- a/libyul/AsmPrinter.h +++ b/libyul/AsmPrinter.h @@ -90,12 +90,12 @@ public: private: std::string formatTypedName(TypedName _variable); std::string appendTypeName(YulString _type, bool _isBoolLiteral = false) const; - std::string formatSourceLocationComment(std::shared_ptr const& _debugData, bool _statement); + std::string formatDebugData(std::shared_ptr const& _debugData, bool _statement); template - std::string formatSourceLocationComment(T const& _node) + std::string formatDebugData(T const& _node) { bool isExpression = std::is_constructible::value; - return formatSourceLocationComment(_node.debugData, !isExpression); + return formatDebugData(_node.debugData, !isExpression); } Dialect const* const m_dialect = nullptr; From a72f4f39939e8f2d474c4fb48c833e948b0ca4bb Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 6 Sep 2021 18:52:48 +0200 Subject: [PATCH 110/232] Print AST ID. --- libsolidity/codegen/ir/Common.cpp | 3 +- libyul/AsmPrinter.cpp | 46 +++++++++++++++++++------------ libyul/AsmPrinter.h | 3 +- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/libsolidity/codegen/ir/Common.cpp b/libsolidity/codegen/ir/Common.cpp index 0a445c119..49a6be5e5 100644 --- a/libsolidity/codegen/ir/Common.cpp +++ b/libsolidity/codegen/ir/Common.cpp @@ -135,10 +135,9 @@ string dispenseLocationComment(langutil::SourceLocation const& _location, IRGene { solAssert(_location.sourceName, ""); _context.markSourceUsed(*_location.sourceName); - return AsmPrinter::formatSourceLocationComment( + return "/// " + AsmPrinter::formatSourceLocation( _location, _context.sourceIndices(), - true /* _statement */, _context.soliditySourceProvider() ); } diff --git a/libyul/AsmPrinter.cpp b/libyul/AsmPrinter.cpp index 6be9fc33f..6a764ee16 100644 --- a/libyul/AsmPrinter.cpp +++ b/libyul/AsmPrinter.cpp @@ -258,10 +258,9 @@ string AsmPrinter::appendTypeName(YulString _type, bool _isBoolLiteral) const return ":" + _type.str(); } -string AsmPrinter::formatSourceLocationComment( +string AsmPrinter::formatSourceLocation( SourceLocation const& _location, map const& _nameToSourceIndex, - bool _statement, CharStreamProvider const* _soliditySourceProvider ) { @@ -294,27 +293,38 @@ string AsmPrinter::formatSourceLocationComment( ":" + to_string(_location.end); - return - _statement ? - "/// " + joinHumanReadable(vector{sourceLocation, solidityCodeSnippet}, " ") : - "/** " + joinHumanReadable(vector{sourceLocation, solidityCodeSnippet}, " ") + " */ "; + return joinHumanReadable(vector{sourceLocation, solidityCodeSnippet}, " "); } string AsmPrinter::formatDebugData(shared_ptr const& _debugData, bool _statement) { - if ( - !_debugData || - m_lastLocation == _debugData->location || - m_nameToSourceIndex.empty() - ) + if (!_debugData) return ""; - m_lastLocation = _debugData->location; + vector items; + if (auto id = _debugData->astID) + items.emplace_back("@ast-id " + to_string(*id)); - return formatSourceLocationComment( - _debugData->location, - m_nameToSourceIndex, - _statement, - m_soliditySourceProvider - ) + (_statement ? "\n" : ""); + if ( + m_lastLocation != _debugData->location && + !m_nameToSourceIndex.empty() + ) + { + m_lastLocation = _debugData->location; + + items.emplace_back(formatSourceLocation( + _debugData->location, + m_nameToSourceIndex, + m_soliditySourceProvider + )); + } + + string commentBody = joinHumanReadable(items, " "); + if (commentBody.empty()) + return ""; + else + return + _statement ? + "/// " + commentBody + "\n" : + "/** " + commentBody + " */ "; } diff --git a/libyul/AsmPrinter.h b/libyul/AsmPrinter.h index 73a878958..3bb683191 100644 --- a/libyul/AsmPrinter.h +++ b/libyul/AsmPrinter.h @@ -80,10 +80,9 @@ public: std::string operator()(Leave const& _continue); std::string operator()(Block const& _block); - static std::string formatSourceLocationComment( + static std::string formatSourceLocation( langutil::SourceLocation const& _location, std::map const& _nameToSourceIndex, - bool _statement, langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr ); From 8b3748e5b7b72e76667733be5e7bf4c7bc142334 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 9 Sep 2021 18:24:28 +0200 Subject: [PATCH 111/232] Emit ast id. --- libsolidity/codegen/ir/IRGenerator.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 30fc149ad..0b314bc9b 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -340,6 +340,7 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function) return m_context.functionCollector().createFunction(functionName, [&]() { m_context.resetLocalVariables(); Whiskers t(R"( + /// @ast-id function () -> { @@ -348,6 +349,7 @@ string IRGenerator::generateFunction(FunctionDefinition const& _function) )"); + t("astID", to_string(_function.id())); t("sourceLocationComment", dispenseLocationComment(_function)); t( "contractSourceLocationComment", @@ -407,6 +409,7 @@ string IRGenerator::generateModifier( return m_context.functionCollector().createFunction(functionName, [&]() { m_context.resetLocalVariables(); Whiskers t(R"( + /// @ast-id function () -> { @@ -437,6 +440,7 @@ string IRGenerator::generateModifier( _modifierInvocation.name().annotation().referencedDeclaration ); solAssert(modifier, ""); + t("astID", to_string(modifier->id())); t("sourceLocationComment", dispenseLocationComment(*modifier)); t( "contractSourceLocationComment", @@ -542,12 +546,14 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) solAssert(paramTypes.empty(), ""); solUnimplementedAssert(type->sizeOnStack() == 1, ""); return Whiskers(R"( + /// @ast-id function () -> rval { rval := loadimmutable("") } )") + ("astID", to_string(_varDecl.id())) ("sourceLocationComment", dispenseLocationComment(_varDecl)) ( "contractSourceLocationComment", @@ -561,12 +567,14 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) { solAssert(paramTypes.empty(), ""); return Whiskers(R"( + /// @ast-id function () -> { := () } )") + ("astID", to_string(_varDecl.id())) ("sourceLocationComment", dispenseLocationComment(_varDecl)) ( "contractSourceLocationComment", @@ -683,6 +691,7 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) } return Whiskers(R"( + /// @ast-id function () -> { @@ -693,6 +702,7 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) ("params", joinHumanReadable(parameters)) ("retVariables", joinHumanReadable(returnVariables)) ("code", std::move(code)) + ("astID", to_string(_varDecl.id())) ("sourceLocationComment", dispenseLocationComment(_varDecl)) ( "contractSourceLocationComment", @@ -804,7 +814,7 @@ void IRGenerator::generateConstructors(ContractDefinition const& _contract) m_context.resetLocalVariables(); m_context.functionCollector().createFunction(IRNames::constructor(*contract), [&]() { Whiskers t(R"( - + function () { @@ -819,6 +829,10 @@ void IRGenerator::generateConstructors(ContractDefinition const& _contract) for (ASTPointer const& varDecl: contract->constructor()->parameters()) params += m_context.addLocalVariable(*varDecl).stackSlots(); + if (contract->constructor()) + t("astIDComment", "/// @ast-id " + to_string(contract->constructor()->id()) + "\n"); + else + t("astIDComment", ""); t("sourceLocationComment", dispenseLocationComment( contract->constructor() ? dynamic_cast(*contract->constructor()) : From 3e429ab231696f34a2bdb9132cae0a46920ca7a4 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 15 Sep 2021 17:40:11 +0200 Subject: [PATCH 112/232] Update commandline tests. --- test/cmdlineTests/exp_base_literal/output | 1 + test/cmdlineTests/name_simplifier/output | 2 +- test/cmdlineTests/revert_strings/output | 1 + .../standard_irOptimized_requested/output.json | 2 +- test/cmdlineTests/standard_ir_requested/output.json | 1 + .../cmdlineTests/standard_viair_requested/output.json | 1 + test/cmdlineTests/viair_abicoder_v1/output | 1 + test/cmdlineTests/yul_source_locations/output.json | 11 +++++++++++ .../yul_source_locations_code_snippet_escaping/output | 1 + test/cmdlineTests/yul_string_format_ascii/output.json | 1 + .../yul_string_format_ascii_bytes32/output.json | 1 + .../output.json | 1 + .../yul_string_format_ascii_long/output.json | 1 + test/cmdlineTests/yul_string_format_hex/output.json | 1 + 14 files changed, 24 insertions(+), 2 deletions(-) diff --git a/test/cmdlineTests/exp_base_literal/output b/test/cmdlineTests/exp_base_literal/output index 7a7f0647a..c4b71dcac 100644 --- a/test/cmdlineTests/exp_base_literal/output +++ b/test/cmdlineTests/exp_base_literal/output @@ -288,6 +288,7 @@ object "C_81" { power := exp(1, exponent) } + /// @ast-id 80 /// @src 0:96:368 "function f(uint a, uint b, uint c, uint d) public pure returns (uint, int, uint, uint) {..." function fun_f_80(var_a_4, var_b_6, var_c_8, var_d_10) -> var__13, var__15, var__17, var__19 { /// @src 0:160:164 "uint" diff --git a/test/cmdlineTests/name_simplifier/output b/test/cmdlineTests/name_simplifier/output index 703ddc2dc..73c9cc1aa 100644 --- a/test/cmdlineTests/name_simplifier/output +++ b/test/cmdlineTests/name_simplifier/output @@ -105,7 +105,7 @@ object "C_59" { mstore(4, 0x32) revert(0, 0x24) } - /// @src 0:381:623 "function sumArray(S[] memory _s) public returns (uint, string memory) {..." + /// @ast-id 58 @src 0:381:623 "function sumArray(S[] memory _s) public returns (uint, string memory) {..." function fun_sumArray(var_s_mpos) -> var, var_mpos { /// @src 0:346:625 "contract C {..." diff --git a/test/cmdlineTests/revert_strings/output b/test/cmdlineTests/revert_strings/output index df0029e63..718cf0ba9 100644 --- a/test/cmdlineTests/revert_strings/output +++ b/test/cmdlineTests/revert_strings/output @@ -357,6 +357,7 @@ object "C_15" { } + /// @ast-id 14 /// @src 0:93:145 "function f(uint[][] memory, E e) public pure {..." function fun_f_14(var__7_mpos, var_e_10) { diff --git a/test/cmdlineTests/standard_irOptimized_requested/output.json b/test/cmdlineTests/standard_irOptimized_requested/output.json index 696a03573..c636adcc4 100644 --- a/test/cmdlineTests/standard_irOptimized_requested/output.json +++ b/test/cmdlineTests/standard_irOptimized_requested/output.json @@ -68,7 +68,7 @@ object \"C_7\" { { tail := add(headStart, 0) } function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { revert(0, 0) } - /// @src 0:92:119 \"function f() public pure {}\" + /// @ast-id 6 @src 0:92:119 \"function f() public pure {}\" function fun_f_6() { } } diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index a056672b9..2c01878f3 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -98,6 +98,7 @@ object \"C_7\" { revert(0, 0) } + /// @ast-id 6 /// @src 0:92:119 \"function f() public pure {}\" function fun_f_6() { diff --git a/test/cmdlineTests/standard_viair_requested/output.json b/test/cmdlineTests/standard_viair_requested/output.json index 31ab3de5e..9ae88b90c 100644 --- a/test/cmdlineTests/standard_viair_requested/output.json +++ b/test/cmdlineTests/standard_viair_requested/output.json @@ -187,6 +187,7 @@ object \"D_16\" { revert(pos, returndatasize()) } + /// @ast-id 15 /// @src 0:106:144 \"function f() public { C c = new C(); }\" function fun_f_15() { diff --git a/test/cmdlineTests/viair_abicoder_v1/output b/test/cmdlineTests/viair_abicoder_v1/output index 3a0d4744b..18d02a0e9 100644 --- a/test/cmdlineTests/viair_abicoder_v1/output +++ b/test/cmdlineTests/viair_abicoder_v1/output @@ -113,6 +113,7 @@ object "test_11" { ret := 0 } + /// @ast-id 10 /// @src 0:99:167 "function f() public pure returns (bool) {..." function fun_f_10() -> var__5 { /// @src 0:133:137 "bool" diff --git a/test/cmdlineTests/yul_source_locations/output.json b/test/cmdlineTests/yul_source_locations/output.json index 0839fb1f3..8d0cd3c11 100644 --- a/test/cmdlineTests/yul_source_locations/output.json +++ b/test/cmdlineTests/yul_source_locations/output.json @@ -135,6 +135,7 @@ object \"C_54\" { sstore(slot, update_byte_slice_32_shift_0(sload(slot), prepare_store_t_int256(convertedValue_0))) } + /// @ast-id 20 /// @src 0:175:223 \"constructor(int _init)...\" function constructor_C_54(var__init_12) { @@ -267,6 +268,7 @@ object \"C_54\" { } + /// @ast-id 10 /// @src 0:152:171 \"int public stateVar\" function getter_fun_stateVar_10() -> ret { @@ -325,6 +327,7 @@ object \"C_54\" { sum := add(x, y) } + /// @ast-id 30 /// @src 0:226:302 \"function f() external pure returns (int)...\" function fun_f_30() -> var__23 { /// @src 0:262:265 \"int\" @@ -395,6 +398,7 @@ object \"C_54\" { sstore(slot, update_byte_slice_32_shift_0(sload(slot), prepare_store_t_int256(convertedValue_0))) } + /// @ast-id 37 /// @src 0:304:341 \"modifier m()...\" function modifier_m_40(var__42) -> _5 { _5 := var__42 @@ -539,6 +543,7 @@ object \"C_54\" { } /// @src 0:79:428 \"contract C...\" + /// @ast-id 53 /// @src 0:343:426 \"function f2() m public returns (int)...\" function fun_f2_53() -> var__42 { /// @src 0:375:378 \"int\" @@ -731,6 +736,7 @@ object \"D_72\" { sstore(slot, update_byte_slice_32_shift_0(sload(slot), prepare_store_t_int256(convertedValue_0))) } + /// @ast-id 71 /// @src 1:113:164 \"constructor(int _init2)...\" function constructor_D_72(var__init2_63) { /// @src 1:107:108 \"3\" @@ -760,6 +766,7 @@ object \"D_72\" { converted := cleanup_t_int256(identity(cleanup_t_rational_42_by_1(value))) } + /// @ast-id 20 /// @src 0:175:223 \"constructor(int _init)...\" function constructor_C_54(var__init_12) { @@ -892,6 +899,7 @@ object \"D_72\" { } + /// @ast-id 10 /// @src 0:152:171 \"int public stateVar\" function getter_fun_stateVar_10() -> ret { @@ -950,6 +958,7 @@ object \"D_72\" { sum := add(x, y) } + /// @ast-id 30 /// @src 0:226:302 \"function f() external pure returns (int)...\" function fun_f_30() -> var__23 { /// @src 0:262:265 \"int\" @@ -1020,6 +1029,7 @@ object \"D_72\" { sstore(slot, update_byte_slice_32_shift_0(sload(slot), prepare_store_t_int256(convertedValue_0))) } + /// @ast-id 37 /// @src 0:304:341 \"modifier m()...\" function modifier_m_40(var__42) -> _5 { _5 := var__42 @@ -1164,6 +1174,7 @@ object \"D_72\" { } /// @src 1:91:166 \"contract D is C(3)...\" + /// @ast-id 53 /// @src 0:343:426 \"function f2() m public returns (int)...\" function fun_f2_53() -> var__42 { /// @src 0:375:378 \"int\" diff --git a/test/cmdlineTests/yul_source_locations_code_snippet_escaping/output b/test/cmdlineTests/yul_source_locations_code_snippet_escaping/output index 6563ceb3e..9fea7f8cc 100644 --- a/test/cmdlineTests/yul_source_locations_code_snippet_escaping/output +++ b/test/cmdlineTests/yul_source_locations_code_snippet_escaping/output @@ -333,6 +333,7 @@ object "D_27" { converted := copy_literal_to_memory_5bde9a896e3f09acac1496d16642fcdd887d2a000bf1ab18bdff3f17b91e320b() } + /// @ast-id 26 /// @src 0:336:597 "function f() /* @use-src 0:\"input.sol\", 1:\"#utility.yul\" @ast-id 15 *\/ public returns (string memory) { C c = new /// @src 0:149:156 \"new C()\"..." function fun_f_26() -> var__5_mpos { /// @src 0:423:436 "string memory" diff --git a/test/cmdlineTests/yul_string_format_ascii/output.json b/test/cmdlineTests/yul_string_format_ascii/output.json index 221c9d306..f68f984c7 100644 --- a/test/cmdlineTests/yul_string_format_ascii/output.json +++ b/test/cmdlineTests/yul_string_format_ascii/output.json @@ -192,6 +192,7 @@ object \"C_11\" { converted := copy_literal_to_memory_9f0adad0a59b05d2e04a1373342b10b9eb16c57c164c8a3bfcbf46dccee39a21() } + /// @ast-id 10 /// @src 0:91:162 \"function f() external pure returns (string memory) { return \\\"abcabc\\\"; }\" function fun_f_10() -> var__5_mpos { /// @src 0:127:140 \"string memory\" diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json index 0c8fbe701..e2757135e 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32/output.json @@ -116,6 +116,7 @@ object \"C_11\" { converted := 0x6162636162630000000000000000000000000000000000000000000000000000 } + /// @ast-id 10 /// @src 0:91:156 \"function f() external pure returns (bytes32) { return \\\"abcabc\\\"; }\" function fun_f_10() -> var__5 { /// @src 0:127:134 \"bytes32\" diff --git a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json index f495dc98a..c977d791d 100644 --- a/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_bytes32_from_number/output.json @@ -127,6 +127,7 @@ object \"C_11\" { converted := cleanup_t_bytes4(shift_left_224(cleanup_t_rational_1633837924_by_1(value))) } + /// @ast-id 10 /// @src 0:91:157 \"function f() external pure returns (bytes4) { return 0x61626364; }\" function fun_f_10() -> var__5 { /// @src 0:127:133 \"bytes4\" diff --git a/test/cmdlineTests/yul_string_format_ascii_long/output.json b/test/cmdlineTests/yul_string_format_ascii_long/output.json index c32952157..19428f29d 100644 --- a/test/cmdlineTests/yul_string_format_ascii_long/output.json +++ b/test/cmdlineTests/yul_string_format_ascii_long/output.json @@ -196,6 +196,7 @@ object \"C_11\" { converted := copy_literal_to_memory_d6604f85ac07e2b33103a620b3d3d75b0473c7214912beded67b9b624d41c571() } + /// @ast-id 10 /// @src 0:91:241 \"function f() external pure returns (string memory) { return \\\"abcdabcdcafecafeabcdabcdcafecafeffffzzzzoooo0123456789,.<,>.?:;'[{]}|`~!@#$%^&*()-_=+\\\"; }\" function fun_f_10() -> var__5_mpos { /// @src 0:127:140 \"string memory\" diff --git a/test/cmdlineTests/yul_string_format_hex/output.json b/test/cmdlineTests/yul_string_format_hex/output.json index 98e3c8e46..b17922a55 100644 --- a/test/cmdlineTests/yul_string_format_hex/output.json +++ b/test/cmdlineTests/yul_string_format_hex/output.json @@ -127,6 +127,7 @@ object \"C_11\" { converted := cleanup_t_bytes4(shift_left_224(cleanup_t_rational_2864434397_by_1(value))) } + /// @ast-id 10 /// @src 0:91:157 \"function f() external pure returns (bytes4) { return 0xaabbccdd; }\" function fun_f_10() -> var__5 { /// @src 0:127:133 \"bytes4\" From cedf68365bb2c1f6142997192b9b45518d575b58 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 16 Sep 2021 12:42:53 +0200 Subject: [PATCH 113/232] Move test. --- .../input.json | 0 .../output.json | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename test/cmdlineTests/{yul_source_locations => standard_yul_source_locations}/input.json (100%) rename test/cmdlineTests/{yul_source_locations => standard_yul_source_locations}/output.json (100%) diff --git a/test/cmdlineTests/yul_source_locations/input.json b/test/cmdlineTests/standard_yul_source_locations/input.json similarity index 100% rename from test/cmdlineTests/yul_source_locations/input.json rename to test/cmdlineTests/standard_yul_source_locations/input.json diff --git a/test/cmdlineTests/yul_source_locations/output.json b/test/cmdlineTests/standard_yul_source_locations/output.json similarity index 100% rename from test/cmdlineTests/yul_source_locations/output.json rename to test/cmdlineTests/standard_yul_source_locations/output.json From a141589adf32cede437fa040e42962eae6470cb4 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 16 Sep 2021 12:49:01 +0200 Subject: [PATCH 114/232] Update tests. --- .../standard_yul_source_locations/input.json | 7 +- .../standard_yul_source_locations/output.json | 586 +++++++++++++++--- 2 files changed, 502 insertions(+), 91 deletions(-) diff --git a/test/cmdlineTests/standard_yul_source_locations/input.json b/test/cmdlineTests/standard_yul_source_locations/input.json index ce5c4b626..8ba84239a 100644 --- a/test/cmdlineTests/standard_yul_source_locations/input.json +++ b/test/cmdlineTests/standard_yul_source_locations/input.json @@ -4,7 +4,7 @@ { "C": { - "content": "//SPDX-License-Identifier: GPL-2.0\npragma solidity >=0.0;\npragma abicoder v2;\n\ncontract C\n{\n int constant constVar = 41;\n int immutable immutVar = 42;\n int public stateVar;\n\n constructor(int _init)\n {\n stateVar = _init;\n }\n\n function f() external pure returns (int)\n {\n return constVar + immutVar;\n }\n modifier m()\n {\n stateVar++;\n _;\n }\n function f2() m public returns (int)\n {\n return stateVar + this.f() + immutVar;\n }\n}\n" + "content": "//SPDX-License-Identifier: GPL-2.0\npragma solidity >=0.0;\npragma abicoder v2;\n\ncontract C\n{\n int public constant constVar = 41;\n int immutable immutVar = 42;\n int public stateVar;\n\n constructor(int _init)\n {\n stateVar = _init;\n }\n\n function f() external pure returns (int)\n {\n return constVar + immutVar;\n }\n modifier m()\n {\n stateVar++;\n _;\n }\n function f2() m public returns (int)\n {\n return stateVar + this.f() + immutVar;\n }\n}\n" }, "D": { @@ -15,7 +15,8 @@ { "outputSelection": { - "*": { "*": ["ir"] } - } + "*": { "*": ["ir", "irOptimized"] } + }, + "optimizer": { "enabled": true } } } diff --git a/test/cmdlineTests/standard_yul_source_locations/output.json b/test/cmdlineTests/standard_yul_source_locations/output.json index 8d0cd3c11..485380625 100644 --- a/test/cmdlineTests/standard_yul_source_locations/output.json +++ b/test/cmdlineTests/standard_yul_source_locations/output.json @@ -9,7 +9,7 @@ /// @use-src 0:\"C\" object \"C_54\" { code { - /// @src 0:79:428 \"contract C...\" + /// @src 0:79:435 \"contract C...\" mstore(64, 160) if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } @@ -136,31 +136,31 @@ object \"C_54\" { } /// @ast-id 20 - /// @src 0:175:223 \"constructor(int _init)...\" + /// @src 0:182:230 \"constructor(int _init)...\" function constructor_C_54(var__init_12) { - /// @src 0:175:223 \"constructor(int _init)...\" + /// @src 0:182:230 \"constructor(int _init)...\" - /// @src 0:147:149 \"42\" + /// @src 0:154:156 \"42\" let expr_7 := 0x2a let _3 := convert_t_rational_42_by_1_to_t_int256(expr_7) mstore(128, _3) - /// @src 0:214:219 \"_init\" + /// @src 0:221:226 \"_init\" let _4 := var__init_12 let expr_16 := _4 - /// @src 0:203:219 \"stateVar = _init\" + /// @src 0:210:226 \"stateVar = _init\" update_storage_value_offset_0t_int256_to_t_int256(0x00, expr_16) let expr_17 := expr_16 } - /// @src 0:79:428 \"contract C...\" + /// @src 0:79:435 \"contract C...\" } /// @use-src 0:\"C\" object \"C_54_deployed\" { code { - /// @src 0:79:428 \"contract C...\" + /// @src 0:79:435 \"contract C...\" mstore(64, 128) if iszero(lt(calldatasize(), 4)) @@ -204,6 +204,18 @@ object \"C_54\" { return(memPos, sub(memEnd, memPos)) } + case 0xa00b982b + { + // constVar() + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := getter_fun_constVar_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + } + default {} } if iszero(calldatasize()) { } @@ -269,7 +281,7 @@ object \"C_54\" { } /// @ast-id 10 - /// @src 0:152:171 \"int public stateVar\" + /// @src 0:159:178 \"int public stateVar\" function getter_fun_stateVar_10() -> ret { let slot := 0 @@ -278,15 +290,7 @@ object \"C_54\" { ret := read_from_storage_split_dynamic_t_int256(slot, offset) } - /// @src 0:79:428 \"contract C...\" - - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { - revert(0, 0) - } - - function zero_value_for_split_t_int256() -> ret { - ret := 0 - } + /// @src 0:79:435 \"contract C...\" function cleanup_t_rational_41_by_1(value) -> cleaned { cleaned := value @@ -300,13 +304,28 @@ object \"C_54\" { converted := cleanup_t_int256(identity(cleanup_t_rational_41_by_1(value))) } - /// @src 0:93:119 \"int constant constVar = 41\" + /// @src 0:93:126 \"int public constant constVar = 41\" function constant_constVar_5() -> ret { - /// @src 0:117:119 \"41\" + /// @src 0:124:126 \"41\" let expr_4 := 0x29 - let _2 := convert_t_rational_41_by_1_to_t_int256(expr_4) + let _1 := convert_t_rational_41_by_1_to_t_int256(expr_4) - ret := _2 + ret := _1 + } + + /// @ast-id 5 + /// @src 0:93:126 \"int public constant constVar = 41\" + function getter_fun_constVar_5() -> ret_0 { + ret_0 := constant_constVar_5() + } + /// @src 0:79:435 \"contract C...\" + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function zero_value_for_split_t_int256() -> ret { + ret := 0 } function panic_error_0x11() { @@ -328,26 +347,26 @@ object \"C_54\" { } /// @ast-id 30 - /// @src 0:226:302 \"function f() external pure returns (int)...\" + /// @src 0:233:309 \"function f() external pure returns (int)...\" function fun_f_30() -> var__23 { - /// @src 0:262:265 \"int\" - let zero_t_int256_1 := zero_value_for_split_t_int256() - var__23 := zero_t_int256_1 + /// @src 0:269:272 \"int\" + let zero_t_int256_2 := zero_value_for_split_t_int256() + var__23 := zero_t_int256_2 - /// @src 0:279:287 \"constVar\" + /// @src 0:286:294 \"constVar\" let expr_25 := constant_constVar_5() - /// @src 0:290:298 \"immutVar\" + /// @src 0:297:305 \"immutVar\" let _3 := loadimmutable(\"8\") let expr_26 := _3 - /// @src 0:279:298 \"constVar + immutVar\" + /// @src 0:286:305 \"constVar + immutVar\" let expr_27 := checked_add_t_int256(expr_25, expr_26) - /// @src 0:272:298 \"return constVar + immutVar\" + /// @src 0:279:305 \"return constVar + immutVar\" var__23 := expr_27 leave } - /// @src 0:79:428 \"contract C...\" + /// @src 0:79:435 \"contract C...\" function shift_right_0_unsigned(value) -> newValue { newValue := @@ -399,20 +418,20 @@ object \"C_54\" { } /// @ast-id 37 - /// @src 0:304:341 \"modifier m()...\" + /// @src 0:311:348 \"modifier m()...\" function modifier_m_40(var__42) -> _5 { _5 := var__42 - /// @src 0:322:332 \"stateVar++\" + /// @src 0:329:339 \"stateVar++\" let _7 := read_from_storage_split_offset_0_t_int256(0x00) let _6 := increment_t_int256(_7) update_storage_value_offset_0t_int256_to_t_int256(0x00, _6) let expr_33 := _7 - /// @src 0:336:337 \"_\" + /// @src 0:343:344 \"_\" _5 := fun_f2_53_inner(var__42) } - /// @src 0:79:428 \"contract C...\" + /// @src 0:79:435 \"contract C...\" function cleanup_t_uint160(value) -> cleaned { cleaned := and(value, 0xffffffffffffffffffffffffffffffffffffffff) @@ -494,19 +513,19 @@ object \"C_54\" { revert(pos, returndatasize()) } - /// @src 0:343:426 \"function f2() m public returns (int)...\" + /// @src 0:350:433 \"function f2() m public returns (int)...\" function fun_f2_53_inner(_8) -> var__42 { var__42 := _8 - /// @src 0:392:400 \"stateVar\" + /// @src 0:399:407 \"stateVar\" let _9 := read_from_storage_split_offset_0_t_int256(0x00) let expr_44 := _9 - /// @src 0:403:407 \"this\" + /// @src 0:410:414 \"this\" let expr_45_address := address() - /// @src 0:403:409 \"this.f\" + /// @src 0:410:416 \"this.f\" let expr_46_address := convert_t_contract$_C_$54_to_t_address(expr_45_address) let expr_46_functionSelector := 0x26121ff0 - /// @src 0:403:411 \"this.f()\" + /// @src 0:410:418 \"this.f()\" if iszero(extcodesize(expr_46_address)) { revert_error_0cc013b6b3b6beabea4e3a74a6d380f0df81852ca99887912475e1f66b2a2c20() } // storage for arguments and returned data @@ -527,32 +546,32 @@ object \"C_54\" { // decode return parameters from external try-call into retVars expr_47 := abi_decode_tuple_t_int256_fromMemory(_10, add(_10, returndatasize())) } - /// @src 0:392:411 \"stateVar + this.f()\" + /// @src 0:399:418 \"stateVar + this.f()\" let expr_48 := checked_add_t_int256(expr_44, expr_47) - /// @src 0:414:422 \"immutVar\" + /// @src 0:421:429 \"immutVar\" let _13 := loadimmutable(\"8\") let expr_49 := _13 - /// @src 0:392:422 \"stateVar + this.f() + immutVar\" + /// @src 0:399:429 \"stateVar + this.f() + immutVar\" let expr_50 := checked_add_t_int256(expr_48, expr_49) - /// @src 0:385:422 \"return stateVar + this.f() + immutVar\" + /// @src 0:392:429 \"return stateVar + this.f() + immutVar\" var__42 := expr_50 leave } - /// @src 0:79:428 \"contract C...\" + /// @src 0:79:435 \"contract C...\" /// @ast-id 53 - /// @src 0:343:426 \"function f2() m public returns (int)...\" + /// @src 0:350:433 \"function f2() m public returns (int)...\" function fun_f2_53() -> var__42 { - /// @src 0:375:378 \"int\" + /// @src 0:382:385 \"int\" let zero_t_int256_4 := zero_value_for_split_t_int256() var__42 := zero_t_int256_4 var__42 := modifier_m_40(var__42) } - /// @src 0:79:428 \"contract C...\" + /// @src 0:79:435 \"contract C...\" } @@ -561,6 +580,188 @@ object \"C_54\" { } +","irOptimized":"/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + +/// @use-src 0:\"C\" +object \"C_54\" { + code { + { + /// @src 0:79:435 \"contract C...\" + mstore(64, 160) + if callvalue() { revert(0, 0) } + let programSize := datasize(\"C_54\") + let argSize := sub(codesize(), programSize) + let newFreePtr := add(160, and(add(argSize, 31), not(31))) + if or(gt(newFreePtr, sub(shl(64, 1), 1)), lt(newFreePtr, 160)) + { + mstore(/** @src -1:-1:-1 */ 0, /** @src 0:79:435 \"contract C...\" */ shl(224, 0x4e487b71)) + mstore(4, 0x41) + revert(/** @src -1:-1:-1 */ 0, /** @src 0:79:435 \"contract C...\" */ 0x24) + } + mstore(64, newFreePtr) + codecopy(160, programSize, argSize) + if slt(argSize, 32) + { + revert(/** @src -1:-1:-1 */ 0, 0) + } + /// @src 0:79:435 \"contract C...\" + constructor_C(mload(160)) + let _1 := mload(64) + let _2 := datasize(\"C_54_deployed\") + codecopy(_1, dataoffset(\"C_54_deployed\"), _2) + setimmutable(_1, \"8\", mload(128)) + return(_1, _2) + } + /// @ast-id 20 @src 0:182:230 \"constructor(int _init)...\" + function constructor_C(var_init) + { + /// @src 0:154:156 \"42\" + mstore(128, 0x2a) + /// @src 0:79:435 \"contract C...\" + sstore(/** @src 0:210:226 \"stateVar = _init\" */ 0x00, /** @src 0:79:435 \"contract C...\" */ var_init) + } + } + /// @use-src 0:\"C\" + object \"C_54_deployed\" { + code { + { + /// @src 0:79:435 \"contract C...\" + mstore(64, 128) + if iszero(lt(calldatasize(), 4)) + { + let _1 := 0 + switch shr(224, calldataload(_1)) + case 0x26121ff0 { + if callvalue() { revert(_1, _1) } + abi_decode(calldatasize()) + let ret := /** @src 0:286:305 \"constVar + immutVar\" */ checked_add_int256_568(/** @src 0:297:305 \"immutVar\" */ loadimmutable(\"8\")) + /// @src 0:79:435 \"contract C...\" + let memPos := mload(64) + return(memPos, sub(abi_encode_int256(memPos, ret), memPos)) + } + case 0x793816ec { + if callvalue() { revert(_1, _1) } + abi_decode(calldatasize()) + let ret_1 := sload(_1) + let memPos_1 := mload(64) + return(memPos_1, sub(abi_encode_int256(memPos_1, ret_1), memPos_1)) + } + case 0x9942ec6f { + if callvalue() { revert(_1, _1) } + abi_decode(calldatasize()) + let ret_2 := /** @src 0:382:385 \"int\" */ modifier_m() + /// @src 0:79:435 \"contract C...\" + let memPos_2 := mload(64) + return(memPos_2, sub(abi_encode_int256(memPos_2, ret_2), memPos_2)) + } + case 0xa00b982b { + if callvalue() { revert(_1, _1) } + abi_decode(calldatasize()) + let memPos_3 := mload(64) + return(memPos_3, sub(abi_encode_int256_567(memPos_3), memPos_3)) + } + } + revert(0, 0) + } + function abi_decode(dataEnd) + { + if slt(add(dataEnd, not(3)), 0) { revert(0, 0) } + } + function abi_encode_int256_567(headStart) -> tail + { + tail := add(headStart, 32) + mstore(headStart, /** @src 0:124:126 \"41\" */ 0x29) + } + /// @src 0:79:435 \"contract C...\" + function abi_encode_int256(headStart, value0) -> tail + { + tail := add(headStart, 32) + mstore(headStart, value0) + } + function panic_error_0x11() + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 0x11) + revert(0, 0x24) + } + function checked_add_int256_568(y) -> sum + { + if and(1, sgt(y, sub(shl(255, 1), 42))) { panic_error_0x11() } + sum := add(/** @src 0:124:126 \"41\" */ 0x29, /** @src 0:79:435 \"contract C...\" */ y) + } + function checked_add_int256(x, y) -> sum + { + let _1 := slt(x, 0) + if and(iszero(_1), sgt(y, sub(sub(shl(255, 1), 1), x))) { panic_error_0x11() } + if and(_1, slt(y, sub(shl(255, 1), x))) { panic_error_0x11() } + sum := add(x, y) + } + /// @ast-id 37 @src 0:311:348 \"modifier m()...\" + function modifier_m() -> _1 + { + /// @src 0:79:435 \"contract C...\" + let _2 := 0 + let _3 := sload(_2) + if eq(_3, sub(shl(255, 1), 1)) { panic_error_0x11() } + let ret := add(_3, 1) + sstore(_2, ret) + /// @src 0:410:418 \"this.f()\" + if iszero(extcodesize(/** @src 0:410:414 \"this\" */ address())) + /// @src 0:410:418 \"this.f()\" + { + /// @src 0:79:435 \"contract C...\" + revert(_2, _2) + } + /// @src 0:410:418 \"this.f()\" + let _4 := /** @src 0:79:435 \"contract C...\" */ mload(64) + /// @src 0:410:418 \"this.f()\" + mstore(_4, /** @src 0:79:435 \"contract C...\" */ shl(228, 0x026121ff)) + /// @src 0:410:418 \"this.f()\" + let _5 := staticcall(gas(), /** @src 0:410:414 \"this\" */ address(), /** @src 0:410:418 \"this.f()\" */ _4, 4, _4, 32) + if iszero(_5) + { + /// @src 0:79:435 \"contract C...\" + let pos := mload(64) + returndatacopy(pos, _2, returndatasize()) + revert(pos, returndatasize()) + } + /// @src 0:410:418 \"this.f()\" + let expr := /** @src 0:79:435 \"contract C...\" */ _2 + /// @src 0:410:418 \"this.f()\" + if _5 + { + /// @src 0:79:435 \"contract C...\" + let newFreePtr := add(_4, and(add(/** @src 0:410:418 \"this.f()\" */ returndatasize(), /** @src 0:79:435 \"contract C...\" */ 31), not(31))) + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, _4)) + { + mstore(_2, shl(224, 0x4e487b71)) + mstore(/** @src 0:410:418 \"this.f()\" */ 4, /** @src 0:79:435 \"contract C...\" */ 0x41) + revert(_2, 0x24) + } + mstore(64, newFreePtr) + /// @src 0:410:418 \"this.f()\" + expr := abi_decode_int256_fromMemory(_4, add(_4, returndatasize())) + } + /// @src 0:399:418 \"stateVar + this.f()\" + let expr_1 := checked_add_int256(ret, expr) + /// @src 0:343:344 \"_\" + _1 := /** @src 0:399:429 \"stateVar + this.f() + immutVar\" */ checked_add_int256(expr_1, /** @src 0:421:429 \"immutVar\" */ loadimmutable(\"8\")) + } + /// @src 0:79:435 \"contract C...\" + function abi_decode_int256_fromMemory(headStart, dataEnd) -> value0 + { + if slt(sub(dataEnd, headStart), 32) { revert(0, 0) } + value0 := mload(headStart) + } + } + data \".metadata\" hex\"\" + } +} "}},"D":{"D":{"ir":"/*=====================================================* * WARNING * * Solidity to Yul compilation is still EXPERIMENTAL * @@ -767,20 +968,20 @@ object \"D_72\" { } /// @ast-id 20 - /// @src 0:175:223 \"constructor(int _init)...\" + /// @src 0:182:230 \"constructor(int _init)...\" function constructor_C_54(var__init_12) { - /// @src 0:175:223 \"constructor(int _init)...\" + /// @src 0:182:230 \"constructor(int _init)...\" - /// @src 0:147:149 \"42\" + /// @src 0:154:156 \"42\" let expr_7 := 0x2a let _6 := convert_t_rational_42_by_1_to_t_int256(expr_7) mstore(128, _6) - /// @src 0:214:219 \"_init\" + /// @src 0:221:226 \"_init\" let _7 := var__init_12 let expr_16 := _7 - /// @src 0:203:219 \"stateVar = _init\" + /// @src 0:210:226 \"stateVar = _init\" update_storage_value_offset_0t_int256_to_t_int256(0x00, expr_16) let expr_17 := expr_16 @@ -835,6 +1036,18 @@ object \"D_72\" { return(memPos, sub(memEnd, memPos)) } + case 0xa00b982b + { + // constVar() + + if callvalue() { revert_error_ca66f745a3ce8ff40e2ccaf1ad45db7774001b90d25810abd9040049be7bf4bb() } + abi_decode_tuple_(4, calldatasize()) + let ret_0 := getter_fun_constVar_5() + let memPos := allocate_unbounded() + let memEnd := abi_encode_tuple_t_int256__to_t_int256__fromStack(memPos , ret_0) + return(memPos, sub(memEnd, memPos)) + } + default {} } if iszero(calldatasize()) { } @@ -900,7 +1113,7 @@ object \"D_72\" { } /// @ast-id 10 - /// @src 0:152:171 \"int public stateVar\" + /// @src 0:159:178 \"int public stateVar\" function getter_fun_stateVar_10() -> ret { let slot := 0 @@ -911,14 +1124,6 @@ object \"D_72\" { } /// @src 1:91:166 \"contract D is C(3)...\" - function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { - revert(0, 0) - } - - function zero_value_for_split_t_int256() -> ret { - ret := 0 - } - function cleanup_t_rational_41_by_1(value) -> cleaned { cleaned := value } @@ -931,13 +1136,28 @@ object \"D_72\" { converted := cleanup_t_int256(identity(cleanup_t_rational_41_by_1(value))) } - /// @src 0:93:119 \"int constant constVar = 41\" + /// @src 0:93:126 \"int public constant constVar = 41\" function constant_constVar_5() -> ret { - /// @src 0:117:119 \"41\" + /// @src 0:124:126 \"41\" let expr_4 := 0x29 - let _2 := convert_t_rational_41_by_1_to_t_int256(expr_4) + let _1 := convert_t_rational_41_by_1_to_t_int256(expr_4) - ret := _2 + ret := _1 + } + + /// @ast-id 5 + /// @src 0:93:126 \"int public constant constVar = 41\" + function getter_fun_constVar_5() -> ret_0 { + ret_0 := constant_constVar_5() + } + /// @src 1:91:166 \"contract D is C(3)...\" + + function revert_error_42b3090547df1d2001c96683413b8cf91c1b902ef5e3cb8d9f6f304cf7446f74() { + revert(0, 0) + } + + function zero_value_for_split_t_int256() -> ret { + ret := 0 } function panic_error_0x11() { @@ -959,21 +1179,21 @@ object \"D_72\" { } /// @ast-id 30 - /// @src 0:226:302 \"function f() external pure returns (int)...\" + /// @src 0:233:309 \"function f() external pure returns (int)...\" function fun_f_30() -> var__23 { - /// @src 0:262:265 \"int\" - let zero_t_int256_1 := zero_value_for_split_t_int256() - var__23 := zero_t_int256_1 + /// @src 0:269:272 \"int\" + let zero_t_int256_2 := zero_value_for_split_t_int256() + var__23 := zero_t_int256_2 - /// @src 0:279:287 \"constVar\" + /// @src 0:286:294 \"constVar\" let expr_25 := constant_constVar_5() - /// @src 0:290:298 \"immutVar\" + /// @src 0:297:305 \"immutVar\" let _3 := loadimmutable(\"8\") let expr_26 := _3 - /// @src 0:279:298 \"constVar + immutVar\" + /// @src 0:286:305 \"constVar + immutVar\" let expr_27 := checked_add_t_int256(expr_25, expr_26) - /// @src 0:272:298 \"return constVar + immutVar\" + /// @src 0:279:305 \"return constVar + immutVar\" var__23 := expr_27 leave @@ -1030,16 +1250,16 @@ object \"D_72\" { } /// @ast-id 37 - /// @src 0:304:341 \"modifier m()...\" + /// @src 0:311:348 \"modifier m()...\" function modifier_m_40(var__42) -> _5 { _5 := var__42 - /// @src 0:322:332 \"stateVar++\" + /// @src 0:329:339 \"stateVar++\" let _7 := read_from_storage_split_offset_0_t_int256(0x00) let _6 := increment_t_int256(_7) update_storage_value_offset_0t_int256_to_t_int256(0x00, _6) let expr_33 := _7 - /// @src 0:336:337 \"_\" + /// @src 0:343:344 \"_\" _5 := fun_f2_53_inner(var__42) } @@ -1125,19 +1345,19 @@ object \"D_72\" { revert(pos, returndatasize()) } - /// @src 0:343:426 \"function f2() m public returns (int)...\" + /// @src 0:350:433 \"function f2() m public returns (int)...\" function fun_f2_53_inner(_8) -> var__42 { var__42 := _8 - /// @src 0:392:400 \"stateVar\" + /// @src 0:399:407 \"stateVar\" let _9 := read_from_storage_split_offset_0_t_int256(0x00) let expr_44 := _9 - /// @src 0:403:407 \"this\" + /// @src 0:410:414 \"this\" let expr_45_address := address() - /// @src 0:403:409 \"this.f\" + /// @src 0:410:416 \"this.f\" let expr_46_address := convert_t_contract$_C_$54_to_t_address(expr_45_address) let expr_46_functionSelector := 0x26121ff0 - /// @src 0:403:411 \"this.f()\" + /// @src 0:410:418 \"this.f()\" if iszero(extcodesize(expr_46_address)) { revert_error_0cc013b6b3b6beabea4e3a74a6d380f0df81852ca99887912475e1f66b2a2c20() } // storage for arguments and returned data @@ -1158,16 +1378,16 @@ object \"D_72\" { // decode return parameters from external try-call into retVars expr_47 := abi_decode_tuple_t_int256_fromMemory(_10, add(_10, returndatasize())) } - /// @src 0:392:411 \"stateVar + this.f()\" + /// @src 0:399:418 \"stateVar + this.f()\" let expr_48 := checked_add_t_int256(expr_44, expr_47) - /// @src 0:414:422 \"immutVar\" + /// @src 0:421:429 \"immutVar\" let _13 := loadimmutable(\"8\") let expr_49 := _13 - /// @src 0:392:422 \"stateVar + this.f() + immutVar\" + /// @src 0:399:429 \"stateVar + this.f() + immutVar\" let expr_50 := checked_add_t_int256(expr_48, expr_49) - /// @src 0:385:422 \"return stateVar + this.f() + immutVar\" + /// @src 0:392:429 \"return stateVar + this.f() + immutVar\" var__42 := expr_50 leave @@ -1175,9 +1395,9 @@ object \"D_72\" { /// @src 1:91:166 \"contract D is C(3)...\" /// @ast-id 53 - /// @src 0:343:426 \"function f2() m public returns (int)...\" + /// @src 0:350:433 \"function f2() m public returns (int)...\" function fun_f2_53() -> var__42 { - /// @src 0:375:378 \"int\" + /// @src 0:382:385 \"int\" let zero_t_int256_4 := zero_value_for_split_t_int256() var__42 := zero_t_int256_4 @@ -1192,4 +1412,194 @@ object \"D_72\" { } +","irOptimized":"/*=====================================================* + * WARNING * + * Solidity to Yul compilation is still EXPERIMENTAL * + * It can result in LOSS OF FUNDS or worse * + * !USE AT YOUR OWN RISK! * + *=====================================================*/ + +/// @use-src 0:\"C\", 1:\"D\" +object \"D_72\" { + code { + { + /// @src 1:91:166 \"contract D is C(3)...\" + mstore(64, 160) + if callvalue() { revert(0, 0) } + let programSize := datasize(\"D_72\") + let argSize := sub(codesize(), programSize) + let newFreePtr := add(160, and(add(argSize, 31), not(31))) + if or(gt(newFreePtr, sub(shl(64, 1), 1)), lt(newFreePtr, 160)) + { + mstore(/** @src -1:-1:-1 */ 0, /** @src 1:91:166 \"contract D is C(3)...\" */ shl(224, 0x4e487b71)) + mstore(4, 0x41) + revert(/** @src -1:-1:-1 */ 0, /** @src 1:91:166 \"contract D is C(3)...\" */ 0x24) + } + mstore(64, newFreePtr) + codecopy(160, programSize, argSize) + if slt(argSize, 32) + { + revert(/** @src -1:-1:-1 */ 0, 0) + } + /// @src 1:91:166 \"contract D is C(3)...\" + constructor_D(mload(160)) + let _1 := mload(64) + let _2 := datasize(\"D_72_deployed\") + codecopy(_1, dataoffset(\"D_72_deployed\"), _2) + setimmutable(_1, \"8\", mload(128)) + return(_1, _2) + } + /// @ast-id 71 @src 1:113:164 \"constructor(int _init2)...\" + function constructor_D(var_init2) + { + /// @src 0:154:156 \"42\" + mstore(128, 0x2a) + /// @src 1:91:166 \"contract D is C(3)...\" + sstore(/** @src 0:210:226 \"stateVar = _init\" */ 0x00, /** @src 1:107:108 \"3\" */ 0x03) + /// @src 1:91:166 \"contract D is C(3)...\" + if and(1, sgt(var_init2, sub(shl(255, 1), 4))) + { + mstore(/** @src 0:210:226 \"stateVar = _init\" */ 0x00, /** @src 1:91:166 \"contract D is C(3)...\" */ shl(224, 0x4e487b71)) + mstore(4, 0x11) + revert(/** @src 0:210:226 \"stateVar = _init\" */ 0x00, /** @src 1:91:166 \"contract D is C(3)...\" */ 0x24) + } + sstore(/** @src 0:210:226 \"stateVar = _init\" */ 0x00, /** @src 1:91:166 \"contract D is C(3)...\" */ add(/** @src 1:107:108 \"3\" */ 0x03, /** @src 1:91:166 \"contract D is C(3)...\" */ var_init2)) + } + } + /// @use-src 0:\"C\", 1:\"D\" + object \"D_72_deployed\" { + code { + { + /// @src 1:91:166 \"contract D is C(3)...\" + mstore(64, 128) + if iszero(lt(calldatasize(), 4)) + { + let _1 := 0 + switch shr(224, calldataload(_1)) + case 0x26121ff0 { + if callvalue() { revert(_1, _1) } + abi_decode(calldatasize()) + let ret := /** @src 0:286:305 \"constVar + immutVar\" */ checked_add_int256_568(/** @src 0:297:305 \"immutVar\" */ loadimmutable(\"8\")) + /// @src 1:91:166 \"contract D is C(3)...\" + let memPos := mload(64) + return(memPos, sub(abi_encode_int256(memPos, ret), memPos)) + } + case 0x793816ec { + if callvalue() { revert(_1, _1) } + abi_decode(calldatasize()) + let ret_1 := sload(_1) + let memPos_1 := mload(64) + return(memPos_1, sub(abi_encode_int256(memPos_1, ret_1), memPos_1)) + } + case 0x9942ec6f { + if callvalue() { revert(_1, _1) } + abi_decode(calldatasize()) + let ret_2 := /** @src 0:382:385 \"int\" */ modifier_m() + /// @src 1:91:166 \"contract D is C(3)...\" + let memPos_2 := mload(64) + return(memPos_2, sub(abi_encode_int256(memPos_2, ret_2), memPos_2)) + } + case 0xa00b982b { + if callvalue() { revert(_1, _1) } + abi_decode(calldatasize()) + let memPos_3 := mload(64) + return(memPos_3, sub(abi_encode_int256_567(memPos_3), memPos_3)) + } + } + revert(0, 0) + } + function abi_decode(dataEnd) + { + if slt(add(dataEnd, not(3)), 0) { revert(0, 0) } + } + function abi_encode_int256_567(headStart) -> tail + { + tail := add(headStart, 32) + mstore(headStart, /** @src 0:124:126 \"41\" */ 0x29) + } + /// @src 1:91:166 \"contract D is C(3)...\" + function abi_encode_int256(headStart, value0) -> tail + { + tail := add(headStart, 32) + mstore(headStart, value0) + } + function panic_error_0x11() + { + mstore(0, shl(224, 0x4e487b71)) + mstore(4, 0x11) + revert(0, 0x24) + } + function checked_add_int256_568(y) -> sum + { + if and(1, sgt(y, sub(shl(255, 1), 42))) { panic_error_0x11() } + sum := add(/** @src 0:124:126 \"41\" */ 0x29, /** @src 1:91:166 \"contract D is C(3)...\" */ y) + } + function checked_add_int256(x, y) -> sum + { + let _1 := slt(x, 0) + if and(iszero(_1), sgt(y, sub(sub(shl(255, 1), 1), x))) { panic_error_0x11() } + if and(_1, slt(y, sub(shl(255, 1), x))) { panic_error_0x11() } + sum := add(x, y) + } + /// @ast-id 37 @src 0:311:348 \"modifier m()...\" + function modifier_m() -> _1 + { + /// @src 1:91:166 \"contract D is C(3)...\" + let _2 := 0 + let _3 := sload(_2) + if eq(_3, sub(shl(255, 1), 1)) { panic_error_0x11() } + let ret := add(_3, 1) + sstore(_2, ret) + /// @src 0:410:418 \"this.f()\" + if iszero(extcodesize(/** @src 0:410:414 \"this\" */ address())) + /// @src 0:410:418 \"this.f()\" + { + /// @src 1:91:166 \"contract D is C(3)...\" + revert(_2, _2) + } + /// @src 0:410:418 \"this.f()\" + let _4 := /** @src 1:91:166 \"contract D is C(3)...\" */ mload(64) + /// @src 0:410:418 \"this.f()\" + mstore(_4, /** @src 1:91:166 \"contract D is C(3)...\" */ shl(228, 0x026121ff)) + /// @src 0:410:418 \"this.f()\" + let _5 := staticcall(gas(), /** @src 0:410:414 \"this\" */ address(), /** @src 0:410:418 \"this.f()\" */ _4, 4, _4, 32) + if iszero(_5) + { + /// @src 1:91:166 \"contract D is C(3)...\" + let pos := mload(64) + returndatacopy(pos, _2, returndatasize()) + revert(pos, returndatasize()) + } + /// @src 0:410:418 \"this.f()\" + let expr := /** @src 1:91:166 \"contract D is C(3)...\" */ _2 + /// @src 0:410:418 \"this.f()\" + if _5 + { + /// @src 1:91:166 \"contract D is C(3)...\" + let newFreePtr := add(_4, and(add(/** @src 0:410:418 \"this.f()\" */ returndatasize(), /** @src 1:91:166 \"contract D is C(3)...\" */ 31), not(31))) + if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, _4)) + { + mstore(_2, shl(224, 0x4e487b71)) + mstore(/** @src 0:410:418 \"this.f()\" */ 4, /** @src 1:91:166 \"contract D is C(3)...\" */ 0x41) + revert(_2, 0x24) + } + mstore(64, newFreePtr) + /// @src 0:410:418 \"this.f()\" + expr := abi_decode_int256_fromMemory(_4, add(_4, returndatasize())) + } + /// @src 0:399:418 \"stateVar + this.f()\" + let expr_1 := checked_add_int256(ret, expr) + /// @src 0:343:344 \"_\" + _1 := /** @src 0:399:429 \"stateVar + this.f() + immutVar\" */ checked_add_int256(expr_1, /** @src 0:421:429 \"immutVar\" */ loadimmutable(\"8\")) + } + /// @src 1:91:166 \"contract D is C(3)...\" + function abi_decode_int256_fromMemory(headStart, dataEnd) -> value0 + { + if slt(sub(dataEnd, headStart), 32) { revert(0, 0) } + value0 := mload(headStart) + } + } + data \".metadata\" hex\"\" + } +} "}}},"sources":{"C":{"id":0},"D":{"id":1}}} From 66a540ea01f6043cda4c7fb596909779f816413d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 16 Sep 2021 19:22:23 +0200 Subject: [PATCH 115/232] Fix pylint warnings about the usage of f-strings --- scripts/bytecodecompare/prepare_report.py | 13 +++++++------ scripts/extract_test_cases.py | 2 +- scripts/isolate_tests.py | 5 +++-- scripts/regressions.py | 16 +++++++--------- .../wasm-rebuild/docker-scripts/isolate_tests.py | 3 ++- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/scripts/bytecodecompare/prepare_report.py b/scripts/bytecodecompare/prepare_report.py index 7c8ce9b0d..33463f198 100755 --- a/scripts/bytecodecompare/prepare_report.py +++ b/scripts/bytecodecompare/prepare_report.py @@ -101,12 +101,13 @@ class Statistics: self.missing_metadata_count += sum(1 for c in contract_reports if c.metadata is None) def __str__(self) -> str: - return "test cases: {}, contracts: {}, errors: {}, missing bytecode: {}, missing metadata: {}".format( - self.file_count, - str(self.contract_count) + ('+' if self.error_count > 0 else ''), - self.error_count, - self.missing_bytecode_count, - self.missing_metadata_count, + contract_count = str(self.contract_count) + ('+' if self.error_count > 0 else '') + return ( + f"test cases: {self.file_count}, " + f"contracts: {contract_count}, " + f"errors: {self.error_count}, " + f"missing bytecode: {self.missing_bytecode_count}, " + f"missing metadata: {self.missing_metadata_count}" ) diff --git a/scripts/extract_test_cases.py b/scripts/extract_test_cases.py index 4277271cf..c43cabce2 100755 --- a/scripts/extract_test_cases.py +++ b/scripts/extract_test_cases.py @@ -23,7 +23,7 @@ def extract_test_cases(_path): for l in lines: if inside: if l.strip().endswith(')' + delimiter + '";'): - with open('%03d_%s.sol' % (ctr, test_name), mode='wb', encoding='utf8') as f: + with open(f'{ctr:03d}_{test_name}.sol', mode='wb', encoding='utf8') as f: f.write(test) ctr += 1 inside = False diff --git a/scripts/isolate_tests.py b/scripts/isolate_tests.py index f3a121f3d..93cf2755c 100755 --- a/scripts/isolate_tests.py +++ b/scripts/isolate_tests.py @@ -58,7 +58,7 @@ def extract_yul_docs_cases(path): if line.startswith("//"): continue if not line.startswith("object") and not line.startswith("{"): - return indent("{{\n{}\n}}\n\n".format(code.rstrip()), " ") + return indent(f"{{\n{code.rstrip()}\n}}\n\n", " ") break return code @@ -107,7 +107,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) - sol_filename = 'test_%s_%s.%s' % (hashlib.sha256(test.encode("utf-8")).hexdigest(), cleaned_filename, language) + hash = hashlib.sha256(test.encode("utf-8")).hexdigest() + sol_filename = f'test_{hash}_{cleaned_filename}.{language}' with open(sol_filename, mode='w', encoding='utf8', newline='') as fi: fi.write(remainder) diff --git a/scripts/regressions.py b/scripts/regressions.py index 185d7bbdf..1efbb48b5 100755 --- a/scripts/regressions.py +++ b/scripts/regressions.py @@ -101,22 +101,20 @@ class regressor(): """ testStatus = [] - for fuzzer in glob.iglob("{}/*_ossfuzz".format(self._fuzzer_path)): + for fuzzer in glob.iglob(f"{self._fuzzer_path}/*_ossfuzz"): basename = os.path.basename(fuzzer) - logfile = os.path.join(self._logpath, "{}.log".format(basename)) - corpus_dir = "/tmp/solidity-fuzzing-corpus/{0}_seed_corpus" \ - .format(basename) - cmd = "find {0} -type f | xargs -n1 sh -c '{1} $0 || exit 255'".format(corpus_dir, fuzzer) + logfile = os.path.join(self._logpath, f"{basename}.log") + corpus_dir = f"/tmp/solidity-fuzzing-corpus/{basename}_seed_corpus" + cmd = f"find {corpus_dir} -type f | xargs -n1 sh -c '{fuzzer} $0 || exit 255'" self.run_cmd(cmd, logfile=logfile) ret = self.process_log(logfile) if not ret: print( - "\t[-] libFuzzer reported failure for {0}. " - "Failure logged to test_results".format( - basename)) + f"\t[-] libFuzzer reported failure for {basename}. " + "Failure logged to test_results") testStatus.append(False) else: - print("\t[+] {0} passed regression tests.".format(basename)) + print(f"\t[+] {basename} passed regression tests.") testStatus.append(True) return all(testStatus) diff --git a/scripts/wasm-rebuild/docker-scripts/isolate_tests.py b/scripts/wasm-rebuild/docker-scripts/isolate_tests.py index 53a78a990..635ebcc31 100755 --- a/scripts/wasm-rebuild/docker-scripts/isolate_tests.py +++ b/scripts/wasm-rebuild/docker-scripts/isolate_tests.py @@ -46,7 +46,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) - with open('test_%s_%s.sol' % (hashlib.sha256(test).hexdigest(), cleaned_filename), 'w', encoding='utf8') as _f: + hash = hashlib.sha256(test).hexdigest() + with open(f'test_{hash}_{cleaned_filename}.sol', 'w', encoding='utf8') as _f: _f.write(remainder) From 4560e5bdd9442693d16035ed190413fc70d207cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 16 Sep 2021 20:22:24 +0200 Subject: [PATCH 116/232] Bump base image version for b_bytecode_ems to get a newer version of Python --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4a9745481..af5d4336e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1007,7 +1007,7 @@ jobs: b_bytecode_ems: docker: - - image: circleci/node:14 + - image: circleci/node:16 environment: SOLC_EMSCRIPTEN: "On" steps: From 1a9ba1baca03435a8300d20d01d1f751f47c7177 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 16 Sep 2021 13:00:45 +0200 Subject: [PATCH 117/232] Failing test: standard_yul_single_file_via_urls --- .../standard_yul_single_file_via_urls/args | 1 + .../standard_yul_single_file_via_urls/input.json | 6 ++++++ .../standard_yul_single_file_via_urls/output.json | 12 ++++++++++++ 3 files changed, 19 insertions(+) create mode 100644 test/cmdlineTests/standard_yul_single_file_via_urls/args create mode 100644 test/cmdlineTests/standard_yul_single_file_via_urls/input.json create mode 100644 test/cmdlineTests/standard_yul_single_file_via_urls/output.json diff --git a/test/cmdlineTests/standard_yul_single_file_via_urls/args b/test/cmdlineTests/standard_yul_single_file_via_urls/args new file mode 100644 index 000000000..24d48faf2 --- /dev/null +++ b/test/cmdlineTests/standard_yul_single_file_via_urls/args @@ -0,0 +1 @@ +--pretty-json --json-indent 4 --allow-paths . diff --git a/test/cmdlineTests/standard_yul_single_file_via_urls/input.json b/test/cmdlineTests/standard_yul_single_file_via_urls/input.json new file mode 100644 index 000000000..0f4da43fc --- /dev/null +++ b/test/cmdlineTests/standard_yul_single_file_via_urls/input.json @@ -0,0 +1,6 @@ +{ + "language": "Yul", + "sources": { + "C": {"urls": ["in.yul"]} + } +} diff --git a/test/cmdlineTests/standard_yul_single_file_via_urls/output.json b/test/cmdlineTests/standard_yul_single_file_via_urls/output.json new file mode 100644 index 000000000..cdef28c26 --- /dev/null +++ b/test/cmdlineTests/standard_yul_single_file_via_urls/output.json @@ -0,0 +1,12 @@ +{ + "errors": + [ + { + "component": "general", + "formattedMessage": "Yul mode only supports exactly one input file.", + "message": "Yul mode only supports exactly one input file.", + "severity": "error", + "type": "JSONError" + } + ] +} From fc8c4b046c0bf0ad48ec56e1db1f33592a8a4716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 16 Sep 2021 13:09:08 +0200 Subject: [PATCH 118/232] StandardCompiler: Do not discard non-fatal errors that happened before a fatal error --- Changelog.md | 1 + libsolidity/interface/StandardCompiler.cpp | 65 +++++++++++++++---- .../output.json | 7 ++ 3 files changed, 60 insertions(+), 13 deletions(-) diff --git a/Changelog.md b/Changelog.md index 516f20b33..eae8eb8be 100644 --- a/Changelog.md +++ b/Changelog.md @@ -28,6 +28,7 @@ Bugfixes: * SMTChecker: Fix false positive in external calls from constructors. * SMTChecker: Fix internal error on some multi-source uses of ``abi.*``, cryptographic functions and constants. * SMTChecker: Fix BMC's constraints regarding internal functions. + * Standard JSON: Fix non-fatal errors in Yul mode being discarded if followed by a fatal error. * Type Checker: Disallow modifier declarations and definitions in interfaces. * Yul Optimizer: Fix a crash in LoadResolver, when ``keccak256`` has particular non-identifier arguments. diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 4d4dba6ca..1031ec7c3 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -1312,16 +1312,49 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) { - if (_inputsAndSettings.sources.size() != 1) - return formatFatalError("JSONError", "Yul mode only supports exactly one input file."); - if (!_inputsAndSettings.smtLib2Responses.empty()) - return formatFatalError("JSONError", "Yul mode does not support smtlib2responses."); - if (!_inputsAndSettings.remappings.empty()) - return formatFatalError("JSONError", "Field \"settings.remappings\" cannot be used for Yul."); - if (_inputsAndSettings.revertStrings != RevertStrings::Default) - return formatFatalError("JSONError", "Field \"settings.debug.revertStrings\" cannot be used for Yul."); - Json::Value output = Json::objectValue; + output["errors"] = std::move(_inputsAndSettings.errors); + + if (_inputsAndSettings.sources.size() != 1) + { + output["errors"].append(formatError( + Error::Severity::Error, + "JSONError", + "general", + "Yul mode only supports exactly one input file." + )); + return output; + } + if (!_inputsAndSettings.smtLib2Responses.empty()) + { + output["errors"].append(formatError( + Error::Severity::Error, + "JSONError", + "general", + "Yul mode does not support smtlib2responses." + )); + return output; + } + if (!_inputsAndSettings.remappings.empty()) + { + output["errors"].append(formatError( + Error::Severity::Error, + "JSONError", + "general", + "Field \"settings.remappings\" cannot be used for Yul." + )); + return output; + } + if (_inputsAndSettings.revertStrings != RevertStrings::Default) + { + output["errors"].append(formatError( + Error::Severity::Error, + "JSONError", + "general", + "Field \"settings.debug.revertStrings\" cannot be used for Yul." + )); + return output; + } AssemblyStack stack( _inputsAndSettings.evmVersion, @@ -1333,16 +1366,23 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) // Inconsistent state - stop here to receive error reports from users if (!stack.parseAndAnalyze(sourceName, sourceContents) && stack.errors().empty()) - return formatFatalError("InternalCompilerError", "No error reported, but compilation failed."); + { + output["errors"].append(formatError( + Error::Severity::Error, + "InternalCompilerError", + "general", + "No error reported, but compilation failed." + )); + return output; + } if (!stack.errors().empty()) { - Json::Value errors = Json::arrayValue; for (auto const& error: stack.errors()) { auto err = dynamic_pointer_cast(error); - errors.append(formatErrorWithException( + output["errors"].append(formatErrorWithException( stack, *error, Error::errorSeverity(err->type()), @@ -1351,7 +1391,6 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings) "" )); } - output["errors"] = errors; return output; } diff --git a/test/cmdlineTests/standard_yul_single_file_via_urls/output.json b/test/cmdlineTests/standard_yul_single_file_via_urls/output.json index cdef28c26..3f62fa0fe 100644 --- a/test/cmdlineTests/standard_yul_single_file_via_urls/output.json +++ b/test/cmdlineTests/standard_yul_single_file_via_urls/output.json @@ -1,6 +1,13 @@ { "errors": [ + { + "component": "general", + "formattedMessage": "Cannot import url (\"in.yul\"): File not found.", + "message": "Cannot import url (\"in.yul\"): File not found.", + "severity": "error", + "type": "IOError" + }, { "component": "general", "formattedMessage": "Yul mode only supports exactly one input file.", From 553d3ed7142c692268a2669f82a2fa33b118c0e3 Mon Sep 17 00:00:00 2001 From: Basit Raza Date: Fri, 17 Sep 2021 10:51:54 +0400 Subject: [PATCH 119/232] Added the BigSur 11.5 in the supported os list --- scripts/install_deps.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/install_deps.sh b/scripts/install_deps.sh index 8fa65667a..ddea2e8b7 100755 --- a/scripts/install_deps.sh +++ b/scripts/install_deps.sh @@ -93,8 +93,8 @@ case $(uname -s) in 10.15) echo "Installing solidity dependencies on macOS 10.15 Catalina." ;; - 11.0 | 11.1 | 11.2 | 11.3 | 11.4) - echo "Installing solidity dependencies on macOS 11.0 / 11.1 / 11.2 / 11.3 / 11.4 Big Sur." + 11.0 | 11.1 | 11.2 | 11.3 | 11.4 | 11.5) + echo "Installing solidity dependencies on macOS 11.0 / 11.1 / 11.2 / 11.3 / 11.4 / 11.5 Big Sur." ;; *) echo "Unsupported macOS version." From bb1e185f8805ba4162bb6e4f5297e9cb5fdf27ab Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Fri, 17 Sep 2021 15:40:35 +0200 Subject: [PATCH 120/232] Docker config: Update ossfuzz docker image. --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index af5d4336e..4706fe6c0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -17,8 +17,8 @@ parameters: default: "solbuildpackpusher/solidity-buildpack-deps@sha256:61232feea23c8c57e82cf5fae890f8b86bbec353cdc04f2fcba383ca589e1d8b" ubuntu-1604-clang-ossfuzz-docker-image: type: string - # solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-11 - default: "solbuildpackpusher/solidity-buildpack-deps@sha256:4acb2674eab3e7939d6dc6caa0b8320f4dd79484325242b58473ca2875792d90" + # solbuildpackpusher/solidity-buildpack-deps:ubuntu1604.clang.ossfuzz-13 + default: "solbuildpackpusher/solidity-buildpack-deps@sha256:c26a7ffc9fc243a4ec3105b9dc1edcdd964ad0e9665c83172b7ebda74bbf3021" emscripten-docker-image: type: string # solbuildpackpusher/solidity-buildpack-deps:emscripten-6 From 13571f4a6797f838ea4ca5ffb2b4fe737ac529bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 14 Sep 2021 14:09:18 +0200 Subject: [PATCH 121/232] CommandLineInterface: Add asserts documenting which function is expected to work in which input modes --- solc/CommandLineInterface.cpp | 38 +++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index de361f0c6..3399a86fb 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -154,6 +154,8 @@ static bool coloredOutput(CommandLineOptions const& _options) void CommandLineInterface::handleBinary(string const& _contract) { + solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); + if (m_options.compiler.outputs.binary) { if (!m_options.output.dir.empty()) @@ -178,6 +180,8 @@ void CommandLineInterface::handleBinary(string const& _contract) void CommandLineInterface::handleOpcode(string const& _contract) { + solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); + if (!m_options.output.dir.empty()) createFile(m_compiler->filesystemFriendlyName(_contract) + ".opcode", evmasm::disassemble(m_compiler->object(_contract).bytecode)); else @@ -190,6 +194,8 @@ void CommandLineInterface::handleOpcode(string const& _contract) void CommandLineInterface::handleIR(string const& _contractName) { + solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); + if (!m_options.compiler.outputs.ir) return; @@ -204,6 +210,8 @@ void CommandLineInterface::handleIR(string const& _contractName) void CommandLineInterface::handleIROptimized(string const& _contractName) { + solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); + if (!m_options.compiler.outputs.irOptimized) return; @@ -218,6 +226,8 @@ void CommandLineInterface::handleIROptimized(string const& _contractName) void CommandLineInterface::handleEwasm(string const& _contractName) { + solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); + if (!m_options.compiler.outputs.ewasm) return; @@ -239,6 +249,8 @@ void CommandLineInterface::handleEwasm(string const& _contractName) void CommandLineInterface::handleBytecode(string const& _contract) { + solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); + if (m_options.compiler.outputs.opcodes) handleOpcode(_contract); if (m_options.compiler.outputs.binary || m_options.compiler.outputs.binaryRuntime) @@ -247,6 +259,8 @@ void CommandLineInterface::handleBytecode(string const& _contract) void CommandLineInterface::handleSignatureHashes(string const& _contract) { + solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); + if (!m_options.compiler.outputs.signatureHashes) return; @@ -263,6 +277,8 @@ void CommandLineInterface::handleSignatureHashes(string const& _contract) void CommandLineInterface::handleMetadata(string const& _contract) { + solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); + if (!m_options.compiler.outputs.metadata) return; @@ -275,6 +291,8 @@ void CommandLineInterface::handleMetadata(string const& _contract) void CommandLineInterface::handleABI(string const& _contract) { + solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); + if (!m_options.compiler.outputs.abi) return; @@ -287,6 +305,8 @@ void CommandLineInterface::handleABI(string const& _contract) void CommandLineInterface::handleStorageLayout(string const& _contract) { + solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); + if (!m_options.compiler.outputs.storageLayout) return; @@ -299,6 +319,8 @@ void CommandLineInterface::handleStorageLayout(string const& _contract) void CommandLineInterface::handleNatspec(bool _natspecDev, string const& _contract) { + solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); + bool enabled = false; std::string suffix; std::string title; @@ -339,6 +361,8 @@ void CommandLineInterface::handleNatspec(bool _natspecDev, string const& _contra void CommandLineInterface::handleGasEstimation(string const& _contract) { + solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); + Json::Value estimates = m_compiler->gasEstimates(_contract); sout() << "Gas estimation:" << endl; @@ -465,6 +489,8 @@ bool CommandLineInterface::readInputFiles() map CommandLineInterface::parseAstFromInput() { + solAssert(m_options.input.mode == InputMode::CompilerWithASTImport, ""); + map sourceJsons; map tmpSources; @@ -711,6 +737,8 @@ bool CommandLineInterface::compile() void CommandLineInterface::handleCombinedJSON() { + solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); + if (!m_options.compiler.combinedJsonRequests.has_value()) return; @@ -801,6 +829,8 @@ void CommandLineInterface::handleCombinedJSON() void CommandLineInterface::handleAst() { + solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); + if (!m_options.compiler.outputs.astCompactJson) return; @@ -848,6 +878,8 @@ bool CommandLineInterface::actOnInput() bool CommandLineInterface::link() { + solAssert(m_options.input.mode == InputMode::Linker, ""); + // Map from how the libraries will be named inside the bytecode to their addresses. map librariesReplacements; int const placeholderSize = 40; // 20 bytes or 40 hex characters @@ -911,6 +943,8 @@ bool CommandLineInterface::link() void CommandLineInterface::writeLinkedFiles() { + solAssert(m_options.input.mode == InputMode::Linker, ""); + for (auto const& src: m_fileReader.sourceCodes()) if (src.first == g_stdinFileName) sout() << src.second << endl; @@ -946,6 +980,8 @@ string CommandLineInterface::objectWithLinkRefsHex(evmasm::LinkerObject const& _ bool CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul::AssemblyStack::Machine _targetMachine) { + solAssert(m_options.input.mode == InputMode::Assembler, ""); + bool successful = true; map assemblyStacks; for (auto const& src: m_fileReader.sourceCodes()) @@ -1088,6 +1124,8 @@ bool CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul: void CommandLineInterface::outputCompilationResults() { + solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); + handleCombinedJSON(); // do we need AST output? From 30796b8957da1fae59150fa8a120d339f7e7f116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 16 Sep 2021 14:15:17 +0200 Subject: [PATCH 122/232] Split CommandLineParser::parse() into smaller functions --- solc/CommandLineParser.cpp | 61 ++++++++++++++++++++++++++------------ solc/CommandLineParser.h | 20 ++++++++++++- 2 files changed, 61 insertions(+), 20 deletions(-) diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 220f0e393..dbfb46756 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -323,6 +323,16 @@ OptimiserSettings CommandLineOptions::optimiserSettings() const return settings; } +bool CommandLineParser::parse(int _argc, char const* const* _argv, bool _interactiveTerminal) +{ + m_hasOutput = false; + + if (!parseArgs(_argc, _argv, _interactiveTerminal)) + return false; + + return processArgs(); +} + bool CommandLineParser::parseInputPathsAndRemappings() { m_options.input.ignoreMissingFiles = (m_args.count(g_strIgnoreMissingFiles) > 0); @@ -478,10 +488,8 @@ bool CommandLineParser::parseLibraryOption(string const& _input) return true; } -bool CommandLineParser::parse(int _argc, char const* const* _argv, bool interactiveTerminal) +po::options_description CommandLineParser::optionsDescription() { - m_hasOutput = false; - // Declare the supported options. po::options_description desc((R"(solc, the Solidity commandline compiler. @@ -780,12 +788,22 @@ General Information)").c_str(), ; desc.add(smtCheckerOptions); - po::options_description allOptions = desc; - allOptions.add_options()(g_strInputFile.c_str(), po::value>(), "input file"); + desc.add_options()(g_strInputFile.c_str(), po::value>(), "input file"); + return desc; +} +po::positional_options_description CommandLineParser::positionalOptionsDescription() +{ // All positional options should be interpreted as input files po::positional_options_description filesPositions; filesPositions.add(g_strInputFile.c_str(), -1); + return filesPositions; +} + +bool CommandLineParser::parseArgs(int _argc, char const* const* _argv, bool _interactiveTerminal) +{ + po::options_description allOptions = optionsDescription(); + po::positional_options_description filesPositions = positionalOptionsDescription(); // parse the compiler arguments try @@ -801,6 +819,25 @@ General Information)").c_str(), return false; } + if (m_args.count(g_strHelp) || (_interactiveTerminal && _argc == 1)) + { + sout() << allOptions; + return false; + } + + if (m_args.count(g_strVersion)) + printVersionAndExit(); + + if (m_args.count(g_strLicense)) + printLicenseAndExit(); + + po::notify(m_args); + + return true; +} + +bool CommandLineParser::processArgs() +{ if (!checkMutuallyExclusive({g_strColor, g_strNoColor})) return false; @@ -826,18 +863,6 @@ General Information)").c_str(), m_options.formatting.withErrorIds = m_args.count(g_strErrorIds); - if (m_args.count(g_strHelp) || (interactiveTerminal && _argc == 1)) - { - sout() << desc; - return false; - } - - if (m_args.count(g_strVersion)) - printVersionAndExit(); - - if (m_args.count(g_strLicense)) - printLicenseAndExit(); - if (m_args.count(g_strRevertStrings)) { string revertStringsString = m_args[g_strRevertStrings].as(); @@ -895,8 +920,6 @@ General Information)").c_str(), m_options.compiler.estimateGas = (m_args.count(g_strGas) > 0); - po::notify(m_args); - if (m_args.count(g_strBasePath)) m_options.input.basePath = m_args[g_strBasePath].as(); diff --git a/solc/CommandLineParser.h b/solc/CommandLineParser.h index ac80f6f0d..41aaab71b 100644 --- a/solc/CommandLineParser.h +++ b/solc/CommandLineParser.h @@ -195,7 +195,7 @@ public: /// CommandLineOptions structure has been fully initialized. false if there were errors - in /// this case CommandLineOptions may be only partially filled out. May also return false if /// there is not further processing necessary and the program should just exit. - bool parse(int _argc, char const* const* _argv, bool interactiveTerminal); + bool parse(int _argc, char const* const* _argv, bool _interactiveTerminal); CommandLineOptions const& options() const { return m_options; } @@ -203,6 +203,24 @@ public: bool hasOutput() const { return m_hasOutput; } private: + /// @returns a specification of all named command-line options accepted by the compiler. + /// The object can be used to parse command-line arguments or to generate the help screen. + static boost::program_options::options_description optionsDescription(); + + /// @returns a specification of all positional command-line arguments accepted by the compiler. + /// The object can be used to parse command-line arguments or to generate the help screen. + static boost::program_options::positional_options_description positionalOptionsDescription(); + + /// Uses boost::program_options to parse the command-line arguments and leaves the result in @a m_args. + /// Also handles the arguments that result in information being printed followed by immediate exit. + /// @returns false if parsing fails due to syntactical errors or the arguments not matching the description. + bool parseArgs(int _argc, char const* const* _argv, bool _interactiveTerminal); + + /// Validates parsed arguments stored in @a m_args and fills out the internal CommandLineOptions + /// structure. + /// @return false if there are any validation errors, true otherwise. + bool processArgs(); + /// Parses the value supplied to --combined-json. /// @return false if there are any validation errors, true otherwise. bool parseCombinedJsonOption(); From 4a8a003b3d937bd65c8610258e865a3bc51ac9a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 16 Sep 2021 14:21:56 +0200 Subject: [PATCH 123/232] CommandLineParser: Initialize inputMode and perform generic validations earlier --- solc/CommandLineParser.cpp | 102 ++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index dbfb46756..a72a010ab 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -838,6 +838,37 @@ bool CommandLineParser::parseArgs(int _argc, char const* const* _argv, bool _int bool CommandLineParser::processArgs() { + if (!checkMutuallyExclusive({ + g_strStandardJSON, + g_strLink, + g_strAssemble, + g_strStrictAssembly, + g_strYul, + g_strImportAst, + })) + return false; + + if (m_args.count(g_strStandardJSON) > 0) + m_options.input.mode = InputMode::StandardJson; + else if (m_args.count(g_strAssemble) > 0 || m_args.count(g_strStrictAssembly) > 0 || m_args.count(g_strYul) > 0) + m_options.input.mode = InputMode::Assembler; + else if (m_args.count(g_strLink) > 0) + m_options.input.mode = InputMode::Linker; + else if (m_args.count(g_strImportAst) > 0) + m_options.input.mode = InputMode::CompilerWithASTImport; + else + m_options.input.mode = InputMode::Compiler; + + if ( + m_args.count(g_strExperimentalViaIR) > 0 && + m_options.input.mode != InputMode::Compiler && + m_options.input.mode != InputMode::CompilerWithASTImport + ) + { + serr() << "The option --" << g_strExperimentalViaIR << " is only supported in the compiler mode." << endl; + return false; + } + if (!checkMutuallyExclusive({g_strColor, g_strNoColor})) return false; @@ -856,6 +887,26 @@ bool CommandLineParser::processArgs() if (!checkMutuallyExclusive({g_strStopAfter, option})) return false; + if ( + m_options.input.mode != InputMode::Compiler && + m_options.input.mode != InputMode::CompilerWithASTImport && + m_options.input.mode != InputMode::Assembler + ) + { + if (!m_args[g_strOptimizeRuns].defaulted()) + { + serr() << "Option --" << g_strOptimizeRuns << " is only valid in compiler and assembler modes." << endl; + return false; + } + + for (string const& option: {g_strOptimize, g_strNoOptimizeYul, g_strOptimizeYul, g_strYulOptimizations}) + if (m_args.count(option) > 0) + { + serr() << "Option --" << option << " is only valid in compiler and assembler modes." << endl; + return false; + } + } + if (m_args.count(g_strColor) > 0) m_options.formatting.coloredOutput = true; else if (m_args.count(g_strNoColor) > 0) @@ -950,60 +1001,9 @@ bool CommandLineParser::processArgs() m_options.output.stopAfter = CompilerStack::State::Parsed; } - if (!checkMutuallyExclusive({ - g_strStandardJSON, - g_strLink, - g_strAssemble, - g_strStrictAssembly, - g_strYul, - g_strImportAst, - })) - return false; - - if (m_args.count(g_strStandardJSON) > 0) - m_options.input.mode = InputMode::StandardJson; - else if (m_args.count(g_strAssemble) > 0 || m_args.count(g_strStrictAssembly) > 0 || m_args.count(g_strYul) > 0) - m_options.input.mode = InputMode::Assembler; - else if (m_args.count(g_strLink) > 0) - m_options.input.mode = InputMode::Linker; - else if (m_args.count(g_strImportAst) > 0) - m_options.input.mode = InputMode::CompilerWithASTImport; - else - m_options.input.mode = InputMode::Compiler; - - if ( - m_args.count(g_strExperimentalViaIR) > 0 && - m_options.input.mode != InputMode::Compiler && - m_options.input.mode != InputMode::CompilerWithASTImport - ) - { - serr() << "The option --" << g_strExperimentalViaIR << " is only supported in the compiler mode." << endl; - return false; - } - if (!parseInputPathsAndRemappings()) return false; - if ( - m_options.input.mode != InputMode::Compiler && - m_options.input.mode != InputMode::CompilerWithASTImport && - m_options.input.mode != InputMode::Assembler - ) - { - if (!m_args[g_strOptimizeRuns].defaulted()) - { - serr() << "Option --" << g_strOptimizeRuns << " is only valid in compiler and assembler modes." << endl; - return false; - } - - for (string const& option: {g_strOptimize, g_strNoOptimizeYul, g_strOptimizeYul, g_strYulOptimizations}) - if (m_args.count(option) > 0) - { - serr() << "Option --" << option << " is only valid in compiler and assembler modes." << endl; - return false; - } - } - if (m_options.input.mode == InputMode::StandardJson) return true; From 588ec39eef280a8d7af72b01bfa9f93431afa616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 13 Sep 2021 12:15:18 +0200 Subject: [PATCH 124/232] SMTSolverChoice: Make more members const/noexcept --- libsmtutil/SolverInterface.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libsmtutil/SolverInterface.h b/libsmtutil/SolverInterface.h index 21648c245..3737013b6 100644 --- a/libsmtutil/SolverInterface.h +++ b/libsmtutil/SolverInterface.h @@ -42,11 +42,11 @@ struct SMTSolverChoice bool smtlib2 = false; bool z3 = false; - static constexpr SMTSolverChoice All() { return {true, true, true}; } - static constexpr SMTSolverChoice CVC4() { return {true, false, false}; } - static constexpr SMTSolverChoice SMTLIB2() { return {false, true, false}; } - static constexpr SMTSolverChoice Z3() { return {false, false, true}; } - static constexpr SMTSolverChoice None() { return {false, false, false}; } + static constexpr SMTSolverChoice All() noexcept { return {true, true, true}; } + static constexpr SMTSolverChoice CVC4() noexcept { return {true, false, false}; } + static constexpr SMTSolverChoice SMTLIB2() noexcept { return {false, true, false}; } + static constexpr SMTSolverChoice Z3() noexcept { return {false, false, true}; } + static constexpr SMTSolverChoice None() noexcept { return {false, false, false}; } static std::optional fromString(std::string const& _solvers) { @@ -101,9 +101,9 @@ struct SMTSolverChoice return true; } - bool none() { return !some(); } - bool some() { return cvc4 || smtlib2 || z3; } - bool all() { return cvc4 && smtlib2 && z3; } + bool none() const noexcept { return !some(); } + bool some() const noexcept { return cvc4 || smtlib2 || z3; } + bool all() const noexcept { return cvc4 && smtlib2 && z3; } }; enum class CheckResult From b3a513d3b69bf906e206de45ac4f586b389d4481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 17 Sep 2021 19:41:34 +0200 Subject: [PATCH 125/232] SMTSolverChoice: Rewrite operator & not to modify its argument --- libsmtutil/SolverInterface.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libsmtutil/SolverInterface.h b/libsmtutil/SolverInterface.h index 3737013b6..e5cf33ece 100644 --- a/libsmtutil/SolverInterface.h +++ b/libsmtutil/SolverInterface.h @@ -65,7 +65,7 @@ struct SMTSolverChoice return solvers; } - SMTSolverChoice& operator&(SMTSolverChoice const& _other) + SMTSolverChoice& operator&=(SMTSolverChoice const& _other) { cvc4 &= _other.cvc4; smtlib2 &= _other.smtlib2; @@ -73,9 +73,10 @@ struct SMTSolverChoice return *this; } - SMTSolverChoice& operator&=(SMTSolverChoice const& _other) + SMTSolverChoice operator&(SMTSolverChoice _other) const noexcept { - return *this & _other; + _other &= *this; + return _other; } bool operator!=(SMTSolverChoice const& _other) const noexcept { return !(*this == _other); } From a9b5835e5de85e8532bcba39b1a621d6a53cf021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 17 Sep 2021 20:53:32 +0200 Subject: [PATCH 126/232] AsmPrinter: Don't include whitespace after @src if there's no code snippet --- libyul/AsmPrinter.cpp | 2 +- .../standard_yul_source_locations/output.json | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libyul/AsmPrinter.cpp b/libyul/AsmPrinter.cpp index 6a764ee16..c8f169cd1 100644 --- a/libyul/AsmPrinter.cpp +++ b/libyul/AsmPrinter.cpp @@ -293,7 +293,7 @@ string AsmPrinter::formatSourceLocation( ":" + to_string(_location.end); - return joinHumanReadable(vector{sourceLocation, solidityCodeSnippet}, " "); + return sourceLocation + (solidityCodeSnippet.empty() ? "" : " ") + solidityCodeSnippet; } string AsmPrinter::formatDebugData(shared_ptr const& _debugData, bool _statement) diff --git a/test/cmdlineTests/standard_yul_source_locations/output.json b/test/cmdlineTests/standard_yul_source_locations/output.json index 485380625..0ba3b09a3 100644 --- a/test/cmdlineTests/standard_yul_source_locations/output.json +++ b/test/cmdlineTests/standard_yul_source_locations/output.json @@ -599,15 +599,15 @@ object \"C_54\" { let newFreePtr := add(160, and(add(argSize, 31), not(31))) if or(gt(newFreePtr, sub(shl(64, 1), 1)), lt(newFreePtr, 160)) { - mstore(/** @src -1:-1:-1 */ 0, /** @src 0:79:435 \"contract C...\" */ shl(224, 0x4e487b71)) + mstore(/** @src -1:-1:-1 */ 0, /** @src 0:79:435 \"contract C...\" */ shl(224, 0x4e487b71)) mstore(4, 0x41) - revert(/** @src -1:-1:-1 */ 0, /** @src 0:79:435 \"contract C...\" */ 0x24) + revert(/** @src -1:-1:-1 */ 0, /** @src 0:79:435 \"contract C...\" */ 0x24) } mstore(64, newFreePtr) codecopy(160, programSize, argSize) if slt(argSize, 32) { - revert(/** @src -1:-1:-1 */ 0, 0) + revert(/** @src -1:-1:-1 */ 0, 0) } /// @src 0:79:435 \"contract C...\" constructor_C(mload(160)) @@ -1431,15 +1431,15 @@ object \"D_72\" { let newFreePtr := add(160, and(add(argSize, 31), not(31))) if or(gt(newFreePtr, sub(shl(64, 1), 1)), lt(newFreePtr, 160)) { - mstore(/** @src -1:-1:-1 */ 0, /** @src 1:91:166 \"contract D is C(3)...\" */ shl(224, 0x4e487b71)) + mstore(/** @src -1:-1:-1 */ 0, /** @src 1:91:166 \"contract D is C(3)...\" */ shl(224, 0x4e487b71)) mstore(4, 0x41) - revert(/** @src -1:-1:-1 */ 0, /** @src 1:91:166 \"contract D is C(3)...\" */ 0x24) + revert(/** @src -1:-1:-1 */ 0, /** @src 1:91:166 \"contract D is C(3)...\" */ 0x24) } mstore(64, newFreePtr) codecopy(160, programSize, argSize) if slt(argSize, 32) { - revert(/** @src -1:-1:-1 */ 0, 0) + revert(/** @src -1:-1:-1 */ 0, 0) } /// @src 1:91:166 \"contract D is C(3)...\" constructor_D(mload(160)) From 2052307d33dd0dbbf58c9b80003a718ce5f9b000 Mon Sep 17 00:00:00 2001 From: Andrew Lyndem Date: Sat, 18 Sep 2021 15:19:56 +0530 Subject: [PATCH 127/232] Update README.md Hyperlink correction. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index abc8616e0..ccd8dc634 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ Please follow the if you want to help. You can find our current feature and bug priorities for forthcoming -releases [in the projects section](https://github.com/ethereum/solidity/projects). +releases in the [projects section](https://github.com/ethereum/solidity/projects). ## Maintainers * [@axic](https://github.com/axic) From f47e918caaa49d6423564462c724dd0ff9dd577c Mon Sep 17 00:00:00 2001 From: Sean Hawkes Date: Sat, 18 Sep 2021 04:55:50 -0500 Subject: [PATCH 128/232] Moved program_options add_options to a helper function to allow defaults to be set by derived class constructor before immutable options are created by parent --- test/Common.cpp | 5 +++++ test/Common.h | 1 + test/tools/IsolTestOptions.cpp | 10 +++++++--- test/tools/IsolTestOptions.h | 1 + 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/test/Common.cpp b/test/Common.cpp index 9b2cfbb96..4be8e1625 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -91,6 +91,11 @@ CommonOptions::CommonOptions(std::string _caption): po::options_description::m_default_line_length, po::options_description::m_default_line_length - 23 ) +{ + +} + +void CommonOptions::addOptions() { options.add_options() ("evm-version", po::value(&evmVersionString), "which evm version to use") diff --git a/test/Common.h b/test/Common.h index c8a863d8c..4d97d720d 100644 --- a/test/Common.h +++ b/test/Common.h @@ -70,6 +70,7 @@ struct CommonOptions langutil::EVMVersion evmVersion() const; + virtual addOptions(); virtual bool parse(int argc, char const* const* argv); // Throws a ConfigException on error virtual void validate() const; diff --git a/test/tools/IsolTestOptions.cpp b/test/tools/IsolTestOptions.cpp index aaa087e47..487c7e8c7 100644 --- a/test/tools/IsolTestOptions.cpp +++ b/test/tools/IsolTestOptions.cpp @@ -58,6 +58,13 @@ std::string editorPath() IsolTestOptions::IsolTestOptions(std::string* _editor): CommonOptions(description) +{ + enforceViaYul = true; + enforceGasTest = (evmVersion() == langutil::EVMVersion{}); + enforceGasTestMinValue = 100000; +} + +void IsolTestOptions::addOptions() { options.add_options() ("editor", po::value(_editor)->default_value(editorPath()), "Path to editor for opening test files.") @@ -76,9 +83,6 @@ bool IsolTestOptions::parse(int _argc, char const* const* _argv) std::cout << options << std::endl; return false; } - enforceViaYul = true; - enforceGasTest = (evmVersion() == langutil::EVMVersion{}); - enforceGasTestMinValue = 100000; return res; } diff --git a/test/tools/IsolTestOptions.h b/test/tools/IsolTestOptions.h index aa9eb2564..7c1a5ebe1 100644 --- a/test/tools/IsolTestOptions.h +++ b/test/tools/IsolTestOptions.h @@ -35,6 +35,7 @@ struct IsolTestOptions: CommonOptions std::string testFilter = std::string{}; IsolTestOptions(std::string* _editor); + void addOptions() override; bool parse(int _argc, char const* const* _argv) override; void validate() const override; }; From ae7c617711cd8b93fa4d42b13791c2e8c5d4ca29 Mon Sep 17 00:00:00 2001 From: Sean Hawkes Date: Sat, 18 Sep 2021 05:43:09 -0500 Subject: [PATCH 129/232] Added call to addOptions virtual helper in CommonOptions::parse to add options from base/derived classes, modified interface of IsolTestOptions to include editor member variable set based on provided parameter in constructor as it is now needed by addOptions helper function --- test/Common.cpp | 1 + test/Common.h | 2 +- test/tools/IsolTestOptions.cpp | 1 + test/tools/IsolTestOptions.h | 3 ++- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/test/Common.cpp b/test/Common.cpp index 4be8e1625..5a5a253ae 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -144,6 +144,7 @@ void CommonOptions::validate() const bool CommonOptions::parse(int argc, char const* const* argv) { po::variables_map arguments; + addOptions(); po::command_line_parser cmdLineParser(argc, argv); cmdLineParser.options(options); diff --git a/test/Common.h b/test/Common.h index 4d97d720d..f7c8fa733 100644 --- a/test/Common.h +++ b/test/Common.h @@ -70,7 +70,7 @@ struct CommonOptions langutil::EVMVersion evmVersion() const; - virtual addOptions(); + virtual void addOptions(); virtual bool parse(int argc, char const* const* argv); // Throws a ConfigException on error virtual void validate() const; diff --git a/test/tools/IsolTestOptions.cpp b/test/tools/IsolTestOptions.cpp index 487c7e8c7..bcbee4463 100644 --- a/test/tools/IsolTestOptions.cpp +++ b/test/tools/IsolTestOptions.cpp @@ -59,6 +59,7 @@ std::string editorPath() IsolTestOptions::IsolTestOptions(std::string* _editor): CommonOptions(description) { + editor = _editor; enforceViaYul = true; enforceGasTest = (evmVersion() == langutil::EVMVersion{}); enforceGasTestMinValue = 100000; diff --git a/test/tools/IsolTestOptions.h b/test/tools/IsolTestOptions.h index 7c1a5ebe1..4deb5f9aa 100644 --- a/test/tools/IsolTestOptions.h +++ b/test/tools/IsolTestOptions.h @@ -33,8 +33,9 @@ struct IsolTestOptions: CommonOptions bool noColor = false; bool acceptUpdates = false; std::string testFilter = std::string{}; + std::string editor = std::string{}; - IsolTestOptions(std::string* _editor); + explicit IsolTestOptions(const std::string* _editor); void addOptions() override; bool parse(int _argc, char const* const* _argv) override; void validate() const override; From 76fa00abedac5f1399a88635ac7b96ecaa0dec42 Mon Sep 17 00:00:00 2001 From: Sean Hawkes Date: Sat, 18 Sep 2021 06:22:27 -0500 Subject: [PATCH 130/232] Added invocation of base class addOptions in derived to populate list with common and derived options, fixed errors with editor member variable type mismatch --- test/tools/IsolTestOptions.cpp | 3 ++- test/tools/IsolTestOptions.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test/tools/IsolTestOptions.cpp b/test/tools/IsolTestOptions.cpp index bcbee4463..44cf90655 100644 --- a/test/tools/IsolTestOptions.cpp +++ b/test/tools/IsolTestOptions.cpp @@ -67,8 +67,9 @@ IsolTestOptions::IsolTestOptions(std::string* _editor): void IsolTestOptions::addOptions() { + CommonOptions::addOptions(); options.add_options() - ("editor", po::value(_editor)->default_value(editorPath()), "Path to editor for opening test files.") + ("editor", po::value(editor)->default_value(editorPath()), "Path to editor for opening test files.") ("help", po::bool_switch(&showHelp), "Show this help screen.") ("no-color", po::bool_switch(&noColor), "Don't use colors.") ("accept-updates", po::bool_switch(&acceptUpdates), "Automatically accept expectation updates.") diff --git a/test/tools/IsolTestOptions.h b/test/tools/IsolTestOptions.h index 4deb5f9aa..f889f5b8f 100644 --- a/test/tools/IsolTestOptions.h +++ b/test/tools/IsolTestOptions.h @@ -33,9 +33,9 @@ struct IsolTestOptions: CommonOptions bool noColor = false; bool acceptUpdates = false; std::string testFilter = std::string{}; - std::string editor = std::string{}; + std::string* editor = nullptr; - explicit IsolTestOptions(const std::string* _editor); + explicit IsolTestOptions(std::string* _editor); void addOptions() override; bool parse(int _argc, char const* const* _argv) override; void validate() const override; From f2e59923ab4c632da6f12b16ddd62f50c6ec4578 Mon Sep 17 00:00:00 2001 From: Sean Hawkes Date: Sat, 18 Sep 2021 06:59:37 -0500 Subject: [PATCH 131/232] Added call to CommonOptions base class validate method to derived IsolTestOptions validate method to validate against both common and extended options --- test/tools/IsolTestOptions.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/tools/IsolTestOptions.cpp b/test/tools/IsolTestOptions.cpp index 44cf90655..7e38b55b2 100644 --- a/test/tools/IsolTestOptions.cpp +++ b/test/tools/IsolTestOptions.cpp @@ -91,6 +91,7 @@ bool IsolTestOptions::parse(int _argc, char const* const* _argv) void IsolTestOptions::validate() const { + CommonOptions::validate(); static std::string filterString{"[a-zA-Z0-9_/*]*"}; static std::regex filterExpression{filterString}; assertThrow( From 0ac441ac73f19b54ceb37ba8fa37134188fbd605 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Wed, 15 Sep 2021 16:52:56 -0700 Subject: [PATCH 132/232] Clarify interpretation of literals. This is based on discussions on Gitter. --- docs/yul.rst | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/docs/yul.rst b/docs/yul.rst index d0126e65b..e4819ff22 100644 --- a/docs/yul.rst +++ b/docs/yul.rst @@ -174,9 +174,32 @@ whitespace, i.e. there is no terminating ``;`` or newline required. Literals -------- -As literals, you can use integer constants in decimal or hexadecimal notation -or strings as ASCII (`"abc"`) or HEX strings (`hex"616263"`) of up to -32 bytes length. +As literals, you can use: + +- Integer constants in decimal or hexadecimal notation. + +- ASCII strings (e.g. ``"abc"``), which may contain hex escapes ``\xNN`` and Unicode escapes ``\uNNNN`` where ``N`` are hexadecimal digits. + +- Hex strings (e.g. ``hex"616263"``). + +In the EVM dialect of Yul, literals represent 256-bit words as follows: + +- Decimal or hexadecimal constants must be less than ``2**256``. + They represent the 256-bit word with that value as an unsigned integer in big endian encoding. + +- An ASCII string is first viewed as a byte sequence, by viewing + a non-escape ASCII character as a single byte whose value is the ASCII code, + an escape ``\xNN`` as single byte with that value, and + an escape ``\uNNNN`` as the UTF-8 sequence of bytes for that code point. + The byte sequence must not exceed 32 bytes. + The byte sequence is padded with zeros on the right to reach 32 bytes in length; + in other words, the string is stored left-aligned. + The padded byte sequence represents a 256-bit word whose most significant 8 bits are the ones from the first byte, + i.e. the bytes are interpreted in big endian form. + +- A hex string is first viewed as a byte sequence, by viewing + each pair of contiguous hex digits as a byte. + The byte sequence must not exceed 32 bytes (i.e. 64 hex digits), and is treated as above. When compiling for the EVM, this will be translated into an appropriate ``PUSHi`` instruction. In the following example, @@ -184,8 +207,7 @@ appropriate ``PUSHi`` instruction. In the following example, bitwise ``and`` with the string "abc" is computed. The final value is assigned to a local variable called ``x``. -Strings are stored left-aligned and cannot be longer than 32 bytes. -The limit does not apply to string literals passed to builtin functions that require +The 32-byte limit above does not apply to string literals passed to builtin functions that require literal arguments (e.g. ``setimmutable`` or ``loadimmutable``). Those strings never end up in the generated bytecode. From a875d1225ad10774b174919209812166e80dfa5c Mon Sep 17 00:00:00 2001 From: Sean Hawkes Date: Sat, 18 Sep 2021 07:13:04 -0500 Subject: [PATCH 133/232] Explicity set default values for program options based on initialized values from constructor --- test/Common.cpp | 24 ++++++++++++------------ test/tools/IsolTestOptions.cpp | 6 +++--- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/test/Common.cpp b/test/Common.cpp index 5a5a253ae..b8593490e 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -95,23 +95,23 @@ CommonOptions::CommonOptions(std::string _caption): } -void CommonOptions::addOptions() +void CommonOptions::addOptions() { options.add_options() ("evm-version", po::value(&evmVersionString), "which evm version to use") ("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), "tries to automatically find an ewasm vm and enable ewasm test-execution.") - ("no-semantic-tests", po::bool_switch(&disableSemanticTests), "disable semantic tests") - ("no-smt", po::bool_switch(&disableSMT), "disable SMT checker") - ("optimize", po::bool_switch(&optimize), "enables optimization") - ("enforce-via-yul", po::bool_switch(&enforceViaYul), "Enforce compiling all tests via yul to see if additional tests can be activated.") - ("enforce-compile-to-ewasm", po::bool_switch(&enforceCompileToEwasm), "Enforce compiling all tests to Ewasm to see if additional tests can be activated.") - ("enforce-gas-cost", po::bool_switch(&enforceGasTest), "Enforce checking gas cost in semantic tests.") - ("enforce-gas-cost-min-value", po::value(&enforceGasTestMinValue), "Threshold value to enforce adding gas checks to a test.") - ("abiencoderv1", po::bool_switch(&useABIEncoderV1), "enables abi encoder v1") - ("show-messages", po::bool_switch(&showMessages), "enables message output") - ("show-metadata", po::bool_switch(&showMetadata), "enables metadata output"); + ("ewasm", po::bool_switch(&ewasm)->default_value(ewasm), "tries to automatically find an ewasm vm and enable ewasm test-execution.") + ("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") + ("enforce-via-yul", po::bool_switch(&enforceViaYul)->default_value(enforceViaYul), "Enforce compiling all tests via yul to see if additional tests can be activated.") + ("enforce-compile-to-ewasm", po::bool_switch(&enforceCompileToEwasm)->default_value(enforceCompileToEwasm), "Enforce compiling all tests to Ewasm to see if additional tests can be activated.") + ("enforce-gas-cost", po::bool_switch(&enforceGasTest)->default_value(enforceGasTest), "Enforce checking gas cost in semantic tests.") + ("enforce-gas-cost-min-value", po::value(&enforceGasTestMinValue)->default_value(enforceGasTestMinValue), "Threshold value to enforce adding gas checks to a test.") + ("abiencoderv1", po::bool_switch(&useABIEncoderV1)->default_value(useABIEncoderV1), "enables abi encoder v1") + ("show-messages", po::bool_switch(&showMessages)->default_value(showMessages), "enables message output") + ("show-metadata", po::bool_switch(&showMetadata)->default_value(showMetadata), "enables metadata output"); } void CommonOptions::validate() const diff --git a/test/tools/IsolTestOptions.cpp b/test/tools/IsolTestOptions.cpp index 7e38b55b2..3aecaeefa 100644 --- a/test/tools/IsolTestOptions.cpp +++ b/test/tools/IsolTestOptions.cpp @@ -70,9 +70,9 @@ void IsolTestOptions::addOptions() CommonOptions::addOptions(); options.add_options() ("editor", po::value(editor)->default_value(editorPath()), "Path to editor for opening test files.") - ("help", po::bool_switch(&showHelp), "Show this help screen.") - ("no-color", po::bool_switch(&noColor), "Don't use colors.") - ("accept-updates", po::bool_switch(&acceptUpdates), "Automatically accept expectation updates.") + ("help", po::bool_switch(&showHelp)->default_value(showHelp), "Show this help screen.") + ("no-color", po::bool_switch(&noColor)->default_value(noColor), "Don't use colors.") + ("accept-updates", po::bool_switch(&acceptUpdates)->default_value(acceptUpdates), "Automatically accept expectation updates.") ("test,t", po::value(&testFilter)->default_value("*/*"), "Filters which test units to include."); } From 5edabc014d34102827e78470acf96eecac67fb2a Mon Sep 17 00:00:00 2001 From: hawkess Date: Mon, 20 Sep 2021 13:17:35 -0500 Subject: [PATCH 134/232] Changed enforce-gas-cost and enforce-via-yul to accept explicit arguments --- test/Common.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Common.cpp b/test/Common.cpp index b8593490e..2a663aa1b 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -105,9 +105,9 @@ void CommonOptions::addOptions() ("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") - ("enforce-via-yul", po::bool_switch(&enforceViaYul)->default_value(enforceViaYul), "Enforce compiling all tests via yul to see if additional tests can be activated.") + ("enforce-via-yul", po::value(&enforceViaYul)->default_value(enforceViaYul)->implicit_value(true), "Enforce compiling all tests via yul to see if additional tests can be activated.") ("enforce-compile-to-ewasm", po::bool_switch(&enforceCompileToEwasm)->default_value(enforceCompileToEwasm), "Enforce compiling all tests to Ewasm to see if additional tests can be activated.") - ("enforce-gas-cost", po::bool_switch(&enforceGasTest)->default_value(enforceGasTest), "Enforce checking gas cost in semantic tests.") + ("enforce-gas-cost", po::value(&enforceGasTest)->default_value(enforceGasTest)->implicit_value(true), "Enforce checking gas cost in semantic tests.") ("enforce-gas-cost-min-value", po::value(&enforceGasTestMinValue)->default_value(enforceGasTestMinValue), "Threshold value to enforce adding gas checks to a test.") ("abiencoderv1", po::bool_switch(&useABIEncoderV1)->default_value(useABIEncoderV1), "enables abi encoder v1") ("show-messages", po::bool_switch(&showMessages)->default_value(showMessages), "enables message output") From d86347cf7e399a0a96d105e1ff5a817415e93724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 17 Sep 2021 21:38:08 +0200 Subject: [PATCH 135/232] Rename existing debug info tests to match the naming convention --- .../args | 0 .../input.sol | 0 .../output | 24 +++++++++---------- .../input.json | 0 .../output.json | 0 .../input.json | 0 .../output.json | 0 7 files changed, 12 insertions(+), 12 deletions(-) rename test/cmdlineTests/{yul_source_locations_code_snippet_escaping => debug_info_in_yul_snippet_escaping}/args (100%) rename test/cmdlineTests/{yul_source_locations_code_snippet_escaping => debug_info_in_yul_snippet_escaping}/input.sol (100%) rename test/cmdlineTests/{yul_source_locations_code_snippet_escaping => debug_info_in_yul_snippet_escaping}/output (96%) rename test/cmdlineTests/{yul_source_locations_in_asm => standard_debug_info_in_evm_asm_via_ir_location}/input.json (100%) rename test/cmdlineTests/{yul_source_locations_in_asm => standard_debug_info_in_evm_asm_via_ir_location}/output.json (100%) rename test/cmdlineTests/{standard_yul_source_locations => standard_debug_info_in_yul_location}/input.json (100%) rename test/cmdlineTests/{standard_yul_source_locations => standard_debug_info_in_yul_location}/output.json (100%) diff --git a/test/cmdlineTests/yul_source_locations_code_snippet_escaping/args b/test/cmdlineTests/debug_info_in_yul_snippet_escaping/args similarity index 100% rename from test/cmdlineTests/yul_source_locations_code_snippet_escaping/args rename to test/cmdlineTests/debug_info_in_yul_snippet_escaping/args diff --git a/test/cmdlineTests/yul_source_locations_code_snippet_escaping/input.sol b/test/cmdlineTests/debug_info_in_yul_snippet_escaping/input.sol similarity index 100% rename from test/cmdlineTests/yul_source_locations_code_snippet_escaping/input.sol rename to test/cmdlineTests/debug_info_in_yul_snippet_escaping/input.sol diff --git a/test/cmdlineTests/yul_source_locations_code_snippet_escaping/output b/test/cmdlineTests/debug_info_in_yul_snippet_escaping/output similarity index 96% rename from test/cmdlineTests/yul_source_locations_code_snippet_escaping/output rename to test/cmdlineTests/debug_info_in_yul_snippet_escaping/output index 9fea7f8cc..a9dc1a290 100644 --- a/test/cmdlineTests/yul_source_locations_code_snippet_escaping/output +++ b/test/cmdlineTests/debug_info_in_yul_snippet_escaping/output @@ -7,7 +7,7 @@ IR: *=====================================================*/ -/// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" +/// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "C_2" { code { /// @src 0:265:278 "contract C {}" @@ -38,7 +38,7 @@ object "C_2" { /// @src 0:265:278 "contract C {}" } - /// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" + /// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "C_2_deployed" { code { /// @src 0:265:278 "contract C {}" @@ -85,7 +85,7 @@ Optimized IR: * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" +/// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "C_2" { code { { @@ -97,7 +97,7 @@ object "C_2" { return(128, _1) } } - /// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" + /// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "C_2_deployed" { code { { @@ -119,7 +119,7 @@ IR: *=====================================================*/ -/// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" +/// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "D_27" { code { /// @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." @@ -150,7 +150,7 @@ object "D_27" { /// @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." } - /// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" + /// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "D_27_deployed" { code { /// @src 0:279:599 "contract D /** @src 0:96:165 \"contract D {...\" *\/ {..." @@ -376,7 +376,7 @@ object "D_27" { * !USE AT YOUR OWN RISK! * *=====================================================*/ - /// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" + /// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "C_2" { code { /// @src 0:265:278 "contract C {}" @@ -407,7 +407,7 @@ object "D_27" { /// @src 0:265:278 "contract C {}" } - /// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" + /// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "C_2_deployed" { code { /// @src 0:265:278 "contract C {}" @@ -459,7 +459,7 @@ Optimized IR: * !USE AT YOUR OWN RISK! * *=====================================================*/ -/// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" +/// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "D_27" { code { { @@ -471,7 +471,7 @@ object "D_27" { return(128, _1) } } - /// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" + /// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "D_27_deployed" { code { { @@ -550,7 +550,7 @@ object "D_27" { mstore(memPtr_1, 39) } } - /// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" + /// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "C_2" { code { { @@ -562,7 +562,7 @@ object "D_27" { return(128, _1) } } - /// @use-src 0:"yul_source_locations_code_snippet_escaping/input.sol" + /// @use-src 0:"debug_info_in_yul_snippet_escaping/input.sol" object "C_2_deployed" { code { { diff --git a/test/cmdlineTests/yul_source_locations_in_asm/input.json b/test/cmdlineTests/standard_debug_info_in_evm_asm_via_ir_location/input.json similarity index 100% rename from test/cmdlineTests/yul_source_locations_in_asm/input.json rename to test/cmdlineTests/standard_debug_info_in_evm_asm_via_ir_location/input.json diff --git a/test/cmdlineTests/yul_source_locations_in_asm/output.json b/test/cmdlineTests/standard_debug_info_in_evm_asm_via_ir_location/output.json similarity index 100% rename from test/cmdlineTests/yul_source_locations_in_asm/output.json rename to test/cmdlineTests/standard_debug_info_in_evm_asm_via_ir_location/output.json diff --git a/test/cmdlineTests/standard_yul_source_locations/input.json b/test/cmdlineTests/standard_debug_info_in_yul_location/input.json similarity index 100% rename from test/cmdlineTests/standard_yul_source_locations/input.json rename to test/cmdlineTests/standard_debug_info_in_yul_location/input.json diff --git a/test/cmdlineTests/standard_yul_source_locations/output.json b/test/cmdlineTests/standard_debug_info_in_yul_location/output.json similarity index 100% rename from test/cmdlineTests/standard_yul_source_locations/output.json rename to test/cmdlineTests/standard_debug_info_in_yul_location/output.json From 69e9531181566de1306d500ff62b0fd6ae9373c7 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 15 Sep 2021 19:06:35 +0100 Subject: [PATCH 136/232] Add JSON tests for unicode, all types, and conformance to ECMA-262/ECMA-404 Also avoid using toStyledString --- test/libsolidity/SolidityNatspecJSON.cpp | 8 +- test/libsolutil/JSON.cpp | 93 ++++++++++++++++++++++-- 2 files changed, 90 insertions(+), 11 deletions(-) diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index b295b8091..6ee55d586 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -63,8 +63,8 @@ public: BOOST_CHECK_MESSAGE( expectedDocumentation == generatedDocumentation, - "Expected:\n" << expectedDocumentation.toStyledString() << - "\n but got:\n" << generatedDocumentation.toStyledString() + "Expected:\n" << util::jsonPrettyPrint(expectedDocumentation) << + "\n but got:\n" << util::jsonPrettyPrint(generatedDocumentation) ); } @@ -2089,8 +2089,8 @@ BOOST_AUTO_TEST_CASE(dev_explicit_inehrit_complex) BOOST_CHECK_MESSAGE( expectedDocumentation == generatedDocumentation, - "Expected:\n" << expectedDocumentation.toStyledString() << - "\n but got:\n" << generatedDocumentation.toStyledString() + "Expected:\n" << util::jsonPrettyPrint(expectedDocumentation) << + "\n but got:\n" << util::jsonPrettyPrint(generatedDocumentation) ); } diff --git a/test/libsolutil/JSON.cpp b/test/libsolutil/JSON.cpp index 666397877..1b0ed9388 100644 --- a/test/libsolutil/JSON.cpp +++ b/test/libsolutil/JSON.cpp @@ -33,6 +33,48 @@ namespace solidity::util::test BOOST_AUTO_TEST_SUITE(JsonTest, *boost::unit_test::label("nooptions")) +BOOST_AUTO_TEST_CASE(json_types) +{ + auto check = [](Json::Value value, string const& expectation) { + BOOST_CHECK(jsonCompactPrint(value) == expectation); + }; + + Json::Value value; + BOOST_CHECK(value.empty()); + value = {}; + BOOST_CHECK(value.empty()); + value = Json::Value(); + BOOST_CHECK(value.empty()); + value = Json::nullValue; + BOOST_CHECK(value.empty()); + + check(value, "null"); + check({}, "null"); + check(Json::Value(), "null"); + check(Json::nullValue, "null"); + check(Json::objectValue, "{}"); + check(Json::arrayValue, "[]"); + check(Json::UInt(1), "1"); + check(Json::UInt(-1), "4294967295"); + check(Json::UInt64(1), "1"); + check(Json::UInt64(-1), "18446744073709551615"); + check(Json::LargestUInt(1), "1"); + check(Json::LargestUInt(-1), "18446744073709551615"); + check(Json::LargestUInt(0xffffffff), "4294967295"); + check(Json::Value("test"), "\"test\""); + check("test", "\"test\""); + check(true, "true"); + + value = Json::objectValue; + value["key"] = "value"; + check(value, "{\"key\":\"value\"}"); + + value = Json::arrayValue; + value.append(1); + value.append(2); + check(value, "[1,2]"); +} + BOOST_AUTO_TEST_CASE(json_pretty_print) { Json::Value json; @@ -43,6 +85,8 @@ BOOST_AUTO_TEST_CASE(json_pretty_print) json["1"] = 1; json["2"] = "2"; json["3"] = jsonChild; + json["4"] = "ऑ ऒ ओ औ क ख"; + json["5"] = "\xff"; BOOST_CHECK( "{\n" @@ -52,7 +96,9 @@ BOOST_AUTO_TEST_CASE(json_pretty_print) " {\n" " \"3.1\": \"3.1\",\n" " \"3.2\": 2\n" - " }\n" + " },\n" + " \"4\": \"\\u0911 \\u0912 \\u0913 \\u0914 \\u0915 \\u0916\",\n" + " \"5\": \"\\ufffd\"\n" "}" == jsonPrettyPrint(json)); } @@ -66,26 +112,32 @@ BOOST_AUTO_TEST_CASE(json_compact_print) json["1"] = 1; json["2"] = "2"; json["3"] = jsonChild; + json["4"] = "ऑ ऒ ओ औ क ख"; + json["5"] = "\xff"; - BOOST_CHECK("{\"1\":1,\"2\":\"2\",\"3\":{\"3.1\":\"3.1\",\"3.2\":2}}" == jsonCompactPrint(json)); + BOOST_CHECK("{\"1\":1,\"2\":\"2\",\"3\":{\"3.1\":\"3.1\",\"3.2\":2},\"4\":\"\\u0911 \\u0912 \\u0913 \\u0914 \\u0915 \\u0916\",\"5\":\"\\ufffd\"}" == jsonCompactPrint(json)); } BOOST_AUTO_TEST_CASE(parse_json_strict) { + // In this test we check conformance against JSON.parse (https://tc39.es/ecma262/multipage/structured-data.html#sec-json.parse) + // and ECMA-404 (https://www.ecma-international.org/publications-and-standards/standards/ecma-404/) + Json::Value json; std::string errors; - // just parse a valid json input + // Just parse a valid json input BOOST_CHECK(jsonParseStrict("{\"1\":1,\"2\":\"2\",\"3\":{\"3.1\":\"3.1\",\"3.2\":2}}", json, &errors)); BOOST_CHECK(json["1"] == 1); BOOST_CHECK(json["2"] == "2"); BOOST_CHECK(json["3"]["3.1"] == "3.1"); BOOST_CHECK(json["3"]["3.2"] == 2); - // trailing garbage is not allowed in strict-mode + // Trailing garbage is not allowed in ECMA-262 BOOST_CHECK(!jsonParseStrict("{\"1\":2,\"2\":\"2\",\"3\":{\"3.1\":\"3.1\",\"3.2\":3}}}}}}}}}}", json, &errors)); - // comments are allowed in strict-mode? - that's strange... + // Comments are not allowed in ECMA-262 + // ... but JSONCPP allows them BOOST_CHECK(jsonParseStrict( "{\"1\":3, // awesome comment\n\"2\":\"2\",\"3\":{\"3.1\":\"3.1\",\"3.2\":5}}", json, &errors )); @@ -94,15 +146,42 @@ BOOST_AUTO_TEST_CASE(parse_json_strict) BOOST_CHECK(json["3"]["3.1"] == "3.1"); BOOST_CHECK(json["3"]["3.2"] == 5); - // root element can only be object or array + // According to ECMA-404 object, array, number, string, true, false, null are allowed + // ... but JSONCPP disallows value types BOOST_CHECK(jsonParseStrict("[]", json, &errors)); + BOOST_CHECK(json.isArray()); BOOST_CHECK(jsonParseStrict("{}", json, &errors)); + BOOST_CHECK(json.isObject()); BOOST_CHECK(!jsonParseStrict("1", json, &errors)); + // BOOST_CHECK(json.isNumeric()); BOOST_CHECK(!jsonParseStrict("\"hello\"", json, &errors)); + // BOOST_CHECK(json.isString()); + BOOST_CHECK(!jsonParseStrict("true", json, &errors)); + // BOOST_CHECK(json.isBool()); + BOOST_CHECK(!jsonParseStrict("null", json, &errors)); + // BOOST_CHECK(json.isNull()); - // non-UTF-8 escapes allowed?? + // Single quotes are also disallowed by ECMA-404 + BOOST_CHECK(!jsonParseStrict("'hello'", json, &errors)); + // BOOST_CHECK(json.isString()); + + // Only string keys in objects are allowed in ECMA-404 + BOOST_CHECK(!jsonParseStrict("{ 42: \"hello\" }", json, &errors)); + + // According to ECMA-404 hex escape sequences are not allowed, only unicode (\uNNNN) and + // a few control characters (\b, \f, \n, \r, \t) + // + // More lenient parsers allow hex escapes as long as they translate to a valid UTF-8 encoding. + // + // ... but JSONCPP allows any hex escapes BOOST_CHECK(jsonParseStrict("[ \"\x80\xec\x80\" ]", json, &errors)); + BOOST_CHECK(json.isArray()); BOOST_CHECK(json[0] == "\x80\xec\x80"); + + // This would be valid more lenient parsers. + BOOST_CHECK(jsonParseStrict("[ \"\xF0\x9F\x98\x8A\" ]", json, &errors)); + BOOST_CHECK(json.isArray()); + BOOST_CHECK(json[0] == "😊"); } BOOST_AUTO_TEST_SUITE_END() From 55c64e3ca1688a45842a442c319c113154a741c4 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 15 Sep 2021 19:09:03 +0100 Subject: [PATCH 137/232] Always explicitly initialise Json objects --- libevmasm/Assembly.cpp | 8 +++--- libsolidity/interface/ABI.cpp | 17 ++++++------ libsolidity/interface/CompilerStack.cpp | 2 +- libsolidity/interface/Natspec.cpp | 11 +++++--- libsolidity/interface/StandardCompiler.cpp | 31 +++++++++++----------- 5 files changed, 36 insertions(+), 33 deletions(-) diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index acf655c82..2978fdcdb 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -200,7 +200,7 @@ string Assembly::assemblyString(StringMap const& _sourceCodes) const Json::Value Assembly::createJsonValue(string _name, int _source, int _begin, int _end, string _value, string _jumpType) { - Json::Value value; + Json::Value value{Json::objectValue}; value["name"] = _name; value["source"] = _source; value["begin"] = _begin; @@ -222,8 +222,9 @@ string Assembly::toStringInHex(u256 _value) Json::Value Assembly::assemblyJSON(map const& _sourceIndices) const { Json::Value root; + root[".code"] = Json::arrayValue; - Json::Value& collection = root[".code"] = Json::arrayValue; + Json::Value& collection = root[".code"]; for (AssemblyItem const& i: m_items) { int sourceIndex = -1; @@ -317,7 +318,8 @@ Json::Value Assembly::assemblyJSON(map const& _sourceIndices) if (!m_data.empty() || !m_subs.empty()) { - Json::Value& data = root[".data"] = Json::objectValue; + root[".data"] = Json::objectValue; + Json::Value& data = root[".data"]; for (auto const& i: m_data) if (u256(i.first) >= m_subs.size()) data[toStringInHex((u256)i.first)] = toHex(i.second); diff --git a/libsolidity/interface/ABI.cpp b/libsolidity/interface/ABI.cpp index c4a2dfe5c..cf395ffa0 100644 --- a/libsolidity/interface/ABI.cpp +++ b/libsolidity/interface/ABI.cpp @@ -56,7 +56,7 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef) FunctionType const* externalFunctionType = it.second->interfaceFunctionType(); solAssert(!!externalFunctionType, ""); - Json::Value method; + Json::Value method{Json::objectValue}; method["type"] = "function"; method["name"] = it.second->declaration().name(); method["stateMutability"] = stateMutabilityToString(externalFunctionType->stateMutability()); @@ -80,7 +80,7 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef) FunctionType constrType(*constructor); FunctionType const* externalFunctionType = constrType.interfaceFunctionType(); solAssert(!!externalFunctionType, ""); - Json::Value method; + Json::Value method{Json::objectValue}; method["type"] = "constructor"; method["stateMutability"] = stateMutabilityToString(externalFunctionType->stateMutability()); method["inputs"] = formatTypeList( @@ -96,23 +96,22 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef) { auto const* externalFunctionType = FunctionType(*fallbackOrReceive).interfaceFunctionType(); solAssert(!!externalFunctionType, ""); - Json::Value method; + Json::Value method{Json::objectValue}; method["type"] = TokenTraits::toString(fallbackOrReceive->kind()); method["stateMutability"] = stateMutabilityToString(externalFunctionType->stateMutability()); abi.emplace(std::move(method)); } for (auto const& it: _contractDef.interfaceEvents()) { - Json::Value event; + Json::Value event{Json::objectValue}; event["type"] = "event"; event["name"] = it->name(); event["anonymous"] = it->isAnonymous(); - Json::Value params(Json::arrayValue); + Json::Value params{Json::arrayValue}; for (auto const& p: it->parameters()) { Type const* type = p->annotation().type->interfaceType(false); solAssert(type, ""); - Json::Value input; auto param = formatType(p->name(), *type, *p->annotation().type, false); param["indexed"] = p->isIndexed(); params.append(std::move(param)); @@ -123,7 +122,7 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef) for (ErrorDefinition const* error: _contractDef.interfaceErrors()) { - Json::Value errorJson; + Json::Value errorJson{Json::objectValue}; errorJson["type"] = "error"; errorJson["name"] = error->name(); errorJson["inputs"] = Json::arrayValue; @@ -151,7 +150,7 @@ Json::Value ABI::formatTypeList( bool _forLibrary ) { - Json::Value params(Json::arrayValue); + Json::Value params{Json::arrayValue}; solAssert(_names.size() == _encodingTypes.size(), "Names and types vector size does not match"); solAssert(_names.size() == _solidityTypes.size(), ""); for (unsigned i = 0; i < _names.size(); ++i) @@ -169,7 +168,7 @@ Json::Value ABI::formatType( bool _forLibrary ) { - Json::Value ret; + Json::Value ret{Json::objectValue}; ret["name"] = _name; ret["internalType"] = _solidityType.toString(true); string suffix = (_forLibrary && _encodingType.dataStoredIn(DataLocation::Storage)) ? " storage" : ""; diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 3b5fb8cb5..c08ba6607 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -1429,7 +1429,7 @@ CompilerStack::Source const& CompilerStack::source(string const& _sourceName) co string CompilerStack::createMetadata(Contract const& _contract, bool _forIR) const { - Json::Value meta; + Json::Value meta{Json::objectValue}; meta["version"] = 1; meta["language"] = m_importedSources ? "SolidityAST" : "Solidity"; meta["compiler"]["version"] = VersionStringStrict; diff --git a/libsolidity/interface/Natspec.cpp b/libsolidity/interface/Natspec.cpp index 402d8e15c..533cbaa3d 100644 --- a/libsolidity/interface/Natspec.cpp +++ b/libsolidity/interface/Natspec.cpp @@ -37,7 +37,7 @@ using namespace solidity::frontend; Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef) { - Json::Value doc; + Json::Value doc{Json::objectValue}; doc["version"] = Json::Value(c_natspecVersion); doc["kind"] = Json::Value("user"); @@ -50,7 +50,7 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef) if (!value.empty()) { // add the constructor, only if we have any documentation to add - Json::Value user; + Json::Value user{Json::objectValue}; user["notice"] = Json::Value(value); doc["methods"]["constructor"] = user; } @@ -90,7 +90,7 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef) string value = extractDoc(error->annotation().docTags, "notice"); if (!value.empty()) { - Json::Value errorDoc; + Json::Value errorDoc{Json::objectValue}; errorDoc["notice"] = value; doc["errors"][error->functionType(true)->externalSignature()].append(move(errorDoc)); } @@ -225,7 +225,10 @@ Json::Value Natspec::extractCustomDoc(multimap const& _tags) for (auto const& [tag, value]: _tags) if (boost::starts_with(tag, "custom")) concatenated[tag] += value.content; - Json::Value result; + // We do not want to create an object if there are no custom tags found. + if (concatenated.empty()) + return Json::nullValue; + Json::Value result{Json::objectValue}; for (auto& [tag, value]: concatenated) result[tag] = move(value); return result; diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 1031ec7c3..7d354a405 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -59,7 +59,7 @@ Json::Value formatError( Json::Value const& _secondarySourceLocation = Json::Value() ) { - Json::Value error = Json::objectValue; + Json::Value error{Json::objectValue}; error["type"] = _type; error["component"] = _component; error["severity"] = Error::formatErrorSeverityLowercase(_severity); @@ -74,7 +74,7 @@ Json::Value formatError( Json::Value formatFatalError(string const& _type, string const& _message) { - Json::Value output = Json::objectValue; + Json::Value output{Json::objectValue}; output["errors"] = Json::arrayValue; output["errors"].append(formatError(Error::Severity::Error, _type, "general", _message)); return output; @@ -82,23 +82,22 @@ Json::Value formatFatalError(string const& _type, string const& _message) Json::Value formatSourceLocation(SourceLocation const* location) { - Json::Value sourceLocation; - if (location && location->sourceName) - { - sourceLocation["file"] = *location->sourceName; - sourceLocation["start"] = location->start; - sourceLocation["end"] = location->end; - } + if (!location || !location->sourceName) + return Json::nullValue; + Json::Value sourceLocation{Json::objectValue}; + sourceLocation["file"] = *location->sourceName; + sourceLocation["start"] = location->start; + sourceLocation["end"] = location->end; return sourceLocation; } Json::Value formatSecondarySourceLocation(SecondarySourceLocation const* _secondaryLocation) { if (!_secondaryLocation) - return {}; + return Json::nullValue; - Json::Value secondarySourceLocation = Json::arrayValue; + Json::Value secondarySourceLocation{Json::arrayValue}; for (auto const& location: _secondaryLocation->infos) { Json::Value msg = formatSourceLocation(&location.second); @@ -330,7 +329,7 @@ bool isIRRequested(Json::Value const& _outputSelection) Json::Value formatLinkReferences(std::map const& linkReferences) { - Json::Value ret(Json::objectValue); + Json::Value ret{Json::objectValue}; for (auto const& ref: linkReferences) { @@ -345,7 +344,7 @@ Json::Value formatLinkReferences(std::map const& linkRefere Json::Value fileObject = ret.get(file, Json::objectValue); Json::Value libraryArray = fileObject.get(name, Json::arrayValue); - Json::Value entry = Json::objectValue; + Json::Value entry{Json::objectValue}; entry["start"] = Json::UInt(ref.first); entry["length"] = 20; @@ -359,7 +358,7 @@ Json::Value formatLinkReferences(std::map const& linkRefere Json::Value formatImmutableReferences(map>> const& _immutableReferences) { - Json::Value ret(Json::objectValue); + Json::Value ret{Json::objectValue}; for (auto const& immutableReference: _immutableReferences) { @@ -367,7 +366,7 @@ Json::Value formatImmutableReferences(map>> co Json::Value array(Json::arrayValue); for (size_t byteOffset: byteOffsets) { - Json::Value byteRange(Json::objectValue); + Json::Value byteRange{Json::objectValue}; byteRange["start"] = Json::UInt(byteOffset); byteRange["length"] = Json::UInt(32); // immutable references are currently always 32 bytes wide array.append(byteRange); @@ -386,7 +385,7 @@ Json::Value collectEVMObject( function const& _artifactRequested ) { - Json::Value output = Json::objectValue; + Json::Value output{Json::objectValue}; if (_artifactRequested("object")) output["object"] = _object.toHex(); if (_artifactRequested("opcodes")) From b5e68df3cdb1c31bca03646b242e7fcbd175258d Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 15 Sep 2021 19:18:42 +0100 Subject: [PATCH 138/232] Document JsonFormat --- libsolutil/JSON.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsolutil/JSON.h b/libsolutil/JSON.h index 3a326a5e3..43dddfd4a 100644 --- a/libsolutil/JSON.h +++ b/libsolutil/JSON.h @@ -38,8 +38,8 @@ struct JsonFormat { enum Format { - Compact, - Pretty + Compact, // No unnecessary whitespace (including new lines and indentation) + Pretty, // Nicely indented, with new lines }; static constexpr uint32_t defaultIndent = 2; From e74f853c6bc3bcfbd110cef7537d3bc3cafabfbe Mon Sep 17 00:00:00 2001 From: Leo Alt Date: Fri, 17 Sep 2021 21:28:07 +0200 Subject: [PATCH 139/232] [SMTChecker] Support user types --- Changelog.md | 1 + libsolidity/formal/BMC.cpp | 2 + libsolidity/formal/CHC.cpp | 2 + libsolidity/formal/Predicate.cpp | 6 +- libsolidity/formal/SMTEncoder.cpp | 68 +++++++++++++-- libsolidity/formal/SMTEncoder.h | 9 ++ libsolidity/formal/SymbolicState.cpp | 2 + libsolidity/formal/SymbolicTypes.cpp | 4 + .../types/type_expression_tuple_array_2d.sol | 1 - .../types/type_expression_tuple_array_3d.sol | 1 - .../smtCheckerTests/userTypes/constant.sol | 18 ++++ .../smtCheckerTests/userTypes/conversion.sol | 87 +++++++++++++++++++ .../smtCheckerTests/userTypes/fixedpoint.sol | 74 ++++++++++++++++ .../userTypes/in_parenthesis.sol | 19 ++++ .../userTypes/in_parenthesis_2.sol | 26 ++++++ .../smtCheckerTests/userTypes/mapping_1.sol | 10 +++ .../smtCheckerTests/userTypes/modifier_1.sol | 18 ++++ .../smtCheckerTests/userTypes/multisource.sol | 21 +++++ .../userTypes/multisource_module.sol | 20 +++++ .../smtCheckerTests/userTypes/simple.sol | 23 +++++ .../smtCheckerTests/userTypes/user_abi_1.sol | 14 +++ .../smtCheckerTests/userTypes/user_abi_2.sol | 14 +++ .../wrap_unwrap_via_contract_name.sol | 36 ++++++++ 23 files changed, 462 insertions(+), 14 deletions(-) create mode 100644 test/libsolidity/smtCheckerTests/userTypes/constant.sol create mode 100644 test/libsolidity/smtCheckerTests/userTypes/conversion.sol create mode 100644 test/libsolidity/smtCheckerTests/userTypes/fixedpoint.sol create mode 100644 test/libsolidity/smtCheckerTests/userTypes/in_parenthesis.sol create mode 100644 test/libsolidity/smtCheckerTests/userTypes/in_parenthesis_2.sol create mode 100644 test/libsolidity/smtCheckerTests/userTypes/mapping_1.sol create mode 100644 test/libsolidity/smtCheckerTests/userTypes/modifier_1.sol create mode 100644 test/libsolidity/smtCheckerTests/userTypes/multisource.sol create mode 100644 test/libsolidity/smtCheckerTests/userTypes/multisource_module.sol create mode 100644 test/libsolidity/smtCheckerTests/userTypes/simple.sol create mode 100644 test/libsolidity/smtCheckerTests/userTypes/user_abi_1.sol create mode 100644 test/libsolidity/smtCheckerTests/userTypes/user_abi_2.sol create mode 100644 test/libsolidity/smtCheckerTests/userTypes/wrap_unwrap_via_contract_name.sol diff --git a/Changelog.md b/Changelog.md index eae8eb8be..a7bd8db00 100644 --- a/Changelog.md +++ b/Changelog.md @@ -14,6 +14,7 @@ Compiler Features: * SMTChecker: Add constraints to better correlate ``address(this).balance`` and ``msg.value``. * SMTChecker: Support the ``value`` option for external function calls. * SMTChecker: Support constants via modules. + * SMTChecker: Support user defined value types. Bugfixes: diff --git a/libsolidity/formal/BMC.cpp b/libsolidity/formal/BMC.cpp index 24c6a5231..bf3e5ea05 100644 --- a/libsolidity/formal/BMC.cpp +++ b/libsolidity/formal/BMC.cpp @@ -483,6 +483,8 @@ void BMC::endVisit(FunctionCall const& _funCall) case FunctionType::Kind::BlockHash: case FunctionType::Kind::AddMod: case FunctionType::Kind::MulMod: + case FunctionType::Kind::Unwrap: + case FunctionType::Kind::Wrap: [[fallthrough]]; default: SMTEncoder::endVisit(_funCall); diff --git a/libsolidity/formal/CHC.cpp b/libsolidity/formal/CHC.cpp index b7292221b..53098e081 100644 --- a/libsolidity/formal/CHC.cpp +++ b/libsolidity/formal/CHC.cpp @@ -553,6 +553,8 @@ void CHC::endVisit(FunctionCall const& _funCall) case FunctionType::Kind::BlockHash: case FunctionType::Kind::AddMod: case FunctionType::Kind::MulMod: + case FunctionType::Kind::Unwrap: + case FunctionType::Kind::Wrap: [[fallthrough]]; default: SMTEncoder::endVisit(_funCall); diff --git a/libsolidity/formal/Predicate.cpp b/libsolidity/formal/Predicate.cpp index 9c27a4e92..e058fa2b3 100644 --- a/libsolidity/formal/Predicate.cpp +++ b/libsolidity/formal/Predicate.cpp @@ -237,7 +237,7 @@ string Predicate::formatSummaryCall( auto last = first + static_cast(fun->parameters().size()); solAssert(first >= _args.begin() && first <= _args.end(), ""); solAssert(last >= _args.begin() && last <= _args.end(), ""); - auto inTypes = FunctionType(*fun).parameterTypes(); + auto inTypes = SMTEncoder::replaceUserTypes(FunctionType(*fun).parameterTypes()); vector> functionArgsCex = formatExpressions(vector(first, last), inTypes); vector functionArgs; @@ -317,7 +317,7 @@ vector> Predicate::summaryPostInputValues(vector inValues(first, last); solAssert(inValues.size() == inParams.size(), ""); - auto inTypes = FunctionType(*function).parameterTypes(); + auto inTypes = SMTEncoder::replaceUserTypes(FunctionType(*function).parameterTypes()); return formatExpressions(inValues, inTypes); } @@ -339,7 +339,7 @@ vector> Predicate::summaryPostOutputValues(vector outValues(first, _args.end()); solAssert(outValues.size() == function->returnParameters().size(), ""); - auto outTypes = FunctionType(*function).returnParameterTypes(); + auto outTypes = SMTEncoder::replaceUserTypes(FunctionType(*function).returnParameterTypes()); return formatExpressions(outValues, outTypes); } diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index e0c440919..7411383de 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -370,7 +370,7 @@ void SMTEncoder::endVisit(Assignment const& _assignment) Token op = _assignment.assignmentOperator(); solAssert(TokenTraits::isAssignmentOp(op), ""); - if (!smt::isSupportedType(*_assignment.annotation().type)) + if (!isSupportedType(*_assignment.annotation().type)) { // Give it a new index anyway to keep the SSA scheme sound. @@ -406,6 +406,9 @@ void SMTEncoder::endVisit(TupleExpression const& _tuple) if (_tuple.annotation().type->category() == Type::Category::Function) return; + if (_tuple.annotation().type->category() == Type::Category::TypeType) + return; + createExpr(_tuple); if (_tuple.isInlineArray()) @@ -575,6 +578,17 @@ bool SMTEncoder::visit(FunctionCall const& _funCall) arg->accept(*this); return false; } + // We do not really need to visit the expression in a wrap/unwrap no-op call, + // so we just ignore the function call expression to avoid "unsupported" warnings. + else if ( + funType.kind() == FunctionType::Kind::Wrap || + funType.kind() == FunctionType::Kind::Unwrap + ) + { + if (auto arg = _funCall.arguments().front()) + arg->accept(*this); + return false; + } return true; } @@ -641,6 +655,10 @@ void SMTEncoder::endVisit(FunctionCall const& _funCall) case FunctionType::Kind::MulMod: visitAddMulMod(_funCall); break; + case FunctionType::Kind::Unwrap: + case FunctionType::Kind::Wrap: + visitWrapUnwrap(_funCall); + break; case FunctionType::Kind::Send: case FunctionType::Kind::Transfer: { @@ -846,6 +864,13 @@ void SMTEncoder::visitAddMulMod(FunctionCall const& _funCall) defineExpr(_funCall, divModWithSlacks(x * y, k, intType).second); } +void SMTEncoder::visitWrapUnwrap(FunctionCall const& _funCall) +{ + auto const& args = _funCall.arguments(); + solAssert(args.size() == 1, ""); + defineExpr(_funCall, expr(*args.front())); +} + void SMTEncoder::visitObjectCreation(FunctionCall const& _funCall) { auto const& args = _funCall.arguments(); @@ -889,6 +914,9 @@ void SMTEncoder::endVisit(Identifier const& _identifier) // Ignore module identifiers else if (dynamic_cast(_identifier.annotation().type)) return; + // Ignore user defined value type identifiers + else if (dynamic_cast(_identifier.annotation().type)) + return; // Ignore the builtin abi, it is handled in FunctionCall. // TODO: ignore MagicType in general (abi, block, msg, tx, type) else if (auto magicType = dynamic_cast(_identifier.annotation().type); magicType && magicType->kind() == MagicType::Kind::ABI) @@ -944,7 +972,7 @@ void SMTEncoder::visitPublicGetter(FunctionCall const& _funCall) auto var = dynamic_cast(access.annotation().referencedDeclaration); solAssert(var, ""); solAssert(m_context.knownExpression(_funCall), ""); - auto paramExpectedTypes = FunctionType(*var).parameterTypes(); + auto paramExpectedTypes = replaceUserTypes(FunctionType(*var).parameterTypes()); auto actualArguments = _funCall.arguments(); solAssert(actualArguments.size() == paramExpectedTypes.size(), ""); deque symbArguments; @@ -1164,7 +1192,7 @@ void SMTEncoder::visitTypeConversion(FunctionCall const& _funCall) void SMTEncoder::visitFunctionIdentifier(Identifier const& _identifier) { auto const& fType = dynamic_cast(*_identifier.annotation().type); - if (fType.returnParameterTypes().size() == 1) + if (replaceUserTypes(fType.returnParameterTypes()).size() == 1) { defineGlobalVariable(fType.identifier(), _identifier); m_context.createExpression(_identifier, m_context.globalSymbol(fType.identifier())); @@ -1647,7 +1675,7 @@ void SMTEncoder::defineGlobalVariable(string const& _name, Expression const& _ex m_context.globalSymbol(_name)->increaseIndex(); // The default behavior is not to increase the index since // most of the global values stay the same throughout a tx. - if (smt::isSupportedType(*_expr.annotation().type)) + if (isSupportedType(*_expr.annotation().type)) defineExpr(_expr, m_context.globalSymbol(_name)->currentValue()); } @@ -1843,9 +1871,10 @@ smtutil::Expression SMTEncoder::bitwiseOperation( void SMTEncoder::compareOperation(BinaryOperation const& _op) { - auto const& commonType = _op.annotation().commonType; + auto commonType = _op.annotation().commonType; solAssert(commonType, ""); - if (smt::isSupportedType(*commonType)) + + if (isSupportedType(*commonType)) { smtutil::Expression left(expr(_op.leftExpression(), commonType)); smtutil::Expression right(expr(_op.rightExpression(), commonType)); @@ -1978,7 +2007,7 @@ void SMTEncoder::assignment( Expression const* left = cleanExpression(_left); - if (!smt::isSupportedType(*_type)) + if (!isSupportedType(*_type)) { // Give it a new index anyway to keep the SSA scheme sound. if (auto varDecl = identifierToVariable(*left)) @@ -2019,7 +2048,7 @@ void SMTEncoder::assignment( } else if (funType->kind() == FunctionType::Kind::Internal) { - for (auto type: funType->returnParameterTypes()) + for (auto type: replaceUserTypes(funType->returnParameterTypes())) if (type->category() == Type::Category::Mapping || dynamic_cast(type)) resetReferences(type); } @@ -2356,6 +2385,11 @@ bool SMTEncoder::sameTypeOrSubtype(Type const* _a, Type const* _b) return false; } +bool SMTEncoder::isSupportedType(Type const& _type) const +{ + return smt::isSupportedType(*underlyingType(&_type)); +} + Type const* SMTEncoder::typeWithoutPointer(Type const* _type) { if (auto refType = dynamic_cast(_type)) @@ -2417,7 +2451,7 @@ smtutil::Expression SMTEncoder::expr(Expression const& _e, Type const* _targetTy createExpr(_e); } - return m_context.expression(_e)->currentValue(_targetType); + return m_context.expression(_e)->currentValue(underlyingType(_targetType)); } void SMTEncoder::createExpr(Expression const& _e) @@ -2608,6 +2642,22 @@ Expression const* SMTEncoder::innermostTuple(Expression const& _expr) return expr; } +Type const* SMTEncoder::underlyingType(Type const* _type) +{ + if (auto userType = dynamic_cast(_type)) + _type = &userType->underlyingType(); + return _type; +} + +TypePointers SMTEncoder::replaceUserTypes(TypePointers const& _types) +{ + return applyMap(_types, [](auto _type) { + if (auto userType = dynamic_cast(_type)) + return &userType->underlyingType(); + return _type; + }); +} + pair SMTEncoder::functionCallExpression(FunctionCall const& _funCall) { Expression const* callExpr = &_funCall.expression(); diff --git a/libsolidity/formal/SMTEncoder.h b/libsolidity/formal/SMTEncoder.h index 4852c6831..7ca19358d 100644 --- a/libsolidity/formal/SMTEncoder.h +++ b/libsolidity/formal/SMTEncoder.h @@ -71,6 +71,12 @@ public: /// otherwise _expr. static Expression const* innermostTuple(Expression const& _expr); + /// @returns the underlying type if _type is UserDefinedValueType, + /// and _type otherwise. + static Type const* underlyingType(Type const* _type); + + static TypePointers replaceUserTypes(TypePointers const& _types); + /// @returns {_funCall.expression(), nullptr} if function call option values are not given, and /// {_funCall.expression().expression(), _funCall.expression()} if they are. static std::pair functionCallExpression(FunctionCall const& _funCall); @@ -207,6 +213,7 @@ protected: void visitCryptoFunction(FunctionCall const& _funCall); void visitGasLeft(FunctionCall const& _funCall); virtual void visitAddMulMod(FunctionCall const& _funCall); + void visitWrapUnwrap(FunctionCall const& _funCall); void visitObjectCreation(FunctionCall const& _funCall); void visitTypeConversion(FunctionCall const& _funCall); void visitStructConstructorCall(FunctionCall const& _funCall); @@ -319,6 +326,8 @@ protected: /// @returns whether _a or a subtype of _a is the same as _b. bool sameTypeOrSubtype(Type const* _a, Type const* _b); + bool isSupportedType(Type const& _type) const; + /// Given the state of the symbolic variables at the end of two different branches, /// create a merged state using the given branch condition. void mergeVariables(smtutil::Expression const& _condition, VariableIndices const& _indicesEndTrue, VariableIndices const& _indicesEndFalse); diff --git a/libsolidity/formal/SymbolicState.cpp b/libsolidity/formal/SymbolicState.cpp index 57ff725ba..e136f347d 100644 --- a/libsolidity/formal/SymbolicState.cpp +++ b/libsolidity/formal/SymbolicState.cpp @@ -270,6 +270,8 @@ void SymbolicState::buildABIFunctions(set const& _abiFuncti t = TypeProvider::uint256(); else if (t->category() == frontend::Type::Category::StringLiteral) t = TypeProvider::bytesMemory(); + else if (auto userType = dynamic_cast(t)) + t = &userType->underlyingType(); }; replaceTypes(inTypes); replaceTypes(outTypes); diff --git a/libsolidity/formal/SymbolicTypes.cpp b/libsolidity/formal/SymbolicTypes.cpp index ba82a1666..36d9a0f35 100644 --- a/libsolidity/formal/SymbolicTypes.cpp +++ b/libsolidity/formal/SymbolicTypes.cpp @@ -233,6 +233,10 @@ pair> newSymbolicVariable( bool abstract = false; shared_ptr var; frontend::Type const* type = &_type; + + if (auto userType = dynamic_cast(type)) + return newSymbolicVariable(userType->underlyingType(), _uniqueName, _context); + if (!isSupportedTypeDeclaration(_type)) { abstract = true; diff --git a/test/libsolidity/smtCheckerTests/types/type_expression_tuple_array_2d.sol b/test/libsolidity/smtCheckerTests/types/type_expression_tuple_array_2d.sol index 3087e94aa..0d525f50a 100644 --- a/test/libsolidity/smtCheckerTests/types/type_expression_tuple_array_2d.sol +++ b/test/libsolidity/smtCheckerTests/types/type_expression_tuple_array_2d.sol @@ -9,4 +9,3 @@ function f() public pure { (int[][]); } // Warning 6133: (41-50): Statement has no effect. // Warning 8364: (42-47): Assertion checker does not yet implement type type(int256[] memory) // Warning 8364: (42-49): Assertion checker does not yet implement type type(int256[] memory[] memory) -// Warning 8364: (41-50): Assertion checker does not yet implement type type(int256[] memory[] memory) diff --git a/test/libsolidity/smtCheckerTests/types/type_expression_tuple_array_3d.sol b/test/libsolidity/smtCheckerTests/types/type_expression_tuple_array_3d.sol index 58aab6642..37540b982 100644 --- a/test/libsolidity/smtCheckerTests/types/type_expression_tuple_array_3d.sol +++ b/test/libsolidity/smtCheckerTests/types/type_expression_tuple_array_3d.sol @@ -10,4 +10,3 @@ function f() public pure { (int[][][]); } // Warning 8364: (42-47): Assertion checker does not yet implement type type(int256[] memory) // Warning 8364: (42-49): Assertion checker does not yet implement type type(int256[] memory[] memory) // Warning 8364: (42-51): Assertion checker does not yet implement type type(int256[] memory[] memory[] memory) -// Warning 8364: (41-52): Assertion checker does not yet implement type type(int256[] memory[] memory[] memory) diff --git a/test/libsolidity/smtCheckerTests/userTypes/constant.sol b/test/libsolidity/smtCheckerTests/userTypes/constant.sol new file mode 100644 index 000000000..9730d4b1c --- /dev/null +++ b/test/libsolidity/smtCheckerTests/userTypes/constant.sol @@ -0,0 +1,18 @@ +type T is int224; +pragma solidity >= 0.0.0; +contract C { + T constant public s = T.wrap(int224(165521356710917456517261742455526507355687727119203895813322792776)); + T constant public t = s; + int224 constant public u = T.unwrap(t); + + function f() public pure { + assert(T.unwrap(s) == 165521356710917456517261742455526507355687727119203895813322792776); + assert(T.unwrap(t) == 165521356710917456517261742455526507355687727119203895813322792776); + assert(u == 165521356710917456517261742455526507355687727119203895813322792776); + assert(T.unwrap(s) == 0); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (531-555): CHC: Assertion violation happens here.\nCounterexample:\nu = 165521356710917456517261742455526507355687727119203895813322792776\n\nTransaction trace:\nC.constructor()\nState: u = 165521356710917456517261742455526507355687727119203895813322792776\nC.f() diff --git a/test/libsolidity/smtCheckerTests/userTypes/conversion.sol b/test/libsolidity/smtCheckerTests/userTypes/conversion.sol new file mode 100644 index 000000000..cad0233a7 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/userTypes/conversion.sol @@ -0,0 +1,87 @@ +pragma abicoder v2; + +type MyUInt8 is uint8; +type MyInt8 is int8; +type MyUInt16 is uint16; + +contract C { + function f(uint a) internal pure returns(MyUInt8) { + return MyUInt8.wrap(uint8(a)); + } + function g(uint a) internal pure returns(MyInt8) { + return MyInt8.wrap(int8(int(a))); + } + function h(MyUInt8 a) internal pure returns (MyInt8) { + return MyInt8.wrap(int8(MyUInt8.unwrap(a))); + } + function i(MyUInt8 a) internal pure returns(MyUInt16) { + return MyUInt16.wrap(MyUInt8.unwrap(a)); + } + function j(MyUInt8 a) internal pure returns (uint) { + return MyUInt8.unwrap(a); + } + function k(MyUInt8 a) internal pure returns (MyUInt16) { + return MyUInt16.wrap(MyUInt8.unwrap(a)); + } + function m(MyUInt16 a) internal pure returns (MyUInt8) { + return MyUInt8.wrap(uint8(MyUInt16.unwrap(a))); + } + + function p() public pure { + assert(MyUInt8.unwrap(f(1)) == 1); + assert(MyUInt8.unwrap(f(2)) == 2); + assert(MyUInt8.unwrap(f(257)) == 1); + assert(MyUInt8.unwrap(f(257)) == 257); // should fail + } + + function q() public pure { + assert(MyInt8.unwrap(g(1)) == 1); + assert(MyInt8.unwrap(g(2)) == 2); + assert(MyInt8.unwrap(g(255)) == -1); + assert(MyInt8.unwrap(g(257)) == 1); + assert(MyInt8.unwrap(g(257)) == -1); // should fail + } + + function r() public pure { + assert(MyInt8.unwrap(h(MyUInt8.wrap(1))) == 1); + assert(MyInt8.unwrap(h(MyUInt8.wrap(2))) == 2); + assert(MyInt8.unwrap(h(MyUInt8.wrap(255))) == -1); + assert(MyInt8.unwrap(h(MyUInt8.wrap(255))) == 1); // should fail + } + + function s() public pure { + assert(MyUInt16.unwrap(i(MyUInt8.wrap(250))) == 250); + assert(MyUInt16.unwrap(i(MyUInt8.wrap(250))) == 0); // should fail + } + + function t() public pure { + assert(j(MyUInt8.wrap(1)) == 1); + assert(j(MyUInt8.wrap(2)) == 2); + assert(j(MyUInt8.wrap(255)) == 0xff); + assert(j(MyUInt8.wrap(255)) == 1); // should fail + } + + function v() public pure { + assert(MyUInt16.unwrap(k(MyUInt8.wrap(1))) == 1); + assert(MyUInt16.unwrap(k(MyUInt8.wrap(2))) == 2); + assert(MyUInt16.unwrap(k(MyUInt8.wrap(255))) == 0xff); + assert(MyUInt16.unwrap(k(MyUInt8.wrap(255))) == 1); // should fail + } + + function w() public pure { + assert(MyUInt8.unwrap(m(MyUInt16.wrap(1))) == 1); + assert(MyUInt8.unwrap(m(MyUInt16.wrap(2))) == 2); + assert(MyUInt8.unwrap(m(MyUInt16.wrap(255))) == 0xff); + assert(MyUInt8.unwrap(m(MyUInt16.wrap(255))) == 1); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (937-974): CHC: Assertion violation happens here. +// Warning 6328: (1174-1209): CHC: Assertion violation happens here. +// Warning 6328: (1413-1461): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.r()\n C.h(1) -- internal call\n C.h(2) -- internal call\n C.h(255) -- internal call\n C.h(255) -- internal call +// Warning 6328: (1568-1618): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.s()\n C.i(250) -- internal call\n C.i(250) -- internal call +// Warning 6328: (1779-1812): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.t()\n C.j(1) -- internal call\n C.j(2) -- internal call\n C.j(255) -- internal call\n C.j(255) -- internal call +// Warning 6328: (2024-2074): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.v()\n C.k(1) -- internal call\n C.k(2) -- internal call\n C.k(255) -- internal call\n C.k(255) -- internal call +// Warning 6328: (2286-2336): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/userTypes/fixedpoint.sol b/test/libsolidity/smtCheckerTests/userTypes/fixedpoint.sol new file mode 100644 index 000000000..a8aa0bd9a --- /dev/null +++ b/test/libsolidity/smtCheckerTests/userTypes/fixedpoint.sol @@ -0,0 +1,74 @@ +// Represent a 18 decimal, 256 bit wide fixed point type using a user defined value type. +type UFixed256x18 is uint256; + +/// A minimal library to do fixed point operations on UFixed256x18. +library FixedMath { + uint constant multiplier = 10**18; + /// Adds two UFixed256x18 numbers. Reverts on overflow, relying on checked arithmetic on + /// uint256. + function add(UFixed256x18 a, UFixed256x18 b) internal pure returns (UFixed256x18) { + return UFixed256x18.wrap(UFixed256x18.unwrap(a) + UFixed256x18.unwrap(b)); + } + /// Multiplies UFixed256x18 and uint256. Reverts on overflow, relying on checked arithmetic on + /// uint256. + function mul(UFixed256x18 a, uint256 b) internal pure returns (UFixed256x18) { + return UFixed256x18.wrap(UFixed256x18.unwrap(a) * b); + } + /// Take the floor of a UFixed256x18 number. + /// @return the largest integer that does not exceed `a`. + function floor(UFixed256x18 a) internal pure returns (uint256) { + return UFixed256x18.unwrap(a) / multiplier; + } + /// Turns a uint256 into a UFixed256x18 of the same value. + /// Reverts if the integer is too large. + function toUFixed256x18(uint256 a) internal pure returns (UFixed256x18) { + return UFixed256x18.wrap(a * multiplier); + } +} + +contract TestFixedMath { + function add(UFixed256x18 a, UFixed256x18 b) internal pure returns (UFixed256x18) { + return FixedMath.add(a, b); + } + function mul(UFixed256x18 a, uint256 b) internal pure returns (UFixed256x18) { + return FixedMath.mul(a, b); + } + function floor(UFixed256x18 a) internal pure returns (uint256) { + return FixedMath.floor(a); + } + function toUFixed256x18(uint256 a) internal pure returns (UFixed256x18) { + return FixedMath.toUFixed256x18(a); + } + + function f() public pure { + assert(UFixed256x18.unwrap(add(UFixed256x18.wrap(0), UFixed256x18.wrap(0))) == 0); + assert(UFixed256x18.unwrap(add(UFixed256x18.wrap(25), UFixed256x18.wrap(45))) == 0x46); + assert(UFixed256x18.unwrap(add(UFixed256x18.wrap(25), UFixed256x18.wrap(45))) == 46); // should fail + } + + function g() public pure { + assert(UFixed256x18.unwrap(mul(UFixed256x18.wrap(340282366920938463463374607431768211456), 20)) == 6805647338418769269267492148635364229120); + assert(UFixed256x18.unwrap(mul(UFixed256x18.wrap(340282366920938463463374607431768211456), 20)) == 0); // should fail + } + + function h() public pure { + assert(floor(UFixed256x18.wrap(11579208923731619542357098500868790785326998665640564039457584007913129639930)) == 11579208923731619542357098500868790785326998665640564039457); + assert(floor(UFixed256x18.wrap(115792089237316195423570985008687907853269984665640564039457584007913129639935)) == 115792089237316195423570985008687907853269984665640564039457); + assert(floor(UFixed256x18.wrap(11579208923731619542357098500868790785326998665640564039457584007913129639930)) == 0); // should fail + } + + function i() public pure { + assert(UFixed256x18.unwrap(toUFixed256x18(0)) == 0); + assert(UFixed256x18.unwrap(toUFixed256x18(5)) == 5000000000000000000); + assert(UFixed256x18.unwrap(toUFixed256x18(115792089237316195423570985008687907853269984665640564039457)) == 115792089237316195423570985008687907853269984665640564039457000000000000000000); + assert(UFixed256x18.unwrap(toUFixed256x18(5)) == 5); // should fail + } + +} +// ==== +// 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: (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 diff --git a/test/libsolidity/smtCheckerTests/userTypes/in_parenthesis.sol b/test/libsolidity/smtCheckerTests/userTypes/in_parenthesis.sol new file mode 100644 index 000000000..478b87dfe --- /dev/null +++ b/test/libsolidity/smtCheckerTests/userTypes/in_parenthesis.sol @@ -0,0 +1,19 @@ +type MyInt is int; +contract C { + function f() public pure returns (MyInt a) { + a = MyInt.wrap(5); + assert(MyInt.unwrap(a) == 5); + assert(MyInt.unwrap(a) == 6); // should fail + } + + function g() public pure { + MyInt x = f(); + assert(MyInt.unwrap(x) == 5); + assert(MyInt.unwrap(x) == 6); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (133-161): CHC: Assertion violation happens here.\nCounterexample:\n\na = 5\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (261-289): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.g()\n C.f() -- internal call diff --git a/test/libsolidity/smtCheckerTests/userTypes/in_parenthesis_2.sol b/test/libsolidity/smtCheckerTests/userTypes/in_parenthesis_2.sol new file mode 100644 index 000000000..e8da1dd56 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/userTypes/in_parenthesis_2.sol @@ -0,0 +1,26 @@ +type MyInt is int; +contract C { + function f() public pure returns (MyInt a, int b) { + (MyInt).wrap; + a = (MyInt).wrap(5); + (MyInt).unwrap; + b = (MyInt).unwrap((MyInt).wrap(10)); + } + + function g() public pure { + (MyInt x, int y) = f(); + assert(MyInt.unwrap(x) == 5); + assert(MyInt.unwrap(x) == 6); // should fail + assert(y == 10); + assert(y == 11); // should fail + } + +} +// ==== +// SMTEngine: all +// SMTIgnoreCex: yes +// ---- +// Warning 6133: (87-99): Statement has no effect. +// Warning 6133: (126-140): Statement has no effect. +// Warning 6328: (274-302): CHC: Assertion violation happens here. +// Warning 6328: (340-355): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/userTypes/mapping_1.sol b/test/libsolidity/smtCheckerTests/userTypes/mapping_1.sol new file mode 100644 index 000000000..52ea82800 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/userTypes/mapping_1.sol @@ -0,0 +1,10 @@ +type MyInt is int; +contract C { + mapping(MyInt => int) m; + function f(MyInt a) public view { + assert(m[a] == 0); // should hold + assert(m[a] != 0); // should fail + } +} +// ---- +// Warning 6328: (134-151): CHC: Assertion violation happens here.\nCounterexample:\n\na = 0\n\nTransaction trace:\nC.constructor()\nC.f(0) diff --git a/test/libsolidity/smtCheckerTests/userTypes/modifier_1.sol b/test/libsolidity/smtCheckerTests/userTypes/modifier_1.sol new file mode 100644 index 000000000..3dbcc3126 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/userTypes/modifier_1.sol @@ -0,0 +1,18 @@ +type T1 is uint; +type T2 is uint; + +contract C { + modifier m(T1 x, T2 y) { + require(T1.unwrap(x) == T2.unwrap(y)); + _; + } + + function f(uint x, uint y) m(T1.wrap(x), T2.wrap(y)) public pure { + assert(x == y); + assert(x != y); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (212-226): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 0\ny = 0\n\nTransaction trace:\nC.constructor()\nC.f(0, 0) diff --git a/test/libsolidity/smtCheckerTests/userTypes/multisource.sol b/test/libsolidity/smtCheckerTests/userTypes/multisource.sol new file mode 100644 index 000000000..fef83a8ee --- /dev/null +++ b/test/libsolidity/smtCheckerTests/userTypes/multisource.sol @@ -0,0 +1,21 @@ +==== Source: A ==== +type MyInt is int; +type MyAddress is address; +==== Source: B ==== +import {MyInt, MyAddress as OurAddress} from "A"; +contract A { + function f(int x) internal pure returns(MyInt) { return MyInt.wrap(x); } + function f(address x) internal pure returns(OurAddress) { return OurAddress.wrap(x); } + + function g() public pure { + assert(MyInt.unwrap(f(int(5))) == 5); + assert(MyInt.unwrap(f(int(5))) == 0); // should fail + assert(OurAddress.unwrap(f(address(5))) == address(5)); + assert(OurAddress.unwrap(f(address(5))) == address(0)); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (B:296-332): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nA.constructor()\nA.g()\n A.f(5) -- internal call\n A.f(5) -- internal call +// Warning 6328: (B:409-463): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nA.constructor()\nA.g()\n A.f(5) -- internal call\n A.f(5) -- internal call\n A.f(5) -- internal call\n A.f(5) -- internal call diff --git a/test/libsolidity/smtCheckerTests/userTypes/multisource_module.sol b/test/libsolidity/smtCheckerTests/userTypes/multisource_module.sol new file mode 100644 index 000000000..ee3277d1b --- /dev/null +++ b/test/libsolidity/smtCheckerTests/userTypes/multisource_module.sol @@ -0,0 +1,20 @@ +==== Source: s1.sol ==== +type MyInt is int; +==== Source: s2.sol ==== +import "s1.sol" as M; +contract C { + function f(int x) public pure returns (M.MyInt) { return M.MyInt.wrap(x); } + function g(M.MyInt x) public pure returns (int) { return M.MyInt.unwrap(x); } + + function h() public pure { + assert(M.MyInt.unwrap(f(5)) == 5); + assert(M.MyInt.unwrap(f(5)) == 6); // should fail + assert(g(M.MyInt.wrap(1)) == 1); + assert(g(M.MyInt.wrap(1)) == 0); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (s2.sol:259-292): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.h()\n C.f(5) -- internal call\n C.f(5) -- internal call +// Warning 6328: (s2.sol:346-377): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.h()\n C.f(5) -- internal call\n C.f(5) -- internal call\n C.g(1) -- internal call\n C.g(1) -- internal call diff --git a/test/libsolidity/smtCheckerTests/userTypes/simple.sol b/test/libsolidity/smtCheckerTests/userTypes/simple.sol new file mode 100644 index 000000000..edfde6594 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/userTypes/simple.sol @@ -0,0 +1,23 @@ +type MyInt is int; +contract C { + function f() internal pure returns (MyInt a) { + } + function g() internal pure returns (MyInt b, MyInt c) { + b = MyInt.wrap(int(1)); + c = MyInt.wrap(1); + } + + function h() public pure { + assert(MyInt.unwrap(f()) == 0); + assert(MyInt.unwrap(f()) == 1); // should fail + (MyInt x, MyInt y) = g(); + assert(MyInt.unwrap(x) == 1); + assert(MyInt.unwrap(x) == 0); // should fail + assert(MyInt.unwrap(y) == 1); + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (255-285): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.h()\n C.f() -- internal call\n C.f() -- internal call +// Warning 6328: (364-392): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.h()\n C.f() -- internal call\n C.f() -- internal call\n C.g() -- internal call diff --git a/test/libsolidity/smtCheckerTests/userTypes/user_abi_1.sol b/test/libsolidity/smtCheckerTests/userTypes/user_abi_1.sol new file mode 100644 index 000000000..1d31cbe3d --- /dev/null +++ b/test/libsolidity/smtCheckerTests/userTypes/user_abi_1.sol @@ -0,0 +1,14 @@ +type T is uint; + +contract C { + function f(bytes memory data) public pure { + T x = abi.decode(data, (T)); + uint y = abi.decode(data, (uint)); + assert(T.unwrap(x) == y); // should hold + assert(T.unwrap(x) != y); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (188-212): CHC: Assertion violation happens here.\nCounterexample:\n\ny = 2437\n\nTransaction trace:\nC.constructor()\nC.f(data) diff --git a/test/libsolidity/smtCheckerTests/userTypes/user_abi_2.sol b/test/libsolidity/smtCheckerTests/userTypes/user_abi_2.sol new file mode 100644 index 000000000..a4c4a3a29 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/userTypes/user_abi_2.sol @@ -0,0 +1,14 @@ +type T is uint; + +contract C { + function f(bytes memory data) public pure { + T x = abi.decode(data, (T)); + T y = abi.decode(data, (T)); + assert(T.unwrap(x) == T.unwrap(y)); // should hold + assert(T.unwrap(x) != T.unwrap(y)); // should fail + } +} +// ==== +// SMTEngine: all +// ---- +// Warning 6328: (192-226): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f(data) diff --git a/test/libsolidity/smtCheckerTests/userTypes/wrap_unwrap_via_contract_name.sol b/test/libsolidity/smtCheckerTests/userTypes/wrap_unwrap_via_contract_name.sol new file mode 100644 index 000000000..065dae17a --- /dev/null +++ b/test/libsolidity/smtCheckerTests/userTypes/wrap_unwrap_via_contract_name.sol @@ -0,0 +1,36 @@ +contract C { + type T is uint; +} +contract D { + function f(C.T x) internal pure returns(uint) { + return C.T.unwrap(x); + } + function g(uint x) internal pure returns(C.T) { + return C.T.wrap(x); + } + function h(uint x) internal pure returns(uint) { + return f(g(x)); + } + function i(C.T x) internal pure returns(C.T) { + return g(f(x)); + } + + function m() public pure { + assert(f(C.T.wrap(0x42)) == 0x42); + assert(f(C.T.wrap(0x42)) == 0x43); // should fail + assert(C.T.unwrap(g(0x42)) == 0x42); + assert(C.T.unwrap(g(0x42)) == 0x43); // should fail + assert(h(0x42) == 0x42); + assert(h(0x42) == 0x43); // should fail + assert(C.T.unwrap(i(C.T.wrap(0x42))) == 0x42); + assert(C.T.unwrap(i(C.T.wrap(0x42))) == 0x43); // should fail + } +} +// ==== +// SMTEngine: all +// SMTIgnoreCex: yes +// ---- +// Warning 6328: (403-436): CHC: Assertion violation happens here. +// Warning 6328: (494-529): CHC: Assertion violation happens here. +// Warning 6328: (575-598): CHC: Assertion violation happens here. +// Warning 6328: (666-711): CHC: Assertion violation happens here. From 7bd1d1cf20ef0f8d24dea7efad3b310aeafce4d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 21 Sep 2021 14:09:51 +0200 Subject: [PATCH 140/232] Command-line test for --asm-json --- test/cmdlineTests/asm_json/args | 1 + test/cmdlineTests/asm_json/input.sol | 9 + test/cmdlineTests/asm_json/output | 1586 ++++++++++++++++++++++++++ 3 files changed, 1596 insertions(+) create mode 100644 test/cmdlineTests/asm_json/args create mode 100644 test/cmdlineTests/asm_json/input.sol create mode 100644 test/cmdlineTests/asm_json/output diff --git a/test/cmdlineTests/asm_json/args b/test/cmdlineTests/asm_json/args new file mode 100644 index 000000000..8f4713692 --- /dev/null +++ b/test/cmdlineTests/asm_json/args @@ -0,0 +1 @@ +--asm-json diff --git a/test/cmdlineTests/asm_json/input.sol b/test/cmdlineTests/asm_json/input.sol new file mode 100644 index 000000000..da3a08d7f --- /dev/null +++ b/test/cmdlineTests/asm_json/input.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity >=0.0; + +contract C { + function f(uint x) public pure { + x += 42; + require(x > 100); + } +} diff --git a/test/cmdlineTests/asm_json/output b/test/cmdlineTests/asm_json/output new file mode 100644 index 000000000..bd7a9c223 --- /dev/null +++ b/test/cmdlineTests/asm_json/output @@ -0,0 +1,1586 @@ + +======= asm_json/input.sol:C ======= +EVM assembly: +{ + ".code": + [ + { + "begin": 60, + "end": 160, + "name": "PUSH", + "source": 0, + "value": "80" + }, + { + "begin": 60, + "end": 160, + "name": "PUSH", + "source": 0, + "value": "40" + }, + { + "begin": 60, + "end": 160, + "name": "MSTORE", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "CALLVALUE", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "DUP1", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "ISZERO", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "PUSH [tag]", + "source": 0, + "value": "1" + }, + { + "begin": 60, + "end": 160, + "name": "JUMPI", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "PUSH", + "source": 0, + "value": "0" + }, + { + "begin": 60, + "end": 160, + "name": "DUP1", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "REVERT", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "tag", + "source": 0, + "value": "1" + }, + { + "begin": 60, + "end": 160, + "name": "JUMPDEST", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "POP", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "PUSH #[$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 60, + "end": 160, + "name": "DUP1", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "PUSH [$]", + "source": 0, + "value": "0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 60, + "end": 160, + "name": "PUSH", + "source": 0, + "value": "0" + }, + { + "begin": 60, + "end": 160, + "name": "CODECOPY", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "PUSH", + "source": 0, + "value": "0" + }, + { + "begin": 60, + "end": 160, + "name": "RETURN", + "source": 0 + } + ], + ".data": + { + "0": + { + ".auxdata": "", + ".code": + [ + { + "begin": 60, + "end": 160, + "name": "PUSH", + "source": 0, + "value": "80" + }, + { + "begin": 60, + "end": 160, + "name": "PUSH", + "source": 0, + "value": "40" + }, + { + "begin": 60, + "end": 160, + "name": "MSTORE", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "CALLVALUE", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "DUP1", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "ISZERO", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "PUSH [tag]", + "source": 0, + "value": "1" + }, + { + "begin": 60, + "end": 160, + "name": "JUMPI", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "PUSH", + "source": 0, + "value": "0" + }, + { + "begin": 60, + "end": 160, + "name": "DUP1", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "REVERT", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "tag", + "source": 0, + "value": "1" + }, + { + "begin": 60, + "end": 160, + "name": "JUMPDEST", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "POP", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "PUSH", + "source": 0, + "value": "4" + }, + { + "begin": 60, + "end": 160, + "name": "CALLDATASIZE", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "LT", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "PUSH [tag]", + "source": 0, + "value": "2" + }, + { + "begin": 60, + "end": 160, + "name": "JUMPI", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "PUSH", + "source": 0, + "value": "0" + }, + { + "begin": 60, + "end": 160, + "name": "CALLDATALOAD", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "PUSH", + "source": 0, + "value": "E0" + }, + { + "begin": 60, + "end": 160, + "name": "SHR", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "DUP1", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "PUSH", + "source": 0, + "value": "B3DE648B" + }, + { + "begin": 60, + "end": 160, + "name": "EQ", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "PUSH [tag]", + "source": 0, + "value": "3" + }, + { + "begin": 60, + "end": 160, + "name": "JUMPI", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "tag", + "source": 0, + "value": "2" + }, + { + "begin": 60, + "end": 160, + "name": "JUMPDEST", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "PUSH", + "source": 0, + "value": "0" + }, + { + "begin": 60, + "end": 160, + "name": "DUP1", + "source": 0 + }, + { + "begin": 60, + "end": 160, + "name": "REVERT", + "source": 0 + }, + { + "begin": 77, + "end": 158, + "name": "tag", + "source": 0, + "value": "3" + }, + { + "begin": 77, + "end": 158, + "name": "JUMPDEST", + "source": 0 + }, + { + "begin": 77, + "end": 158, + "name": "PUSH [tag]", + "source": 0, + "value": "4" + }, + { + "begin": 77, + "end": 158, + "name": "PUSH", + "source": 0, + "value": "4" + }, + { + "begin": 77, + "end": 158, + "name": "DUP1", + "source": 0 + }, + { + "begin": 77, + "end": 158, + "name": "CALLDATASIZE", + "source": 0 + }, + { + "begin": 77, + "end": 158, + "name": "SUB", + "source": 0 + }, + { + "begin": 77, + "end": 158, + "name": "DUP2", + "source": 0 + }, + { + "begin": 77, + "end": 158, + "name": "ADD", + "source": 0 + }, + { + "begin": 77, + "end": 158, + "name": "SWAP1", + "source": 0 + }, + { + "begin": 77, + "end": 158, + "name": "PUSH [tag]", + "source": 0, + "value": "5" + }, + { + "begin": 77, + "end": 158, + "name": "SWAP2", + "source": 0 + }, + { + "begin": 77, + "end": 158, + "name": "SWAP1", + "source": 0 + }, + { + "begin": 77, + "end": 158, + "name": "PUSH [tag]", + "source": 0, + "value": "6" + }, + { + "begin": 77, + "end": 158, + "name": "JUMP", + "source": 0, + "value": "[in]" + }, + { + "begin": 77, + "end": 158, + "name": "tag", + "source": 0, + "value": "5" + }, + { + "begin": 77, + "end": 158, + "name": "JUMPDEST", + "source": 0 + }, + { + "begin": 77, + "end": 158, + "name": "PUSH [tag]", + "source": 0, + "value": "7" + }, + { + "begin": 77, + "end": 158, + "name": "JUMP", + "source": 0, + "value": "[in]" + }, + { + "begin": 77, + "end": 158, + "name": "tag", + "source": 0, + "value": "4" + }, + { + "begin": 77, + "end": 158, + "name": "JUMPDEST", + "source": 0 + }, + { + "begin": 77, + "end": 158, + "name": "STOP", + "source": 0 + }, + { + "begin": 77, + "end": 158, + "name": "tag", + "source": 0, + "value": "7" + }, + { + "begin": 77, + "end": 158, + "name": "JUMPDEST", + "source": 0 + }, + { + "begin": 123, + "end": 125, + "name": "PUSH", + "source": 0, + "value": "2A" + }, + { + "begin": 118, + "end": 125, + "name": "DUP2", + "source": 0 + }, + { + "begin": 118, + "end": 125, + "name": "PUSH [tag]", + "source": 0, + "value": "9" + }, + { + "begin": 118, + "end": 125, + "name": "SWAP2", + "source": 0 + }, + { + "begin": 118, + "end": 125, + "name": "SWAP1", + "source": 0 + }, + { + "begin": 118, + "end": 125, + "name": "PUSH [tag]", + "source": 0, + "value": "10" + }, + { + "begin": 118, + "end": 125, + "name": "JUMP", + "source": 0, + "value": "[in]" + }, + { + "begin": 118, + "end": 125, + "name": "tag", + "source": 0, + "value": "9" + }, + { + "begin": 118, + "end": 125, + "name": "JUMPDEST", + "source": 0 + }, + { + "begin": 118, + "end": 125, + "name": "SWAP1", + "source": 0 + }, + { + "begin": 118, + "end": 125, + "name": "POP", + "source": 0 + }, + { + "begin": 147, + "end": 150, + "name": "PUSH", + "source": 0, + "value": "64" + }, + { + "begin": 143, + "end": 144, + "name": "DUP2", + "source": 0 + }, + { + "begin": 143, + "end": 150, + "name": "GT", + "source": 0 + }, + { + "begin": 135, + "end": 151, + "name": "PUSH [tag]", + "source": 0, + "value": "11" + }, + { + "begin": 135, + "end": 151, + "name": "JUMPI", + "source": 0 + }, + { + "begin": 135, + "end": 151, + "name": "PUSH", + "source": 0, + "value": "0" + }, + { + "begin": 135, + "end": 151, + "name": "DUP1", + "source": 0 + }, + { + "begin": 135, + "end": 151, + "name": "REVERT", + "source": 0 + }, + { + "begin": 135, + "end": 151, + "name": "tag", + "source": 0, + "value": "11" + }, + { + "begin": 135, + "end": 151, + "name": "JUMPDEST", + "source": 0 + }, + { + "begin": 77, + "end": 158, + "name": "POP", + "source": 0 + }, + { + "begin": 77, + "end": 158, + "name": "JUMP", + "source": 0, + "value": "[out]" + }, + { + "begin": 88, + "end": 205, + "name": "tag", + "source": 1, + "value": "15" + }, + { + "begin": 88, + "end": 205, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 197, + "end": 198, + "name": "PUSH", + "source": 1, + "value": "0" + }, + { + "begin": 194, + "end": 195, + "name": "DUP1", + "source": 1 + }, + { + "begin": 187, + "end": 199, + "name": "REVERT", + "source": 1 + }, + { + "begin": 334, + "end": 411, + "name": "tag", + "source": 1, + "value": "19" + }, + { + "begin": 334, + "end": 411, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 371, + "end": 378, + "name": "PUSH", + "source": 1, + "value": "0" + }, + { + "begin": 400, + "end": 405, + "name": "DUP2", + "source": 1 + }, + { + "begin": 389, + "end": 405, + "name": "SWAP1", + "source": 1 + }, + { + "begin": 389, + "end": 405, + "name": "POP", + "source": 1 + }, + { + "begin": 334, + "end": 411, + "name": "SWAP2", + "source": 1 + }, + { + "begin": 334, + "end": 411, + "name": "SWAP1", + "source": 1 + }, + { + "begin": 334, + "end": 411, + "name": "POP", + "source": 1 + }, + { + "begin": 334, + "end": 411, + "name": "JUMP", + "source": 1, + "value": "[out]" + }, + { + "begin": 417, + "end": 539, + "name": "tag", + "source": 1, + "value": "21" + }, + { + "begin": 417, + "end": 539, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 490, + "end": 514, + "name": "PUSH [tag]", + "source": 1, + "value": "23" + }, + { + "begin": 508, + "end": 513, + "name": "DUP2", + "source": 1 + }, + { + "begin": 490, + "end": 514, + "name": "PUSH [tag]", + "source": 1, + "value": "19" + }, + { + "begin": 490, + "end": 514, + "name": "JUMP", + "source": 1, + "value": "[in]" + }, + { + "begin": 490, + "end": 514, + "name": "tag", + "source": 1, + "value": "23" + }, + { + "begin": 490, + "end": 514, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 483, + "end": 488, + "name": "DUP2", + "source": 1 + }, + { + "begin": 480, + "end": 515, + "name": "EQ", + "source": 1 + }, + { + "begin": 470, + "end": 533, + "name": "PUSH [tag]", + "source": 1, + "value": "24" + }, + { + "begin": 470, + "end": 533, + "name": "JUMPI", + "source": 1 + }, + { + "begin": 529, + "end": 530, + "name": "PUSH", + "source": 1, + "value": "0" + }, + { + "begin": 526, + "end": 527, + "name": "DUP1", + "source": 1 + }, + { + "begin": 519, + "end": 531, + "name": "REVERT", + "source": 1 + }, + { + "begin": 470, + "end": 533, + "name": "tag", + "source": 1, + "value": "24" + }, + { + "begin": 470, + "end": 533, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 417, + "end": 539, + "name": "POP", + "source": 1 + }, + { + "begin": 417, + "end": 539, + "name": "JUMP", + "source": 1, + "value": "[out]" + }, + { + "begin": 545, + "end": 684, + "name": "tag", + "source": 1, + "value": "25" + }, + { + "begin": 545, + "end": 684, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 591, + "end": 596, + "name": "PUSH", + "source": 1, + "value": "0" + }, + { + "begin": 629, + "end": 635, + "name": "DUP2", + "source": 1 + }, + { + "begin": 616, + "end": 636, + "name": "CALLDATALOAD", + "source": 1 + }, + { + "begin": 607, + "end": 636, + "name": "SWAP1", + "source": 1 + }, + { + "begin": 607, + "end": 636, + "name": "POP", + "source": 1 + }, + { + "begin": 645, + "end": 678, + "name": "PUSH [tag]", + "source": 1, + "value": "27" + }, + { + "begin": 672, + "end": 677, + "name": "DUP2", + "source": 1 + }, + { + "begin": 645, + "end": 678, + "name": "PUSH [tag]", + "source": 1, + "value": "21" + }, + { + "begin": 645, + "end": 678, + "name": "JUMP", + "source": 1, + "value": "[in]" + }, + { + "begin": 645, + "end": 678, + "name": "tag", + "source": 1, + "value": "27" + }, + { + "begin": 645, + "end": 678, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 545, + "end": 684, + "name": "SWAP3", + "source": 1 + }, + { + "begin": 545, + "end": 684, + "name": "SWAP2", + "source": 1 + }, + { + "begin": 545, + "end": 684, + "name": "POP", + "source": 1 + }, + { + "begin": 545, + "end": 684, + "name": "POP", + "source": 1 + }, + { + "begin": 545, + "end": 684, + "name": "JUMP", + "source": 1, + "value": "[out]" + }, + { + "begin": 690, + "end": 1019, + "name": "tag", + "source": 1, + "value": "6" + }, + { + "begin": 690, + "end": 1019, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 749, + "end": 755, + "name": "PUSH", + "source": 1, + "value": "0" + }, + { + "begin": 798, + "end": 800, + "name": "PUSH", + "source": 1, + "value": "20" + }, + { + "begin": 786, + "end": 795, + "name": "DUP3", + "source": 1 + }, + { + "begin": 777, + "end": 784, + "name": "DUP5", + "source": 1 + }, + { + "begin": 773, + "end": 796, + "name": "SUB", + "source": 1 + }, + { + "begin": 769, + "end": 801, + "name": "SLT", + "source": 1 + }, + { + "begin": 766, + "end": 885, + "name": "ISZERO", + "source": 1 + }, + { + "begin": 766, + "end": 885, + "name": "PUSH [tag]", + "source": 1, + "value": "29" + }, + { + "begin": 766, + "end": 885, + "name": "JUMPI", + "source": 1 + }, + { + "begin": 804, + "end": 883, + "name": "PUSH [tag]", + "source": 1, + "value": "30" + }, + { + "begin": 804, + "end": 883, + "name": "PUSH [tag]", + "source": 1, + "value": "15" + }, + { + "begin": 804, + "end": 883, + "name": "JUMP", + "source": 1, + "value": "[in]" + }, + { + "begin": 804, + "end": 883, + "name": "tag", + "source": 1, + "value": "30" + }, + { + "begin": 804, + "end": 883, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 766, + "end": 885, + "name": "tag", + "source": 1, + "value": "29" + }, + { + "begin": 766, + "end": 885, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 924, + "end": 925, + "name": "PUSH", + "source": 1, + "value": "0" + }, + { + "begin": 949, + "end": 1002, + "name": "PUSH [tag]", + "source": 1, + "value": "31" + }, + { + "begin": 994, + "end": 1001, + "name": "DUP5", + "source": 1 + }, + { + "begin": 985, + "end": 991, + "name": "DUP3", + "source": 1 + }, + { + "begin": 974, + "end": 983, + "name": "DUP6", + "source": 1 + }, + { + "begin": 970, + "end": 992, + "name": "ADD", + "source": 1 + }, + { + "begin": 949, + "end": 1002, + "name": "PUSH [tag]", + "source": 1, + "value": "25" + }, + { + "begin": 949, + "end": 1002, + "name": "JUMP", + "source": 1, + "value": "[in]" + }, + { + "begin": 949, + "end": 1002, + "name": "tag", + "source": 1, + "value": "31" + }, + { + "begin": 949, + "end": 1002, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 939, + "end": 1002, + "name": "SWAP2", + "source": 1 + }, + { + "begin": 939, + "end": 1002, + "name": "POP", + "source": 1 + }, + { + "begin": 895, + "end": 1012, + "name": "POP", + "source": 1 + }, + { + "begin": 690, + "end": 1019, + "name": "SWAP3", + "source": 1 + }, + { + "begin": 690, + "end": 1019, + "name": "SWAP2", + "source": 1 + }, + { + "begin": 690, + "end": 1019, + "name": "POP", + "source": 1 + }, + { + "begin": 690, + "end": 1019, + "name": "POP", + "source": 1 + }, + { + "begin": 690, + "end": 1019, + "name": "JUMP", + "source": 1, + "value": "[out]" + }, + { + "begin": 1025, + "end": 1205, + "name": "tag", + "source": 1, + "value": "32" + }, + { + "begin": 1025, + "end": 1205, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 1073, + "end": 1150, + "name": "PUSH", + "source": 1, + "value": "4E487B7100000000000000000000000000000000000000000000000000000000" + }, + { + "begin": 1070, + "end": 1071, + "name": "PUSH", + "source": 1, + "value": "0" + }, + { + "begin": 1063, + "end": 1151, + "name": "MSTORE", + "source": 1 + }, + { + "begin": 1170, + "end": 1174, + "name": "PUSH", + "source": 1, + "value": "11" + }, + { + "begin": 1167, + "end": 1168, + "name": "PUSH", + "source": 1, + "value": "4" + }, + { + "begin": 1160, + "end": 1175, + "name": "MSTORE", + "source": 1 + }, + { + "begin": 1194, + "end": 1198, + "name": "PUSH", + "source": 1, + "value": "24" + }, + { + "begin": 1191, + "end": 1192, + "name": "PUSH", + "source": 1, + "value": "0" + }, + { + "begin": 1184, + "end": 1199, + "name": "REVERT", + "source": 1 + }, + { + "begin": 1211, + "end": 1516, + "name": "tag", + "source": 1, + "value": "10" + }, + { + "begin": 1211, + "end": 1516, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 1251, + "end": 1254, + "name": "PUSH", + "source": 1, + "value": "0" + }, + { + "begin": 1270, + "end": 1290, + "name": "PUSH [tag]", + "source": 1, + "value": "35" + }, + { + "begin": 1288, + "end": 1289, + "name": "DUP3", + "source": 1 + }, + { + "begin": 1270, + "end": 1290, + "name": "PUSH [tag]", + "source": 1, + "value": "19" + }, + { + "begin": 1270, + "end": 1290, + "name": "JUMP", + "source": 1, + "value": "[in]" + }, + { + "begin": 1270, + "end": 1290, + "name": "tag", + "source": 1, + "value": "35" + }, + { + "begin": 1270, + "end": 1290, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 1265, + "end": 1290, + "name": "SWAP2", + "source": 1 + }, + { + "begin": 1265, + "end": 1290, + "name": "POP", + "source": 1 + }, + { + "begin": 1304, + "end": 1324, + "name": "PUSH [tag]", + "source": 1, + "value": "36" + }, + { + "begin": 1322, + "end": 1323, + "name": "DUP4", + "source": 1 + }, + { + "begin": 1304, + "end": 1324, + "name": "PUSH [tag]", + "source": 1, + "value": "19" + }, + { + "begin": 1304, + "end": 1324, + "name": "JUMP", + "source": 1, + "value": "[in]" + }, + { + "begin": 1304, + "end": 1324, + "name": "tag", + "source": 1, + "value": "36" + }, + { + "begin": 1304, + "end": 1324, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 1299, + "end": 1324, + "name": "SWAP3", + "source": 1 + }, + { + "begin": 1299, + "end": 1324, + "name": "POP", + "source": 1 + }, + { + "begin": 1458, + "end": 1459, + "name": "DUP3", + "source": 1 + }, + { + "begin": 1390, + "end": 1456, + "name": "PUSH", + "source": 1, + "value": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + }, + { + "begin": 1386, + "end": 1460, + "name": "SUB", + "source": 1 + }, + { + "begin": 1383, + "end": 1384, + "name": "DUP3", + "source": 1 + }, + { + "begin": 1380, + "end": 1461, + "name": "GT", + "source": 1 + }, + { + "begin": 1377, + "end": 1484, + "name": "ISZERO", + "source": 1 + }, + { + "begin": 1377, + "end": 1484, + "name": "PUSH [tag]", + "source": 1, + "value": "37" + }, + { + "begin": 1377, + "end": 1484, + "name": "JUMPI", + "source": 1 + }, + { + "begin": 1464, + "end": 1482, + "name": "PUSH [tag]", + "source": 1, + "value": "38" + }, + { + "begin": 1464, + "end": 1482, + "name": "PUSH [tag]", + "source": 1, + "value": "32" + }, + { + "begin": 1464, + "end": 1482, + "name": "JUMP", + "source": 1, + "value": "[in]" + }, + { + "begin": 1464, + "end": 1482, + "name": "tag", + "source": 1, + "value": "38" + }, + { + "begin": 1464, + "end": 1482, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 1377, + "end": 1484, + "name": "tag", + "source": 1, + "value": "37" + }, + { + "begin": 1377, + "end": 1484, + "name": "JUMPDEST", + "source": 1 + }, + { + "begin": 1508, + "end": 1509, + "name": "DUP3", + "source": 1 + }, + { + "begin": 1505, + "end": 1506, + "name": "DUP3", + "source": 1 + }, + { + "begin": 1501, + "end": 1510, + "name": "ADD", + "source": 1 + }, + { + "begin": 1494, + "end": 1510, + "name": "SWAP1", + "source": 1 + }, + { + "begin": 1494, + "end": 1510, + "name": "POP", + "source": 1 + }, + { + "begin": 1211, + "end": 1516, + "name": "SWAP3", + "source": 1 + }, + { + "begin": 1211, + "end": 1516, + "name": "SWAP2", + "source": 1 + }, + { + "begin": 1211, + "end": 1516, + "name": "POP", + "source": 1 + }, + { + "begin": 1211, + "end": 1516, + "name": "POP", + "source": 1 + }, + { + "begin": 1211, + "end": 1516, + "name": "JUMP", + "source": 1, + "value": "[out]" + } + ] + } + } +} From b1351f4807fe8596a82fbcf26b22cced137fd6ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 21 Sep 2021 13:25:04 +0200 Subject: [PATCH 141/232] Fix typo in test name: `leave_items_on_tack.sol` -> `leave_items_on_stack.sol` --- .../invalid/{leave_items_on_tack.sol => leave_items_on_stack.sol} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/libsolidity/syntaxTests/inlineAssembly/invalid/{leave_items_on_tack.sol => leave_items_on_stack.sol} (100%) diff --git a/test/libsolidity/syntaxTests/inlineAssembly/invalid/leave_items_on_tack.sol b/test/libsolidity/syntaxTests/inlineAssembly/invalid/leave_items_on_stack.sol similarity index 100% rename from test/libsolidity/syntaxTests/inlineAssembly/invalid/leave_items_on_tack.sol rename to test/libsolidity/syntaxTests/inlineAssembly/invalid/leave_items_on_stack.sol From 0f326ada5cd7cb149d9f7514272c9f9c837a2b37 Mon Sep 17 00:00:00 2001 From: Marenz Date: Tue, 21 Sep 2021 18:01:12 +0200 Subject: [PATCH 142/232] Sort changelog "bugfixes" alphabetically --- Changelog.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Changelog.md b/Changelog.md index eae8eb8be..2d0a1e484 100644 --- a/Changelog.md +++ b/Changelog.md @@ -19,15 +19,15 @@ Compiler Features: Bugfixes: * Code Generator: Fix ICE on assigning to calldata structs and statically-sized calldata arrays in inline assembly. * Code Generator: Use stable source order for ABI functions. - * Commandline Interface: Report optimizer options as invalid in Standard JSON and linker modes instead of ignoring them. * Commandline Interface: Disallow the ``--experimental-via-ir`` option in Standard JSON, Assembler and Linker modes. - * Opcode Optimizer: Prevent the optimizer from running multiple times to avoid potential bytecode differences for referenced code. + * Commandline Interface: Report optimizer options as invalid in Standard JSON and linker modes instead of ignoring them. * Name Resolver: Fix that when importing an aliased symbol using ``import {AliasedName} from "a.sol"`` it would use the original name of the symbol and not the aliased one. + * Opcode Optimizer: Prevent the optimizer from running multiple times to avoid potential bytecode differences for referenced code. * Parser: Properly check for multiple SPDX license identifiers next to each other and validate them. + * SMTChecker: Fix BMC's constraints regarding internal functions. * SMTChecker: Fix false negative caused by ``push`` on storage array references returned by internal functions. * SMTChecker: Fix false positive in external calls from constructors. * SMTChecker: Fix internal error on some multi-source uses of ``abi.*``, cryptographic functions and constants. - * SMTChecker: Fix BMC's constraints regarding internal functions. * Standard JSON: Fix non-fatal errors in Yul mode being discarded if followed by a fatal error. * Type Checker: Disallow modifier declarations and definitions in interfaces. * Yul Optimizer: Fix a crash in LoadResolver, when ``keccak256`` has particular non-identifier arguments. From 7a51acc5fe3458d6c76c81ae409761dfd4be9be5 Mon Sep 17 00:00:00 2001 From: Marenz Date: Tue, 21 Sep 2021 18:02:20 +0200 Subject: [PATCH 143/232] Correct wrong error message referencing `.slot` and `.offset` when `.length` was used --- Changelog.md | 1 + libsolidity/analysis/TypeChecker.cpp | 4 ++-- .../inlineAssembly/invalid/constant_length_access.sol | 10 ++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 test/libsolidity/syntaxTests/inlineAssembly/invalid/constant_length_access.sol diff --git a/Changelog.md b/Changelog.md index 2d0a1e484..eacd9777b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -29,6 +29,7 @@ Bugfixes: * SMTChecker: Fix false positive in external calls from constructors. * SMTChecker: Fix internal error on some multi-source uses of ``abi.*``, cryptographic functions and constants. * Standard JSON: Fix non-fatal errors in Yul mode being discarded if followed by a fatal error. + * Type Checker: Correct wrong error message in inline assembly complaining about ``.slot`` or ``.offset` not valid when actually ``.length`` was used. * Type Checker: Disallow modifier declarations and definitions in interfaces. * Yul Optimizer: Fix a crash in LoadResolver, when ``keccak256`` has particular non-identifier arguments. diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index afcf92525..c9772f1c8 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -799,7 +799,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) m_errorReporter.typeError(6252_error, _identifier.debugData->location, "Constant variables cannot be assigned to."); return false; } - else if (!identifierInfo.suffix.empty()) + else if (identifierInfo.suffix == "slot" || identifierInfo.suffix == "offset") { m_errorReporter.typeError(6617_error, _identifier.debugData->location, "The suffixes .offset and .slot can only be used on non-constant storage variables."); return false; @@ -829,7 +829,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) { string const& suffix = identifierInfo.suffix; solAssert((set{"offset", "slot", "length"}).count(suffix), ""); - if (var->isStateVariable() || var->type()->dataStoredIn(DataLocation::Storage)) + if (!var->isConstant() && (var->isStateVariable() || var->type()->dataStoredIn(DataLocation::Storage))) { if (suffix != "slot" && suffix != "offset") { diff --git a/test/libsolidity/syntaxTests/inlineAssembly/invalid/constant_length_access.sol b/test/libsolidity/syntaxTests/inlineAssembly/invalid/constant_length_access.sol new file mode 100644 index 000000000..eda71f955 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/invalid/constant_length_access.sol @@ -0,0 +1,10 @@ +contract Test { + uint constant x = 2; + function f() public pure { + assembly { + let y := x.length + } + } +} +// ---- +// TypeError 3622: (91-99): The suffix ".length" is not supported by this variable or type. From 4fd5093d9421c939c2895b3ec620127f99abceba Mon Sep 17 00:00:00 2001 From: hawkess Date: Mon, 20 Sep 2021 13:22:58 -0500 Subject: [PATCH 144/232] Removed pointer to external editor resource in IsolTestOptions, changed TestTool::handleResponse() to get editor value from m_options member variable --- test/tools/IsolTestOptions.cpp | 6 ++---- test/tools/IsolTestOptions.h | 4 ++-- test/tools/isoltest.cpp | 7 ++----- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/test/tools/IsolTestOptions.cpp b/test/tools/IsolTestOptions.cpp index 3aecaeefa..7f00e88f6 100644 --- a/test/tools/IsolTestOptions.cpp +++ b/test/tools/IsolTestOptions.cpp @@ -56,20 +56,18 @@ std::string editorPath() } -IsolTestOptions::IsolTestOptions(std::string* _editor): +IsolTestOptions::IsolTestOptions(): CommonOptions(description) { - editor = _editor; enforceViaYul = true; enforceGasTest = (evmVersion() == langutil::EVMVersion{}); - enforceGasTestMinValue = 100000; } void IsolTestOptions::addOptions() { CommonOptions::addOptions(); options.add_options() - ("editor", po::value(editor)->default_value(editorPath()), "Path to editor for opening test files.") + ("editor", po::value(&editor)->default_value(editorPath()), "Path to editor for opening test files.") ("help", po::bool_switch(&showHelp)->default_value(showHelp), "Show this help screen.") ("no-color", po::bool_switch(&noColor)->default_value(noColor), "Don't use colors.") ("accept-updates", po::bool_switch(&acceptUpdates)->default_value(acceptUpdates), "Automatically accept expectation updates.") diff --git a/test/tools/IsolTestOptions.h b/test/tools/IsolTestOptions.h index f889f5b8f..5bb02c2bc 100644 --- a/test/tools/IsolTestOptions.h +++ b/test/tools/IsolTestOptions.h @@ -33,9 +33,9 @@ struct IsolTestOptions: CommonOptions bool noColor = false; bool acceptUpdates = false; std::string testFilter = std::string{}; - std::string* editor = nullptr; + std::string editor = std::string{}; - explicit IsolTestOptions(std::string* _editor); + explicit IsolTestOptions(); void addOptions() override; bool parse(int _argc, char const* const* _argv) override; void validate() const override; diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp index fa7b914aa..73adbc62b 100644 --- a/test/tools/isoltest.cpp +++ b/test/tools/isoltest.cpp @@ -121,8 +121,6 @@ public: fs::path const& _basepath, fs::path const& _path ); - - static string editor; private: enum class Request { @@ -145,7 +143,6 @@ private: static bool m_exitRequested; }; -string TestTool::editor; bool TestTool::m_exitRequested = false; TestTool::Result TestTool::process() @@ -258,7 +255,7 @@ TestTool::Request TestTool::handleResponse(bool _exception) } case 'e': cout << endl << endl; - if (system((TestTool::editor + " \"" + m_path.string() + "\"").c_str())) + if (system((m_options.editor + " \"" + m_path.string() + "\"").c_str())) cerr << "Error running editor command." << endl << endl; return Request::Rerun; case 'q': @@ -425,7 +422,7 @@ int main(int argc, char const *argv[]) setupTerminal(); { - auto options = std::make_unique(&TestTool::editor); + auto options = std::make_unique(); if (!options->parse(argc, argv)) return -1; From e6f0fe8ae3fedd41dcfb24d2ecea39215e5dae6f Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 9 Sep 2021 16:35:15 +0200 Subject: [PATCH 145/232] Use source id in yul to evm code transform. --- libyul/backends/evm/EVMCodeTransform.cpp | 41 ++++++++++++++++------- libyul/backends/evm/EVMCodeTransform.h | 3 +- libyul/backends/evm/EVMObjectCompiler.cpp | 11 +++++- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index 824a4b025..3ae8d7144 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -252,7 +252,7 @@ void CodeTransform::operator()(FunctionCall const& _call) visitExpression(arg); m_assembly.setSourceLocation(locationOf(_call)); m_assembly.appendJumpTo( - functionEntryID(_call.functionName.name, *function), + functionEntryID(*function), static_cast(function->returns.size() - function->arguments.size()) - 1, AbstractAssembly::JumpType::IntoFunction ); @@ -374,7 +374,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function) m_assembly.setSourceLocation(locationOf(_function)); int const stackHeightBefore = m_assembly.stackHeight(); - m_assembly.appendLabel(functionEntryID(_function.name, function)); + m_assembly.appendLabel(functionEntryID(function)); m_assembly.setStackHeight(static_cast(height)); @@ -563,6 +563,10 @@ void CodeTransform::operator()(Block const& _block) Scope* originalScope = m_scope; m_scope = m_info.scopes.at(&_block).get(); + for (auto const& statement: _block.statements) + if (auto function = get_if(&statement)) + createFunctionEntryID(*function); + int blockStartStackHeight = m_assembly.stackHeight(); visitStatements(_block.statements); @@ -572,17 +576,30 @@ void CodeTransform::operator()(Block const& _block) m_scope = originalScope; } -AbstractAssembly::LabelID CodeTransform::functionEntryID(YulString _name, Scope::Function const& _function) +void CodeTransform::createFunctionEntryID(FunctionDefinition const& _function) { - if (!m_context->functionEntryIDs.count(&_function)) - { - AbstractAssembly::LabelID id = - m_useNamedLabelsForFunctions ? - m_assembly.namedLabel(_name.str(), _function.arguments.size(), _function.returns.size(), {}) : - m_assembly.newLabelId(); - m_context->functionEntryIDs[&_function] = id; - } - return m_context->functionEntryIDs[&_function]; + Scope::Function& scopeFunction = std::get(m_scope->identifiers.at(_function.name)); + yulAssert(!m_context->functionEntryIDs.count(&scopeFunction), ""); + + optional astID; + if (_function.debugData) + astID = _function.debugData->astID; + + m_context->functionEntryIDs[&scopeFunction] = + m_useNamedLabelsForFunctions ? + m_assembly.namedLabel( + _function.name.str(), + _function.parameters.size(), + _function.returnVariables.size(), + astID + ) : + m_assembly.newLabelId(); +} + +AbstractAssembly::LabelID CodeTransform::functionEntryID(Scope::Function const& _scopeFunction) const +{ + yulAssert(m_context->functionEntryIDs.count(&_scopeFunction), ""); + return m_context->functionEntryIDs.at(&_scopeFunction); } void CodeTransform::visitExpression(Expression const& _expression) diff --git a/libyul/backends/evm/EVMCodeTransform.h b/libyul/backends/evm/EVMCodeTransform.h index 8bbd3b818..8a605b472 100644 --- a/libyul/backends/evm/EVMCodeTransform.h +++ b/libyul/backends/evm/EVMCodeTransform.h @@ -142,7 +142,8 @@ public: private: AbstractAssembly::LabelID labelFromIdentifier(Identifier const& _identifier); - AbstractAssembly::LabelID functionEntryID(YulString _name, Scope::Function const& _function); + void createFunctionEntryID(FunctionDefinition const& _function); + AbstractAssembly::LabelID functionEntryID(Scope::Function const& _scopeFunction) const; /// Generates code for an expression that is supposed to return a single value. void visitExpression(Expression const& _expression); diff --git a/libyul/backends/evm/EVMObjectCompiler.cpp b/libyul/backends/evm/EVMObjectCompiler.cpp index f65f7f1e3..a526bf218 100644 --- a/libyul/backends/evm/EVMObjectCompiler.cpp +++ b/libyul/backends/evm/EVMObjectCompiler.cpp @@ -64,7 +64,16 @@ void EVMObjectCompiler::run(Object& _object, bool _optimize) yulAssert(_object.code, "No code."); // We do not catch and re-throw the stack too deep exception here because it is a YulException, // which should be native to this part of the code. - CodeTransform transform{m_assembly, *_object.analysisInfo, *_object.code, m_dialect, context, _optimize}; + CodeTransform transform{ + m_assembly, + *_object.analysisInfo, + *_object.code, + m_dialect, + context, + _optimize, + {}, + true /* _useNamedLabelsForFunctions */ + }; transform(*_object.code); if (!transform.stackErrors().empty()) BOOST_THROW_EXCEPTION(transform.stackErrors().front()); From 274117550748739aebbb328034304f095f320347 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 9 Sep 2021 18:15:43 +0200 Subject: [PATCH 146/232] Use function debug data. --- libevmasm/Assembly.cpp | 9 +++++++++ libevmasm/LinkerObject.h | 1 + libsolidity/interface/CompilerStack.cpp | 14 ++++---------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index acf655c82..37b6ea33a 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -38,6 +38,7 @@ #include #include +#include using namespace std; using namespace solidity; @@ -761,8 +762,16 @@ LinkerObject const& Assembly::assemble() const for (auto const& [name, tagInfo]: m_namedTags) { size_t position = m_tagPositionsInBytecode.at(tagInfo.id); + optional tagIndex; + for (auto&& [index, item]: m_items | ranges::views::enumerate) + if (item.type() == Tag && static_cast(item.data()) == tagInfo.id) + { + tagIndex = index; + break; + } ret.functionDebugData[name] = { position == numeric_limits::max() ? nullopt : optional{position}, + tagIndex, tagInfo.sourceID, tagInfo.params, tagInfo.returns diff --git a/libevmasm/LinkerObject.h b/libevmasm/LinkerObject.h index e512dd7ab..c23426882 100644 --- a/libevmasm/LinkerObject.h +++ b/libevmasm/LinkerObject.h @@ -48,6 +48,7 @@ struct LinkerObject struct FunctionDebugData { std::optional bytecodeOffset; + std::optional instructionIndex; std::optional sourceID; size_t params = {}; size_t returns = {}; diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 3b5fb8cb5..1703aa6cc 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -1054,16 +1054,10 @@ size_t CompilerStack::functionEntryPoint( if (m_stackState != CompilationSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); - shared_ptr const& compiler = contract(_contractName).compiler; - if (!compiler) - return 0; - evmasm::AssemblyItem tag = compiler->functionEntryLabel(_function); - if (tag.type() == evmasm::UndefinedItem) - return 0; - evmasm::AssemblyItems const& items = compiler->runtimeAssembly().items(); - for (size_t i = 0; i < items.size(); ++i) - if (items.at(i).type() == evmasm::Tag && items.at(i).data() == tag.data()) - return i; + for (auto&& [name, data]: contract(_contractName).runtimeObject.functionDebugData) + if (data.sourceID == _function.id()) + if (data.instructionIndex) + return *data.instructionIndex; return 0; } From 76372860741f8dd77f50b75dd696bf869acf2dc4 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 9 Sep 2021 18:37:44 +0200 Subject: [PATCH 147/232] Remove unused function. --- libsolidity/codegen/Compiler.cpp | 5 ----- libsolidity/codegen/Compiler.h | 4 ---- 2 files changed, 9 deletions(-) diff --git a/libsolidity/codegen/Compiler.cpp b/libsolidity/codegen/Compiler.cpp index e3308b2de..c044760a0 100644 --- a/libsolidity/codegen/Compiler.cpp +++ b/libsolidity/codegen/Compiler.cpp @@ -60,8 +60,3 @@ std::shared_ptr Compiler::runtimeAssemblyPtr() const solAssert(m_context.runtimeContext(), ""); return m_context.runtimeContext()->assemblyPtr(); } - -evmasm::AssemblyItem Compiler::functionEntryLabel(FunctionDefinition const& _function) const -{ - return m_runtimeContext.functionEntryLabelIfExists(_function); -} diff --git a/libsolidity/codegen/Compiler.h b/libsolidity/codegen/Compiler.h index 0d021b723..1267c1a2d 100644 --- a/libsolidity/codegen/Compiler.h +++ b/libsolidity/codegen/Compiler.h @@ -62,10 +62,6 @@ public: std::string generatedYulUtilityCode() const { return m_context.generatedYulUtilityCode(); } std::string runtimeGeneratedYulUtilityCode() const { return m_runtimeContext.generatedYulUtilityCode(); } - /// @returns the entry label of the given function. Might return an AssemblyItem of type - /// UndefinedItem if it does not exist yet. - evmasm::AssemblyItem functionEntryLabel(FunctionDefinition const& _function) const; - private: OptimiserSettings const m_optimiserSettings; CompilerContext m_runtimeContext; From 50ce1f5dddc92b6a30f3c860e7cf51e9a0e245ae Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 22 Sep 2021 11:19:53 +0200 Subject: [PATCH 148/232] Disambiguate bytesRequired --- libevmasm/Assembly.cpp | 16 ++++++++-------- libevmasm/Assembly.h | 2 +- libevmasm/AssemblyItem.cpp | 2 +- libevmasm/ConstantOptimiser.cpp | 2 +- libsolidity/ast/Types.cpp | 4 ++-- libsolutil/CommonData.h | 2 +- libyul/backends/evm/ConstantOptimiser.cpp | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index acf655c82..a97499c3f 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -56,7 +56,7 @@ AssemblyItem const& Assembly::append(AssemblyItem const& _i) return m_items.back(); } -unsigned Assembly::bytesRequired(unsigned subTagSize) const +unsigned Assembly::codeSize(unsigned subTagSize) const { for (unsigned tagSize = subTagSize; true; ++tagSize) { @@ -66,7 +66,7 @@ unsigned Assembly::bytesRequired(unsigned subTagSize) const for (AssemblyItem const& i: m_items) ret += i.bytesRequired(tagSize); - if (util::bytesRequired(ret) <= tagSize) + if (util::numberEncodingSize(ret) <= tagSize) return static_cast(ret); } } @@ -589,20 +589,20 @@ LinkerObject const& Assembly::assemble() const "Cannot push and assign immutables in the same assembly subroutine." ); - unsigned bytesRequiredForCode = bytesRequired(static_cast(subTagSize)); + unsigned bytesRequiredForCode = codeSize(static_cast(subTagSize)); m_tagPositionsInBytecode = vector(m_usedTags, numeric_limits::max()); map> tagRef; multimap dataRef; multimap subRef; vector sizeRef; ///< Pointers to code locations where the size of the program is inserted - unsigned bytesPerTag = util::bytesRequired(bytesRequiredForCode); + unsigned bytesPerTag = util::numberEncodingSize(bytesRequiredForCode); uint8_t tagPush = static_cast(pushInstruction(bytesPerTag)); unsigned bytesRequiredIncludingData = bytesRequiredForCode + 1 + static_cast(m_auxiliaryData.size()); for (auto const& sub: m_subs) bytesRequiredIncludingData += static_cast(sub->assemble().bytecode.size()); - unsigned bytesPerDataRef = util::bytesRequired(bytesRequiredIncludingData); + unsigned bytesPerDataRef = util::numberEncodingSize(bytesRequiredIncludingData); uint8_t dataRefPush = static_cast(pushInstruction(bytesPerDataRef)); ret.bytecode.reserve(bytesRequiredIncludingData); @@ -619,7 +619,7 @@ LinkerObject const& Assembly::assemble() const break; case Push: { - unsigned b = max(1, util::bytesRequired(i.data())); + unsigned b = max(1, util::numberEncodingSize(i.data())); ret.bytecode.push_back(static_cast(pushInstruction(b))); ret.bytecode.resize(ret.bytecode.size() + b); bytesRef byr(&ret.bytecode.back() + 1 - b, b); @@ -649,7 +649,7 @@ LinkerObject const& Assembly::assemble() const assertThrow(i.data() <= numeric_limits::max(), AssemblyException, ""); auto s = subAssemblyById(static_cast(i.data()))->assemble().bytecode.size(); i.setPushedValue(u256(s)); - unsigned b = max(1, util::bytesRequired(s)); + unsigned b = max(1, util::numberEncodingSize(s)); ret.bytecode.push_back(static_cast(pushInstruction(b))); ret.bytecode.resize(ret.bytecode.size() + b); bytesRef byr(&ret.bytecode.back() + 1 - b, b); @@ -754,7 +754,7 @@ LinkerObject const& Assembly::assemble() const assertThrow(tagId < tagPositions.size(), AssemblyException, "Reference to non-existing tag."); size_t pos = tagPositions[tagId]; assertThrow(pos != numeric_limits::max(), AssemblyException, "Reference to tag without position."); - assertThrow(util::bytesRequired(pos) <= bytesPerTag, AssemblyException, "Tag too large for reserved space."); + assertThrow(util::numberEncodingSize(pos) <= bytesPerTag, AssemblyException, "Tag too large for reserved space."); bytesRef r(ret.bytecode.data() + i.first, bytesPerTag); toBigEndian(pos, r); } diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index 732aa14a1..1d91c2f90 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -167,7 +167,7 @@ protected: /// that are referenced in a super-assembly. std::map const& optimiseInternal(OptimiserSettings const& _settings, std::set _tagsReferencedFromOutside); - unsigned bytesRequired(unsigned subTagSize) const; + unsigned codeSize(unsigned subTagSize) const; private: static Json::Value createJsonValue( diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index 462199ba4..6c10428dc 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -71,7 +71,7 @@ size_t AssemblyItem::bytesRequired(size_t _addressLength) const case Tag: // 1 byte for the JUMPDEST return 1; case Push: - return 1 + max(1, util::bytesRequired(data())); + return 1 + max(1, util::numberEncodingSize(data())); case PushSubSize: case PushProgramSize: return 1 + 4; // worst case: a 16MB program diff --git a/libevmasm/ConstantOptimiser.cpp b/libevmasm/ConstantOptimiser.cpp index a6bb342bc..3b582b7f4 100644 --- a/libevmasm/ConstantOptimiser.cpp +++ b/libevmasm/ConstantOptimiser.cpp @@ -192,7 +192,7 @@ AssemblyItems ComputeMethod::findRepresentation(u256 const& _value) if (_value < 0x10000) // Very small value, not worth computing return AssemblyItems{_value}; - else if (util::bytesRequired(~_value) < util::bytesRequired(_value)) + else if (util::numberEncodingSize(~_value) < util::numberEncodingSize(_value)) // Negated is shorter to represent return findRepresentation(~_value) + AssemblyItems{Instruction::NOT}; else diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 67e8e5168..ffb8dea4b 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1135,7 +1135,7 @@ IntegerType const* RationalNumberType::integerType() const return nullptr; else return TypeProvider::integer( - max(util::bytesRequired(value), 1u) * 8, + max(util::numberEncodingSize(value), 1u) * 8, negative ? IntegerType::Modifier::Signed : IntegerType::Modifier::Unsigned ); } @@ -1169,7 +1169,7 @@ FixedPointType const* RationalNumberType::fixedPointType() const if (v > u256(-1)) return nullptr; - unsigned totalBits = max(util::bytesRequired(v), 1u) * 8; + unsigned totalBits = max(util::numberEncodingSize(v), 1u) * 8; solAssert(totalBits <= 256, ""); return TypeProvider::fixedPoint( diff --git a/libsolutil/CommonData.h b/libsolutil/CommonData.h index 774cedf0a..71387558c 100644 --- a/libsolutil/CommonData.h +++ b/libsolutil/CommonData.h @@ -512,7 +512,7 @@ inline std::string formatNumber(u256 const& _value) /// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero. template -inline unsigned bytesRequired(T _i) +inline unsigned numberEncodingSize(T _i) { static_assert(std::is_same::value || !std::numeric_limits::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift unsigned i = 0; diff --git a/libyul/backends/evm/ConstantOptimiser.cpp b/libyul/backends/evm/ConstantOptimiser.cpp index 09d87da83..aecd00bf4 100644 --- a/libyul/backends/evm/ConstantOptimiser.cpp +++ b/libyul/backends/evm/ConstantOptimiser.cpp @@ -128,7 +128,7 @@ Representation const& RepresentationFinder::findRepresentation(u256 const& _valu Representation routine = represent(_value); - if (bytesRequired(~_value) < bytesRequired(_value)) + if (numberEncodingSize(~_value) < numberEncodingSize(_value)) // Negated is shorter to represent routine = min(move(routine), represent("not"_yulstring, findRepresentation(~_value))); From 7726f37946a8bd5b5493abd0da5f48f90e24104a Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 15 Sep 2021 17:57:15 +0200 Subject: [PATCH 149/232] Update tests. --- test/cmdlineTests/asm_json/output | 48 +-- .../function_debug_info_via_yul/output | 15 +- .../output.json | 310 +++++++++--------- .../libyul/objectCompiler/function_series.yul | 10 +- test/libyul/objectCompiler/jump_tags.yul | 20 +- 5 files changed, 208 insertions(+), 195 deletions(-) diff --git a/test/cmdlineTests/asm_json/output b/test/cmdlineTests/asm_json/output index bd7a9c223..26ab87147 100644 --- a/test/cmdlineTests/asm_json/output +++ b/test/cmdlineTests/asm_json/output @@ -666,7 +666,7 @@ EVM assembly: "end": 205, "name": "tag", "source": 1, - "value": "15" + "value": "13" }, { "begin": 88, @@ -698,7 +698,7 @@ EVM assembly: "end": 411, "name": "tag", "source": 1, - "value": "19" + "value": "15" }, { "begin": 334, @@ -761,7 +761,7 @@ EVM assembly: "end": 539, "name": "tag", "source": 1, - "value": "21" + "value": "16" }, { "begin": 417, @@ -774,7 +774,7 @@ EVM assembly: "end": 514, "name": "PUSH [tag]", "source": 1, - "value": "23" + "value": "25" }, { "begin": 508, @@ -787,7 +787,7 @@ EVM assembly: "end": 514, "name": "PUSH [tag]", "source": 1, - "value": "19" + "value": "15" }, { "begin": 490, @@ -801,7 +801,7 @@ EVM assembly: "end": 514, "name": "tag", "source": 1, - "value": "23" + "value": "25" }, { "begin": 490, @@ -826,7 +826,7 @@ EVM assembly: "end": 533, "name": "PUSH [tag]", "source": 1, - "value": "24" + "value": "26" }, { "begin": 470, @@ -858,7 +858,7 @@ EVM assembly: "end": 533, "name": "tag", "source": 1, - "value": "24" + "value": "26" }, { "begin": 470, @@ -884,7 +884,7 @@ EVM assembly: "end": 684, "name": "tag", "source": 1, - "value": "25" + "value": "17" }, { "begin": 545, @@ -928,7 +928,7 @@ EVM assembly: "end": 678, "name": "PUSH [tag]", "source": 1, - "value": "27" + "value": "28" }, { "begin": 672, @@ -941,7 +941,7 @@ EVM assembly: "end": 678, "name": "PUSH [tag]", "source": 1, - "value": "21" + "value": "16" }, { "begin": 645, @@ -955,7 +955,7 @@ EVM assembly: "end": 678, "name": "tag", "source": 1, - "value": "27" + "value": "28" }, { "begin": 645, @@ -1056,7 +1056,7 @@ EVM assembly: "end": 885, "name": "PUSH [tag]", "source": 1, - "value": "29" + "value": "30" }, { "begin": 766, @@ -1069,14 +1069,14 @@ EVM assembly: "end": 883, "name": "PUSH [tag]", "source": 1, - "value": "30" + "value": "31" }, { "begin": 804, "end": 883, "name": "PUSH [tag]", "source": 1, - "value": "15" + "value": "13" }, { "begin": 804, @@ -1090,7 +1090,7 @@ EVM assembly: "end": 883, "name": "tag", "source": 1, - "value": "30" + "value": "31" }, { "begin": 804, @@ -1103,7 +1103,7 @@ EVM assembly: "end": 885, "name": "tag", "source": 1, - "value": "29" + "value": "30" }, { "begin": 766, @@ -1123,7 +1123,7 @@ EVM assembly: "end": 1002, "name": "PUSH [tag]", "source": 1, - "value": "31" + "value": "32" }, { "begin": 994, @@ -1154,7 +1154,7 @@ EVM assembly: "end": 1002, "name": "PUSH [tag]", "source": 1, - "value": "25" + "value": "17" }, { "begin": 949, @@ -1168,7 +1168,7 @@ EVM assembly: "end": 1002, "name": "tag", "source": 1, - "value": "31" + "value": "32" }, { "begin": 949, @@ -1230,7 +1230,7 @@ EVM assembly: "end": 1205, "name": "tag", "source": 1, - "value": "32" + "value": "18" }, { "begin": 1025, @@ -1336,7 +1336,7 @@ EVM assembly: "end": 1290, "name": "PUSH [tag]", "source": 1, - "value": "19" + "value": "15" }, { "begin": 1270, @@ -1388,7 +1388,7 @@ EVM assembly: "end": 1324, "name": "PUSH [tag]", "source": 1, - "value": "19" + "value": "15" }, { "begin": 1304, @@ -1484,7 +1484,7 @@ EVM assembly: "end": 1482, "name": "PUSH [tag]", "source": 1, - "value": "32" + "value": "18" }, { "begin": 1464, diff --git a/test/cmdlineTests/function_debug_info_via_yul/output b/test/cmdlineTests/function_debug_info_via_yul/output index 5af245ce4..8b952a9e9 100644 --- a/test/cmdlineTests/function_debug_info_via_yul/output +++ b/test/cmdlineTests/function_debug_info_via_yul/output @@ -4,7 +4,20 @@ "function_debug_info_via_yul/input.sol:C": { "function-debug": {}, - "function-debug-runtime": {} + "function-debug-runtime": + { + "abi_encode_uint256": + { + "parameterSlots": 2, + "returnSlots": 1 + }, + "calldata_array_index_access_uint256_dyn_calldata": + { + "entryPoint": 168, + "parameterSlots": 2, + "returnSlots": 1 + } + } } }, "version": "" diff --git a/test/cmdlineTests/standard_debug_info_in_evm_asm_via_ir_location/output.json b/test/cmdlineTests/standard_debug_info_in_evm_asm_via_ir_location/output.json index 56e0a6f31..3b25e108a 100644 --- a/test/cmdlineTests/standard_debug_info_in_evm_asm_via_ir_location/output.json +++ b/test/cmdlineTests/standard_debug_info_in_evm_asm_via_ir_location/output.json @@ -1,10 +1,10 @@ {"contracts":{"C":{"C":{"evm":{"assembly":" /* \"C\":79:428 contract C... */ mstore(0x40, 0xa0) - jumpi(tag_1, iszero(callvalue)) + jumpi(tag_2, iszero(callvalue)) 0x00 dup1 revert -tag_1: +tag_2: bytecodeSize codesize dup2 @@ -27,12 +27,12 @@ tag_1: lt or iszero - tag_2 + tag_3 jumpi mstore(0x00, shl(0xe0, 0x4e487b71)) mstore(0x04, 0x41) revert(0x00, 0x24) -tag_2: +tag_3: 0x40 mstore dup1 @@ -43,15 +43,15 @@ tag_2: dup2 slt iszero - tag_3 + tag_4 jumpi 0x00 dup1 revert -tag_3: +tag_4: pop pop - tag_4 + tag_5 mload(0xa0) /* \"C\":147:149 42 */ mstore(0x80, 0x2a) @@ -62,7 +62,7 @@ tag_3: /* \"C\":175:223 constructor(int _init)... */ jump /* \"C\":79:428 contract C... */ -tag_4: +tag_5: mload(0x40) dataSize(sub_0) dup1 @@ -80,7 +80,7 @@ stop sub_0: assembly { /* \"C\":79:428 contract C... */ mstore(0x40, 0x80) - jumpi(tag_1, lt(calldatasize, 0x04)) + jumpi(tag_8, lt(calldatasize, 0x04)) 0x00 dup1 calldataload @@ -89,38 +89,38 @@ sub_0: assembly { 0x26121ff0 dup2 eq - tag_3 + tag_10 jumpi 0x793816ec dup2 eq - tag_4 + tag_11 jumpi 0x9942ec6f dup2 eq - tag_5 + tag_12 jumpi - jump(tag_2) - tag_3: - jumpi(tag_6, iszero(callvalue)) + jump(tag_9) + tag_10: + jumpi(tag_13, iszero(callvalue)) dup2 dup3 revert - tag_6: - tag_7 + tag_13: + tag_14 calldatasize - tag_8 + tag_1 jump\t// in - tag_7: + tag_14: /* \"C\":279:298 constVar + immutVar */ - tag_9 + tag_15 /* \"C\":290:298 immutVar */ immutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\") /* \"C\":279:298 constVar + immutVar */ - tag_10 + tag_4 jump\t// in - tag_9: + tag_15: /* \"C\":79:428 contract C... */ mload(0x40) dup2 @@ -129,17 +129,17 @@ sub_0: assembly { 0x20 dup2 return - tag_4: - jumpi(tag_13, iszero(callvalue)) + tag_11: + jumpi(tag_17, iszero(callvalue)) dup2 dup3 revert - tag_13: - tag_14 + tag_17: + tag_18 calldatasize - tag_8 + tag_1 jump\t// in - tag_14: + tag_18: dup2 sload mload(0x40) @@ -149,50 +149,50 @@ sub_0: assembly { 0x20 dup2 return - tag_5: - jumpi(tag_16, iszero(callvalue)) + tag_12: + jumpi(tag_20, iszero(callvalue)) dup2 dup3 revert - tag_16: - tag_17 + tag_20: + tag_21 calldatasize - tag_8 + tag_1 jump\t// in - tag_17: + tag_21: /* \"C\":375:378 int */ - tag_9 - tag_19 + tag_15 + tag_6 jump\t// in /* \"C\":79:428 contract C... */ - tag_2: + tag_9: pop pop - tag_1: + tag_8: 0x00 dup1 revert - tag_8: + tag_1: 0x00 not(0x03) dup3 add slt iszero - tag_23 + tag_26 jumpi 0x00 dup1 revert - tag_23: + tag_26: pop jump\t// out /* \"C\":117:119 41 */ - tag_25: + tag_3: mstore(0x00, shl(0xe0, 0x4e487b71)) mstore(0x04, 0x11) revert(0x00, 0x24) - tag_10: + tag_4: 0x00 sub(shl(0xff, 0x01), 0x2a) dup3 @@ -200,18 +200,18 @@ sub_0: assembly { 0x01 and iszero - tag_29 + tag_31 jumpi - tag_29 - tag_25 + tag_31 + tag_3 jump\t// in - tag_29: + tag_31: pop 0x29 add swap1 jump\t// out - tag_30: + tag_5: 0x00 dup1 dup3 @@ -226,12 +226,12 @@ sub_0: assembly { sgt and iszero - tag_33 + tag_34 jumpi - tag_33 - tag_25 + tag_34 + tag_3 jump\t// in - tag_33: + tag_34: shl(0xff, 0x01) dup4 swap1 @@ -241,19 +241,19 @@ sub_0: assembly { dup2 and iszero - tag_35 + tag_36 jumpi - tag_35 - tag_25 + tag_36 + tag_3 jump\t// in - tag_35: + tag_36: pop pop add swap1 jump\t// out /* \"C\":304:341 modifier m()... */ - tag_19: + tag_6: 0x00 /* \"C\":79:428 contract C... */ dup1 @@ -266,12 +266,12 @@ sub_0: assembly { dup2 eq iszero - tag_38 + tag_39 jumpi - tag_38 - tag_25 + tag_39 + tag_3 jump\t// in - tag_38: + tag_39: /* \"C\":117:119 41 */ 0x01 /* \"C\":79:428 contract C... */ @@ -283,14 +283,14 @@ sub_0: assembly { address /* \"C\":403:411 this.f() */ extcodesize - tag_39 + tag_40 jumpi /* \"C\":79:428 contract C... */ dup2 dup3 revert /* \"C\":403:411 this.f() */ - tag_39: + tag_40: /* \"C\":79:428 contract C... */ mload(0x40) shl(0xe4, 0x026121ff) @@ -310,7 +310,7 @@ sub_0: assembly { gas staticcall dup1 - tag_40 + tag_41 jumpi /* \"C\":79:428 contract C... */ mload(0x40) @@ -322,13 +322,13 @@ sub_0: assembly { dup2 revert /* \"C\":403:411 this.f() */ - tag_40: + tag_41: /* \"C\":79:428 contract C... */ dup4 /* \"C\":403:411 this.f() */ dup2 iszero - tag_41 + tag_42 jumpi returndatasize /* \"C\":79:428 contract C... */ @@ -346,7 +346,7 @@ sub_0: assembly { lt or iszero - tag_42 + tag_43 jumpi shl(0xe0, 0x4e487b71) dup7 @@ -359,26 +359,26 @@ sub_0: assembly { 0x24 dup7 revert - tag_42: + tag_43: 0x40 mstore /* \"C\":403:411 this.f() */ - tag_43 + tag_44 returndatasize dup5 add dup5 - tag_44 + tag_7 jump\t// in - tag_43: + tag_44: swap1 pop - tag_41: + tag_42: /* \"C\":392:411 stateVar + this.f() */ tag_45 dup2 dup6 - tag_30 + tag_5 jump\t// in tag_45: swap5 @@ -393,7 +393,7 @@ sub_0: assembly { immutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\") /* \"C\":392:422 stateVar + this.f() + immutVar */ dup3 - tag_30 + tag_5 jump\t// in tag_46: /* \"C\":336:337 _ */ @@ -404,7 +404,7 @@ sub_0: assembly { swap1 jump\t// out /* \"C\":79:428 contract C... */ - tag_44: + tag_7: 0x00 0x20 dup3 @@ -429,11 +429,11 @@ sub_0: assembly { } "}}},"D":{"D":{"evm":{"assembly":" /* \"D\":91:166 contract D is C(3)... */ mstore(0x40, 0xa0) - jumpi(tag_1, iszero(callvalue)) + jumpi(tag_2, iszero(callvalue)) 0x00 dup1 revert -tag_1: +tag_2: bytecodeSize codesize dup2 @@ -456,12 +456,12 @@ tag_1: lt or iszero - tag_2 + tag_3 jumpi mstore(0x00, shl(0xe0, 0x4e487b71)) mstore(0x04, 0x41) revert(0x00, 0x24) -tag_2: +tag_3: 0x40 mstore dup1 @@ -472,19 +472,19 @@ tag_2: dup2 slt iszero - tag_3 + tag_4 jumpi 0x00 dup1 revert -tag_3: - pop - pop - tag_4 - mload(0xa0) - tag_5 - jump\t// in tag_4: + pop + pop + tag_5 + mload(0xa0) + tag_1 + jump\t// in +tag_5: mload(0x40) dataSize(sub_0) dup1 @@ -498,7 +498,7 @@ tag_4: dup3 return /* \"D\":113:164 constructor(int _init2)... */ -tag_5: +tag_1: /* \"C\":147:149 42 */ mstore(0x80, 0x2a) /* \"D\":107:108 3 */ @@ -542,7 +542,7 @@ stop sub_0: assembly { /* \"D\":91:166 contract D is C(3)... */ mstore(0x40, 0x80) - jumpi(tag_1, lt(calldatasize, 0x04)) + jumpi(tag_8, lt(calldatasize, 0x04)) 0x00 dup1 calldataload @@ -551,38 +551,38 @@ sub_0: assembly { 0x26121ff0 dup2 eq - tag_3 + tag_10 jumpi 0x793816ec dup2 eq - tag_4 + tag_11 jumpi 0x9942ec6f dup2 eq - tag_5 + tag_12 jumpi - jump(tag_2) - tag_3: - jumpi(tag_6, iszero(callvalue)) + jump(tag_9) + tag_10: + jumpi(tag_13, iszero(callvalue)) dup2 dup3 revert - tag_6: - tag_7 + tag_13: + tag_14 calldatasize - tag_8 + tag_1 jump\t// in - tag_7: + tag_14: /* \"C\":279:298 constVar + immutVar */ - tag_9 + tag_15 /* \"C\":290:298 immutVar */ immutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\") /* \"C\":279:298 constVar + immutVar */ - tag_10 + tag_4 jump\t// in - tag_9: + tag_15: /* \"D\":91:166 contract D is C(3)... */ mload(0x40) dup2 @@ -591,17 +591,17 @@ sub_0: assembly { 0x20 dup2 return - tag_4: - jumpi(tag_13, iszero(callvalue)) + tag_11: + jumpi(tag_17, iszero(callvalue)) dup2 dup3 revert - tag_13: - tag_14 + tag_17: + tag_18 calldatasize - tag_8 + tag_1 jump\t// in - tag_14: + tag_18: dup2 sload mload(0x40) @@ -611,50 +611,50 @@ sub_0: assembly { 0x20 dup2 return - tag_5: - jumpi(tag_16, iszero(callvalue)) + tag_12: + jumpi(tag_20, iszero(callvalue)) dup2 dup3 revert - tag_16: - tag_17 + tag_20: + tag_21 calldatasize - tag_8 + tag_1 jump\t// in - tag_17: + tag_21: /* \"C\":375:378 int */ - tag_9 - tag_19 + tag_15 + tag_6 jump\t// in /* \"D\":91:166 contract D is C(3)... */ - tag_2: + tag_9: pop pop - tag_1: + tag_8: 0x00 dup1 revert - tag_8: + tag_1: 0x00 not(0x03) dup3 add slt iszero - tag_23 + tag_26 jumpi 0x00 dup1 revert - tag_23: + tag_26: pop jump\t// out /* \"C\":117:119 41 */ - tag_25: + tag_3: mstore(0x00, shl(0xe0, 0x4e487b71)) mstore(0x04, 0x11) revert(0x00, 0x24) - tag_10: + tag_4: 0x00 sub(shl(0xff, 0x01), 0x2a) dup3 @@ -662,18 +662,18 @@ sub_0: assembly { 0x01 and iszero - tag_29 + tag_31 jumpi - tag_29 - tag_25 + tag_31 + tag_3 jump\t// in - tag_29: + tag_31: pop 0x29 add swap1 jump\t// out - tag_30: + tag_5: 0x00 dup1 dup3 @@ -688,12 +688,12 @@ sub_0: assembly { sgt and iszero - tag_33 + tag_34 jumpi - tag_33 - tag_25 + tag_34 + tag_3 jump\t// in - tag_33: + tag_34: shl(0xff, 0x01) dup4 swap1 @@ -703,19 +703,19 @@ sub_0: assembly { dup2 and iszero - tag_35 + tag_36 jumpi - tag_35 - tag_25 + tag_36 + tag_3 jump\t// in - tag_35: + tag_36: pop pop add swap1 jump\t// out /* \"C\":304:341 modifier m()... */ - tag_19: + tag_6: 0x00 /* \"D\":91:166 contract D is C(3)... */ dup1 @@ -728,12 +728,12 @@ sub_0: assembly { dup2 eq iszero - tag_38 + tag_39 jumpi - tag_38 - tag_25 + tag_39 + tag_3 jump\t// in - tag_38: + tag_39: /* \"C\":117:119 41 */ 0x01 /* \"D\":91:166 contract D is C(3)... */ @@ -745,14 +745,14 @@ sub_0: assembly { address /* \"C\":403:411 this.f() */ extcodesize - tag_39 + tag_40 jumpi /* \"D\":91:166 contract D is C(3)... */ dup2 dup3 revert /* \"C\":403:411 this.f() */ - tag_39: + tag_40: /* \"D\":91:166 contract D is C(3)... */ mload(0x40) shl(0xe4, 0x026121ff) @@ -772,7 +772,7 @@ sub_0: assembly { gas staticcall dup1 - tag_40 + tag_41 jumpi /* \"D\":91:166 contract D is C(3)... */ mload(0x40) @@ -784,13 +784,13 @@ sub_0: assembly { dup2 revert /* \"C\":403:411 this.f() */ - tag_40: + tag_41: /* \"D\":91:166 contract D is C(3)... */ dup4 /* \"C\":403:411 this.f() */ dup2 iszero - tag_41 + tag_42 jumpi returndatasize /* \"D\":91:166 contract D is C(3)... */ @@ -808,7 +808,7 @@ sub_0: assembly { lt or iszero - tag_42 + tag_43 jumpi shl(0xe0, 0x4e487b71) dup7 @@ -821,26 +821,26 @@ sub_0: assembly { 0x24 dup7 revert - tag_42: + tag_43: 0x40 mstore /* \"C\":403:411 this.f() */ - tag_43 + tag_44 returndatasize dup5 add dup5 - tag_44 + tag_7 jump\t// in - tag_43: + tag_44: swap1 pop - tag_41: + tag_42: /* \"C\":392:411 stateVar + this.f() */ tag_45 dup2 dup6 - tag_30 + tag_5 jump\t// in tag_45: swap5 @@ -855,7 +855,7 @@ sub_0: assembly { immutable(\"0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10\") /* \"C\":392:422 stateVar + this.f() + immutVar */ dup3 - tag_30 + tag_5 jump\t// in tag_46: /* \"C\":336:337 _ */ @@ -866,7 +866,7 @@ sub_0: assembly { swap1 jump\t// out /* \"D\":91:166 contract D is C(3)... */ - tag_44: + tag_7: 0x00 0x20 dup3 diff --git a/test/libyul/objectCompiler/function_series.yul b/test/libyul/objectCompiler/function_series.yul index cf4911997..f905c04b5 100644 --- a/test/libyul/objectCompiler/function_series.yul +++ b/test/libyul/objectCompiler/function_series.yul @@ -11,15 +11,15 @@ object "Contract" { // ---- // Assembly: // /* "source":33:48 */ -// jump(tag_1) -// tag_2: -// tag_3: +// jump(tag_3) +// tag_1: +// tag_4: // jump // out // /* "source":53:68 */ -// tag_4: +// tag_2: // tag_5: // jump // out -// tag_1: +// tag_3: // /* "source":83:84 */ // 0x01 // /* "source":80:81 */ diff --git a/test/libyul/objectCompiler/jump_tags.yul b/test/libyul/objectCompiler/jump_tags.yul index b78173d18..ba0984b10 100644 --- a/test/libyul/objectCompiler/jump_tags.yul +++ b/test/libyul/objectCompiler/jump_tags.yul @@ -11,21 +11,21 @@ object "Contract" { // ---- // Assembly: // /* "source":33:54 */ -// jump(tag_1) -// tag_2: +// jump(tag_3) +// tag_1: // /* "source":48:52 */ -// tag_4 +// tag_5 // /* "source":50:51 */ // 0x01 // /* "source":48:52 */ -// tag_5 +// tag_2 // jump // in -// tag_4: +// tag_5: // /* "source":33:54 */ -// tag_3: +// tag_4: // jump // out // /* "source":59:104 */ -// tag_5: +// tag_2: // /* "source":78:79 */ // dup1 // /* "source":75:89 */ @@ -46,20 +46,20 @@ object "Contract" { // /* "source":92:101 */ // add // /* "source":90:102 */ -// tag_5 +// tag_2 // jump // in // tag_8: // /* "source":59:104 */ // pop // tag_6: // jump // out -// tag_1: +// tag_3: // /* "source":109:113 */ // tag_9 // /* "source":111:112 */ // 0x01 // /* "source":109:113 */ -// tag_5 +// tag_2 // jump // in // tag_9: // Bytecode: 6026565b600b6001600e565b5b565b8015601857506024565b602260028201600e565b505b565b602e6001600e565b From 84ca67c28340b6b422a4fb36bc36ed9cc5ada393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 21 Sep 2021 13:36:23 +0200 Subject: [PATCH 150/232] Yul syntax tests showing broken behavior --- .../invalid/leave_items_on_stack_with_debug_info.yul | 9 +++++++++ .../literals_on_stack_disallowed_with_debug_info.yul | 9 +++++++++ .../invalid_tuple_assignment_with_debug_info.yul | 8 ++++++++ .../name_clash_sub_scope_with_debug_info.yul | 11 +++++++++++ 4 files changed, 37 insertions(+) create mode 100644 test/libyul/yulSyntaxTests/invalid/leave_items_on_stack_with_debug_info.yul create mode 100644 test/libyul/yulSyntaxTests/invalid/literals_on_stack_disallowed_with_debug_info.yul create mode 100644 test/libyul/yulSyntaxTests/invalid_tuple_assignment_with_debug_info.yul create mode 100644 test/libyul/yulSyntaxTests/name_clash_sub_scope_with_debug_info.yul diff --git a/test/libyul/yulSyntaxTests/invalid/leave_items_on_stack_with_debug_info.yul b/test/libyul/yulSyntaxTests/invalid/leave_items_on_stack_with_debug_info.yul new file mode 100644 index 000000000..e8df2c6ea --- /dev/null +++ b/test/libyul/yulSyntaxTests/invalid/leave_items_on_stack_with_debug_info.yul @@ -0,0 +1,9 @@ +/// @use-src 0:"input.sol" +object "C" { + code { + /// @src 0:0:0 + calldataload(0) + } +} +// ---- +// TypeError 3083: (0-0): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. diff --git a/test/libyul/yulSyntaxTests/invalid/literals_on_stack_disallowed_with_debug_info.yul b/test/libyul/yulSyntaxTests/invalid/literals_on_stack_disallowed_with_debug_info.yul new file mode 100644 index 000000000..f27be64f5 --- /dev/null +++ b/test/libyul/yulSyntaxTests/invalid/literals_on_stack_disallowed_with_debug_info.yul @@ -0,0 +1,9 @@ +/// @use-src 0:"input.sol" +object "C" { + code { + 1 + } +} +// ---- +// ParserError 6913: Call or assignment expected. +// ParserError 2314: (67-68): Expected end of source but got '}' diff --git a/test/libyul/yulSyntaxTests/invalid_tuple_assignment_with_debug_info.yul b/test/libyul/yulSyntaxTests/invalid_tuple_assignment_with_debug_info.yul new file mode 100644 index 000000000..39476217e --- /dev/null +++ b/test/libyul/yulSyntaxTests/invalid_tuple_assignment_with_debug_info.yul @@ -0,0 +1,8 @@ +/// @use-src 0:"input.sol" +object "C" { + code { + let x, y := 1 + } +} +// ---- +// DeclarationError 3812: Variable count mismatch for declaration of "x, y": 2 variables and 1 values. diff --git a/test/libyul/yulSyntaxTests/name_clash_sub_scope_with_debug_info.yul b/test/libyul/yulSyntaxTests/name_clash_sub_scope_with_debug_info.yul new file mode 100644 index 000000000..4c88c2a42 --- /dev/null +++ b/test/libyul/yulSyntaxTests/name_clash_sub_scope_with_debug_info.yul @@ -0,0 +1,11 @@ +/// @use-src 0:"input.sol" +object "C" { + code { + /// @src 0:0:0 + function g() { + function g() {} + } + } +} +// ---- +// DeclarationError 6052: (0-0): Function name g already taken in this scope. From 9c1d40debfc26278b1e931f06e6b3fe81d80d13c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 21 Sep 2021 14:52:51 +0200 Subject: [PATCH 151/232] AsmParser: Replace m_debugDataOverride with separate variables for location and AST ID --- libyul/AsmParser.cpp | 7 ++++--- libyul/AsmParser.h | 5 ++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index d32d15143..ed39ddb72 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -80,7 +80,7 @@ std::shared_ptr Parser::createDebugData() const case UseSourceLocationFrom::LocationOverride: return DebugData::create(m_locationOverride); case UseSourceLocationFrom::Comments: - return m_debugDataOverride; + return DebugData::create(m_locationFromComment, m_astIDFromComment); } solAssert(false, ""); } @@ -135,7 +135,7 @@ void Parser::fetchDebugDataFromComment() string_view commentLiteral = m_scanner->currentCommentLiteral(); match_results match; - langutil::SourceLocation sourceLocation = m_debugDataOverride->location; + langutil::SourceLocation sourceLocation = m_locationFromComment; // Empty for each new node. optional astID; @@ -163,7 +163,8 @@ void Parser::fetchDebugDataFromComment() continue; } - m_debugDataOverride = DebugData::create(sourceLocation, astID); + m_locationFromComment = sourceLocation; + m_astIDFromComment = astID; } optional> Parser::parseSrcComment( diff --git a/libyul/AsmParser.h b/libyul/AsmParser.h index 2145fa93f..4a820cdf4 100644 --- a/libyul/AsmParser.h +++ b/libyul/AsmParser.h @@ -61,7 +61,6 @@ public: ParserBase(_errorReporter), m_dialect(_dialect), m_locationOverride{_locationOverride ? *_locationOverride : langutil::SourceLocation{}}, - m_debugDataOverride{}, m_useSourceLocationFrom{ _locationOverride ? UseSourceLocationFrom::LocationOverride : @@ -79,7 +78,6 @@ public: ParserBase(_errorReporter), m_dialect(_dialect), m_sourceNames{std::move(_sourceNames)}, - m_debugDataOverride{DebugData::create()}, m_useSourceLocationFrom{ m_sourceNames.has_value() ? UseSourceLocationFrom::Comments : @@ -154,7 +152,8 @@ private: std::optional>> m_sourceNames; langutil::SourceLocation m_locationOverride; - std::shared_ptr m_debugDataOverride; + langutil::SourceLocation m_locationFromComment; + std::optional m_astIDFromComment; UseSourceLocationFrom m_useSourceLocationFrom = UseSourceLocationFrom::Scanner; ForLoopComponent m_currentForLoopComponent = ForLoopComponent::None; bool m_insideFunction = false; From ce4420f857b6032262541ef43f0bb9d0ccf3dba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 20 Sep 2021 17:51:01 +0200 Subject: [PATCH 152/232] Separate DebugData fields for Solidity and Yul source locations --- libsolidity/analysis/ControlFlowBuilder.cpp | 6 +- libsolidity/analysis/ReferencesResolver.cpp | 14 +-- libsolidity/analysis/TypeChecker.cpp | 40 +++---- libsolidity/analysis/ViewPureChecker.cpp | 2 +- libsolidity/ast/ASTJsonConverter.cpp | 4 +- libsolidity/codegen/CompilerContext.cpp | 2 +- libsolidity/parsing/Parser.cpp | 2 +- libyul/AST.h | 48 ++++++-- libyul/AsmAnalysis.cpp | 70 +++++------ libyul/AsmJsonConverter.cpp | 32 ++--- libyul/AsmJsonImporter.cpp | 6 +- libyul/AsmParser.cpp | 92 ++++++++------- libyul/AsmParser.h | 5 + libyul/AsmPrinter.cpp | 6 +- libyul/ScopeFiller.cpp | 6 +- libyul/backends/evm/EVMCodeTransform.cpp | 54 ++++----- .../evm/OptimizedEVMCodeTransform.cpp | 18 +-- test/libyul/Parser.cpp | 110 +++++++++--------- .../leave_items_on_stack_with_debug_info.yul | 2 +- ...valid_tuple_assignment_with_debug_info.yul | 2 +- .../name_clash_sub_scope_with_debug_info.yul | 2 +- 21 files changed, 281 insertions(+), 242 deletions(-) diff --git a/libsolidity/analysis/ControlFlowBuilder.cpp b/libsolidity/analysis/ControlFlowBuilder.cpp index 98dcbf069..3b87f6515 100644 --- a/libsolidity/analysis/ControlFlowBuilder.cpp +++ b/libsolidity/analysis/ControlFlowBuilder.cpp @@ -409,7 +409,7 @@ bool ControlFlowBuilder::visit(InlineAssembly const& _inlineAssembly) void ControlFlowBuilder::visit(yul::Statement const& _statement) { solAssert(m_currentNode && m_inlineAssembly, ""); - m_currentNode->location = langutil::SourceLocation::smallestCovering(m_currentNode->location, locationOf(_statement)); + m_currentNode->location = langutil::SourceLocation::smallestCovering(m_currentNode->location, nativeLocationOf(_statement)); ASTWalker::visit(_statement); } @@ -501,7 +501,7 @@ void ControlFlowBuilder::operator()(yul::Identifier const& _identifier) m_currentNode->variableOccurrences.emplace_back( *declaration, VariableOccurrence::Kind::Access, - _identifier.debugData->location + nativeLocationOf(_identifier) ); } } @@ -517,7 +517,7 @@ void ControlFlowBuilder::operator()(yul::Assignment const& _assignment) m_currentNode->variableOccurrences.emplace_back( *declaration, VariableOccurrence::Kind::Assignment, - variable.debugData->location + nativeLocationOf(variable) ); } diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index abaeada03..ae2d82827 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -201,9 +201,9 @@ bool ReferencesResolver::visit(Return const& _return) void ReferencesResolver::operator()(yul::FunctionDefinition const& _function) { - validateYulIdentifierName(_function.name, _function.debugData->location); + validateYulIdentifierName(_function.name, nativeLocationOf(_function)); for (yul::TypedName const& varName: _function.parameters + _function.returnVariables) - validateYulIdentifierName(varName.name, varName.debugData->location); + validateYulIdentifierName(varName.name, nativeLocationOf(varName)); bool wasInsideFunction = m_yulInsideFunction; m_yulInsideFunction = true; @@ -238,7 +238,7 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier) { m_errorReporter.declarationError( 4718_error, - _identifier.debugData->location, + nativeLocationOf(_identifier), "Multiple matching identifiers. Resolving overloaded identifiers is not supported." ); return; @@ -251,7 +251,7 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier) ) m_errorReporter.declarationError( 9467_error, - _identifier.debugData->location, + nativeLocationOf(_identifier), "Identifier not found. Use \".slot\" and \".offset\" to access storage variables." ); return; @@ -261,7 +261,7 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier) { m_errorReporter.declarationError( 6578_error, - _identifier.debugData->location, + nativeLocationOf(_identifier), "Cannot access local Solidity variables from inside an inline assembly function." ); return; @@ -275,7 +275,7 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl) { for (auto const& identifier: _varDecl.variables) { - validateYulIdentifierName(identifier.name, identifier.debugData->location); + validateYulIdentifierName(identifier.name, nativeLocationOf(identifier)); if ( @@ -289,7 +289,7 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl) if (!ssl.infos.empty()) m_errorReporter.declarationError( 3859_error, - identifier.debugData->location, + nativeLocationOf(identifier), ssl, "This declaration shadows a declaration outside the inline assembly block." ); diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index c9772f1c8..eabf466a7 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -772,7 +772,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) solAssert(var->type(), "Expected variable type!"); if (var->immutable()) { - m_errorReporter.typeError(3773_error, _identifier.debugData->location, "Assembly access to immutable variables is not supported."); + m_errorReporter.typeError(3773_error, nativeLocationOf(_identifier), "Assembly access to immutable variables is not supported."); return false; } if (var->isConstant()) @@ -781,7 +781,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) { m_errorReporter.typeError( 3558_error, - _identifier.debugData->location, + nativeLocationOf(_identifier), "Constant variable is circular." ); return false; @@ -791,24 +791,24 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (var && !var->value()) { - m_errorReporter.typeError(3224_error, _identifier.debugData->location, "Constant has no value."); + m_errorReporter.typeError(3224_error, nativeLocationOf(_identifier), "Constant has no value."); return false; } else if (_context == yul::IdentifierContext::LValue) { - m_errorReporter.typeError(6252_error, _identifier.debugData->location, "Constant variables cannot be assigned to."); + m_errorReporter.typeError(6252_error, nativeLocationOf(_identifier), "Constant variables cannot be assigned to."); return false; } else if (identifierInfo.suffix == "slot" || identifierInfo.suffix == "offset") { - m_errorReporter.typeError(6617_error, _identifier.debugData->location, "The suffixes .offset and .slot can only be used on non-constant storage variables."); + m_errorReporter.typeError(6617_error, nativeLocationOf(_identifier), "The suffixes .offset and .slot can only be used on non-constant storage variables."); return false; } else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast(var->value().get())) { m_errorReporter.typeError( 2249_error, - _identifier.debugData->location, + nativeLocationOf(_identifier), "Constant variables with non-literal values cannot be forward referenced from inline assembly." ); return false; @@ -818,7 +818,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) type(*var->value())->category() != Type::Category::RationalNumber )) { - m_errorReporter.typeError(7615_error, _identifier.debugData->location, "Only direct number constants and references to such constants are supported by inline assembly."); + m_errorReporter.typeError(7615_error, nativeLocationOf(_identifier), "Only direct number constants and references to such constants are supported by inline assembly."); return false; } } @@ -833,19 +833,19 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) { if (suffix != "slot" && suffix != "offset") { - m_errorReporter.typeError(4656_error, _identifier.debugData->location, "State variables only support \".slot\" and \".offset\"."); + m_errorReporter.typeError(4656_error, nativeLocationOf(_identifier), "State variables only support \".slot\" and \".offset\"."); return false; } else if (_context == yul::IdentifierContext::LValue) { if (var->isStateVariable()) { - m_errorReporter.typeError(4713_error, _identifier.debugData->location, "State variables cannot be assigned to - you have to use \"sstore()\"."); + m_errorReporter.typeError(4713_error, nativeLocationOf(_identifier), "State variables cannot be assigned to - you have to use \"sstore()\"."); return false; } else if (suffix != "slot") { - m_errorReporter.typeError(9739_error, _identifier.debugData->location, "Only .slot can be assigned to."); + m_errorReporter.typeError(9739_error, nativeLocationOf(_identifier), "Only .slot can be assigned to."); return false; } } @@ -857,13 +857,13 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) { if (suffix != "offset" && suffix != "length") { - m_errorReporter.typeError(1536_error, _identifier.debugData->location, "Calldata variables only support \".offset\" and \".length\"."); + m_errorReporter.typeError(1536_error, nativeLocationOf(_identifier), "Calldata variables only support \".offset\" and \".length\"."); return false; } } else { - m_errorReporter.typeError(3622_error, _identifier.debugData->location, "The suffix \"." + suffix + "\" is not supported by this variable or type."); + m_errorReporter.typeError(3622_error, nativeLocationOf(_identifier), "The suffix \"." + suffix + "\" is not supported by this variable or type."); return false; } } @@ -871,14 +871,14 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) { m_errorReporter.typeError( 1408_error, - _identifier.debugData->location, + nativeLocationOf(_identifier), "Only local variables are supported. To access storage variables, use the \".slot\" and \".offset\" suffixes." ); return false; } else if (var->type()->dataStoredIn(DataLocation::Storage)) { - m_errorReporter.typeError(9068_error, _identifier.debugData->location, "You have to use the \".slot\" or \".offset\" suffix to access storage reference variables."); + m_errorReporter.typeError(9068_error, nativeLocationOf(_identifier), "You have to use the \".slot\" or \".offset\" suffix to access storage reference variables."); return false; } else if (var->type()->sizeOnStack() != 1) @@ -887,18 +887,18 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) auto const* arrayType = dynamic_cast(var->type()); arrayType && arrayType->isDynamicallySized() && arrayType->dataStoredIn(DataLocation::CallData) ) - m_errorReporter.typeError(1397_error, _identifier.debugData->location, "Call data elements cannot be accessed directly. Use \".offset\" and \".length\" to access the calldata offset and length of this array and then use \"calldatacopy\"."); + m_errorReporter.typeError(1397_error, nativeLocationOf(_identifier), "Call data elements cannot be accessed directly. Use \".offset\" and \".length\" to access the calldata offset and length of this array and then use \"calldatacopy\"."); else { solAssert(!var->type()->dataStoredIn(DataLocation::CallData), ""); - m_errorReporter.typeError(9857_error, _identifier.debugData->location, "Only types that use one stack slot are supported."); + m_errorReporter.typeError(9857_error, nativeLocationOf(_identifier), "Only types that use one stack slot are supported."); } return false; } } else if (!identifierInfo.suffix.empty()) { - m_errorReporter.typeError(7944_error, _identifier.debugData->location, "The suffixes \".offset\", \".slot\" and \".length\" can only be used with variables."); + m_errorReporter.typeError(7944_error, nativeLocationOf(_identifier), "The suffixes \".offset\", \".slot\" and \".length\" can only be used with variables."); return false; } else if (_context == yul::IdentifierContext::LValue) @@ -906,7 +906,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (dynamic_cast(declaration)) return false; - m_errorReporter.typeError(1990_error, _identifier.debugData->location, "Only local variables can be assigned to in inline assembly."); + m_errorReporter.typeError(1990_error, nativeLocationOf(_identifier), "Only local variables can be assigned to in inline assembly."); return false; } @@ -915,7 +915,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) solAssert(!!declaration->type(), "Type of declaration required but not yet determined."); if (dynamic_cast(declaration)) { - m_errorReporter.declarationError(2025_error, _identifier.debugData->location, "Access to functions is not allowed in inline assembly."); + m_errorReporter.declarationError(2025_error, nativeLocationOf(_identifier), "Access to functions is not allowed in inline assembly."); return false; } else if (dynamic_cast(declaration)) @@ -925,7 +925,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) { if (!contract->isLibrary()) { - m_errorReporter.typeError(4977_error, _identifier.debugData->location, "Expected a library."); + m_errorReporter.typeError(4977_error, nativeLocationOf(_identifier), "Expected a library."); return false; } } diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index 87831972d..81f755cec 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -69,7 +69,7 @@ public: if (yul::EVMDialect const* dialect = dynamic_cast(&m_dialect)) if (yul::BuiltinFunctionForEVM const* fun = dialect->builtin(_funCall.functionName.name)) if (fun->instruction) - checkInstruction(_funCall.debugData->location, *fun->instruction); + checkInstruction(nativeLocationOf(_funCall), *fun->instruction); for (auto const& arg: _funCall.arguments) std::visit(*this, arg); diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index b74f71572..c624e56ae 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -171,10 +171,10 @@ void ASTJsonConverter::appendExpressionAttributes( _attributes += exprAttributes; } -Json::Value ASTJsonConverter::inlineAssemblyIdentifierToJson(pair _info) const +Json::Value ASTJsonConverter::inlineAssemblyIdentifierToJson(pair _info) const { Json::Value tuple(Json::objectValue); - tuple["src"] = sourceLocationToString(_info.first->debugData->location); + tuple["src"] = sourceLocationToString(nativeLocationOf(*_info.first)); tuple["declaration"] = idOrNull(_info.second.declaration); tuple["isSlot"] = Json::Value(_info.second.suffix == "slot"); tuple["isOffset"] = Json::Value(_info.second.suffix == "offset"); diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 5503c3ecd..700f53d1f 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -421,7 +421,7 @@ void CompilerContext::appendInlineAssembly( if (stackDiff < 1 || stackDiff > 16) BOOST_THROW_EXCEPTION( StackTooDeepError() << - errinfo_sourceLocation(_identifier.debugData->location) << + errinfo_sourceLocation(nativeLocationOf(_identifier)) << util::errinfo_comment("Stack too deep (" + to_string(stackDiff) + "), try removing local variables.") ); if (_context == yul::IdentifierContext::RValue) diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp index 1d16f7828..fea062d01 100644 --- a/libsolidity/parsing/Parser.cpp +++ b/libsolidity/parsing/Parser.cpp @@ -1326,7 +1326,7 @@ ASTPointer Parser::parseInlineAssembly(ASTPointer con if (block == nullptr) BOOST_THROW_EXCEPTION(FatalError()); - location.end = block->debugData->location.end; + location.end = nativeLocationOf(*block).end; return make_shared(nextID(), location, _docString, dialect, block); } diff --git a/libyul/AST.h b/libyul/AST.h index 04306c5a9..1c7b8e02a 100644 --- a/libyul/AST.h +++ b/libyul/AST.h @@ -38,20 +38,34 @@ using Type = YulString; struct DebugData { - explicit DebugData(langutil::SourceLocation _location, std::optional _astID = {}): - location(std::move(_location)), + explicit DebugData( + langutil::SourceLocation _nativeLocation, + langutil::SourceLocation _originLocation = {}, + std::optional _astID = {} + ): + nativeLocation(std::move(_nativeLocation)), + originLocation(std::move(_originLocation)), astID(std::move(_astID)) {} static std::shared_ptr create( - langutil::SourceLocation _location = {}, + langutil::SourceLocation _nativeLocation = {}, + langutil::SourceLocation _originLocation = {}, std::optional _astID = {} ) { - return std::make_shared(std::move(_location), std::move(_astID)); + return std::make_shared( + std::move(_nativeLocation), + std::move(_originLocation), + std::move(_astID) + ); } - langutil::SourceLocation location; + /// Location in the Yul code. + langutil::SourceLocation nativeLocation; + /// Location in the original source that the Yul code was produced from. + /// Optional. Only present if the Yul source contains location annotations. + langutil::SourceLocation originLocation; /// ID in the (Solidity) source AST. std::optional astID; }; @@ -94,16 +108,28 @@ struct Continue { std::shared_ptr debugData; }; /// Leave statement (valid within function) struct Leave { std::shared_ptr debugData; }; -/// Extracts the source location from a Yul node. -template inline langutil::SourceLocation locationOf(T const& _node) +/// Extracts the IR source location from a Yul node. +template inline langutil::SourceLocation nativeLocationOf(T const& _node) { - return _node.debugData ? _node.debugData->location : langutil::SourceLocation{}; + return _node.debugData ? _node.debugData->nativeLocation : langutil::SourceLocation{}; } -/// Extracts the source location from a Yul node. -template inline langutil::SourceLocation locationOf(std::variant const& _node) +/// Extracts the IR source location from a Yul node. +template inline langutil::SourceLocation nativeLocationOf(std::variant const& _node) { - return std::visit([](auto const& _arg) { return locationOf(_arg); }, _node); + return std::visit([](auto const& _arg) { return nativeLocationOf(_arg); }, _node); +} + +/// Extracts the original source location from a Yul node. +template inline langutil::SourceLocation originLocationOf(T const& _node) +{ + return _node.debugData ? _node.debugData->originLocation : langutil::SourceLocation{}; +} + +/// Extracts the original source location from a Yul node. +template inline langutil::SourceLocation originLocationOf(std::variant const& _node) +{ + return std::visit([](auto const& _arg) { return originLocationOf(_arg); }, _node); } /// Extracts the debug data from a Yul node. diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index c01d1929f..aae1c97e1 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -96,22 +96,22 @@ AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect, vector AsmAnalyzer::operator()(Literal const& _literal) { - expectValidType(_literal.type, locationOf(_literal)); + expectValidType(_literal.type, nativeLocationOf(_literal)); if (_literal.kind == LiteralKind::String && _literal.value.str().size() > 32) m_errorReporter.typeError( 3069_error, - locationOf(_literal), + nativeLocationOf(_literal), "String literal too long (" + to_string(_literal.value.str().size()) + " > 32)" ); else if (_literal.kind == LiteralKind::Number && bigint(_literal.value.str()) > u256(-1)) - m_errorReporter.typeError(6708_error, locationOf(_literal), "Number literal too large (> 256 bits)"); + m_errorReporter.typeError(6708_error, nativeLocationOf(_literal), "Number literal too large (> 256 bits)"); else if (_literal.kind == LiteralKind::Boolean) yulAssert(_literal.value == "true"_yulstring || _literal.value == "false"_yulstring, ""); if (!m_dialect.validTypeForLiteral(_literal.kind, _literal.value, _literal.type)) m_errorReporter.typeError( 5170_error, - locationOf(_literal), + nativeLocationOf(_literal), "Invalid type \"" + _literal.type.str() + "\" for literal \"" + _literal.value.str() + "\"." ); @@ -131,7 +131,7 @@ vector AsmAnalyzer::operator()(Identifier const& _identifier) if (!m_activeVariables.count(&_var)) m_errorReporter.declarationError( 4990_error, - locationOf(_identifier), + nativeLocationOf(_identifier), "Variable " + _identifier.name.str() + " used before it was declared." ); type = _var.type; @@ -140,7 +140,7 @@ vector AsmAnalyzer::operator()(Identifier const& _identifier) { m_errorReporter.typeError( 6041_error, - locationOf(_identifier), + nativeLocationOf(_identifier), "Function " + _identifier.name.str() + " used without being called." ); } @@ -165,7 +165,7 @@ vector AsmAnalyzer::operator()(Identifier const& _identifier) // Only add an error message if the callback did not do it. m_errorReporter.declarationError( 8198_error, - locationOf(_identifier), + nativeLocationOf(_identifier), "Identifier \"" + _identifier.name.str() + "\" not found." ); @@ -181,7 +181,7 @@ void AsmAnalyzer::operator()(ExpressionStatement const& _statement) if (watcher.ok() && !types.empty()) m_errorReporter.typeError( 3083_error, - locationOf(_statement), + nativeLocationOf(_statement), "Top-level expressions are not supposed to return values (this expression returns " + to_string(types.size()) + " value" + @@ -201,7 +201,7 @@ void AsmAnalyzer::operator()(Assignment const& _assignment) if (!variables.insert(_variableName.name).second) m_errorReporter.declarationError( 9005_error, - locationOf(_assignment), + nativeLocationOf(_assignment), "Variable " + _variableName.name.str() + " occurs multiple times on the left-hand side of the assignment." @@ -212,7 +212,7 @@ void AsmAnalyzer::operator()(Assignment const& _assignment) if (types.size() != numVariables) m_errorReporter.declarationError( 8678_error, - locationOf(_assignment), + nativeLocationOf(_assignment), "Variable count for assignment to \"" + joinHumanReadable(applyMap(_assignment.variableNames, [](auto const& _identifier){ return _identifier.name.str(); })) + "\" does not match number of values (" + @@ -240,8 +240,8 @@ void AsmAnalyzer::operator()(VariableDeclaration const& _varDecl) ); for (auto const& variable: _varDecl.variables) { - expectValidIdentifier(variable.name, locationOf(variable)); - expectValidType(variable.type, locationOf(variable)); + expectValidIdentifier(variable.name, nativeLocationOf(variable)); + expectValidType(variable.type, nativeLocationOf(variable)); } if (_varDecl.value) @@ -250,7 +250,7 @@ void AsmAnalyzer::operator()(VariableDeclaration const& _varDecl) if (types.size() != numVariables) m_errorReporter.declarationError( 3812_error, - locationOf(_varDecl), + nativeLocationOf(_varDecl), "Variable count mismatch for declaration of \"" + joinHumanReadable(applyMap(_varDecl.variables, [](auto const& _identifier){ return _identifier.name.str(); })) + + "\": " + @@ -269,7 +269,7 @@ void AsmAnalyzer::operator()(VariableDeclaration const& _varDecl) if (variable.type != givenType) m_errorReporter.typeError( 3947_error, - locationOf(variable), + nativeLocationOf(variable), "Assigning value of type \"" + givenType.str() + "\" to variable of type \"" + variable.type.str() + "\"." ); } @@ -284,14 +284,14 @@ void AsmAnalyzer::operator()(VariableDeclaration const& _varDecl) void AsmAnalyzer::operator()(FunctionDefinition const& _funDef) { yulAssert(!_funDef.name.empty(), ""); - expectValidIdentifier(_funDef.name, locationOf(_funDef)); + expectValidIdentifier(_funDef.name, nativeLocationOf(_funDef)); Block const* virtualBlock = m_info.virtualBlocks.at(&_funDef).get(); yulAssert(virtualBlock, ""); Scope& varScope = scope(virtualBlock); for (auto const& var: _funDef.parameters + _funDef.returnVariables) { - expectValidIdentifier(var.name, locationOf(var)); - expectValidType(var.type, locationOf(var)); + expectValidIdentifier(var.name, nativeLocationOf(var)); + expectValidType(var.type, nativeLocationOf(var)); m_activeVariables.insert(&std::get(varScope.identifiers.at(var.name))); } @@ -320,7 +320,7 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) { m_errorReporter.typeError( 4202_error, - locationOf(_funCall.functionName), + nativeLocationOf(_funCall.functionName), "Attempt to call variable instead of function." ); }, @@ -344,7 +344,7 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) if (!validateInstructions(_funCall)) m_errorReporter.declarationError( 4619_error, - locationOf(_funCall.functionName), + nativeLocationOf(_funCall.functionName), "Function \"" + _funCall.functionName.name.str() + "\" not found." ); yulAssert(!watcher.ok(), "Expected a reported error."); @@ -353,7 +353,7 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) if (parameterTypes && _funCall.arguments.size() != parameterTypes->size()) m_errorReporter.typeError( 7000_error, - locationOf(_funCall.functionName), + nativeLocationOf(_funCall.functionName), "Function \"" + _funCall.functionName.name.str() + "\" expects " + to_string(parameterTypes->size()) + " arguments but got " + @@ -373,13 +373,13 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) if (!holds_alternative(arg)) m_errorReporter.typeError( 9114_error, - locationOf(_funCall.functionName), + nativeLocationOf(_funCall.functionName), "Function expects direct literals as arguments." ); else if (*literalArgumentKind != get(arg).kind) m_errorReporter.typeError( 5859_error, - locationOf(arg), + nativeLocationOf(arg), "Function expects " + to_string(*literalArgumentKind) + " literal." ); else if (*literalArgumentKind == LiteralKind::String) @@ -390,7 +390,7 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) if (!m_dataNames.count(get(arg).value)) m_errorReporter.typeError( 3517_error, - locationOf(arg), + nativeLocationOf(arg), "Unknown data object \"" + std::get(arg).value.str() + "\"." ); } @@ -399,7 +399,7 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) if (get(arg).value.empty()) m_errorReporter.typeError( 1844_error, - locationOf(arg), + nativeLocationOf(arg), "The \"verbatim_*\" builtins cannot be used with empty bytecode." ); } @@ -414,7 +414,7 @@ vector AsmAnalyzer::operator()(FunctionCall const& _funCall) if (parameterTypes && parameterTypes->size() == argTypes.size()) for (size_t i = 0; i < parameterTypes->size(); ++i) - expectType((*parameterTypes)[i], argTypes[i], locationOf(_funCall.arguments[i])); + expectType((*parameterTypes)[i], argTypes[i], nativeLocationOf(_funCall.arguments[i])); if (watcher.ok()) { @@ -442,7 +442,7 @@ void AsmAnalyzer::operator()(Switch const& _switch) if (_switch.cases.size() == 1 && !_switch.cases[0].value) m_errorReporter.warning( 9592_error, - locationOf(_switch), + nativeLocationOf(_switch), "\"switch\" statement with only a default case." ); @@ -455,7 +455,7 @@ void AsmAnalyzer::operator()(Switch const& _switch) { auto watcher = m_errorReporter.errorWatcher(); - expectType(valueType, _case.value->type, locationOf(*_case.value)); + expectType(valueType, _case.value->type, nativeLocationOf(*_case.value)); // We cannot use "expectExpression" here because *_case.value is not an // Expression and would be converted to an Expression otherwise. @@ -465,7 +465,7 @@ void AsmAnalyzer::operator()(Switch const& _switch) if (watcher.ok() && !cases.insert(valueOfLiteral(*_case.value)).second) m_errorReporter.declarationError( 6792_error, - locationOf(_case), + nativeLocationOf(_case), "Duplicate case \"" + valueOfLiteral(*_case.value).str() + "\" defined." @@ -517,7 +517,7 @@ YulString AsmAnalyzer::expectExpression(Expression const& _expr) if (types.size() != 1) m_errorReporter.typeError( 3950_error, - locationOf(_expr), + nativeLocationOf(_expr), "Expected expression to evaluate to one value, but got " + to_string(types.size()) + " values instead." @@ -539,7 +539,7 @@ void AsmAnalyzer::expectBoolExpression(Expression const& _expr) if (type != m_dialect.boolType) m_errorReporter.typeError( 1733_error, - locationOf(_expr), + nativeLocationOf(_expr), "Expected a value of boolean type \"" + m_dialect.boolType.str() + "\" but got \"" + @@ -565,11 +565,11 @@ void AsmAnalyzer::checkAssignment(Identifier const& _variable, YulString _valueT ); if (!holds_alternative(*var)) - m_errorReporter.typeError(2657_error, locationOf(_variable), "Assignment requires variable."); + m_errorReporter.typeError(2657_error, nativeLocationOf(_variable), "Assignment requires variable."); else if (!m_activeVariables.count(&std::get(*var))) m_errorReporter.declarationError( 1133_error, - locationOf(_variable), + nativeLocationOf(_variable), "Variable " + _variable.name.str() + " used before it was declared." ); else @@ -588,11 +588,11 @@ void AsmAnalyzer::checkAssignment(Identifier const& _variable, YulString _valueT if (!found && watcher.ok()) // Only add message if the callback did not. - m_errorReporter.declarationError(4634_error, locationOf(_variable), "Variable not found or variable not lvalue."); + m_errorReporter.declarationError(4634_error, nativeLocationOf(_variable), "Variable not found or variable not lvalue."); if (variableType && *variableType != _valueType) m_errorReporter.typeError( 9547_error, - locationOf(_variable), + nativeLocationOf(_variable), "Assigning a value of type \"" + _valueType.str() + "\" to a variable of type \"" + @@ -738,5 +738,5 @@ bool AsmAnalyzer::validateInstructions(evmasm::Instruction _instr, SourceLocatio bool AsmAnalyzer::validateInstructions(FunctionCall const& _functionCall) { - return validateInstructions(_functionCall.functionName.name.str(), locationOf(_functionCall.functionName)); + return validateInstructions(_functionCall.functionName.name.str(), nativeLocationOf(_functionCall.functionName)); } diff --git a/libyul/AsmJsonConverter.cpp b/libyul/AsmJsonConverter.cpp index 0a7f86401..1807396c5 100644 --- a/libyul/AsmJsonConverter.cpp +++ b/libyul/AsmJsonConverter.cpp @@ -33,7 +33,7 @@ namespace solidity::yul Json::Value AsmJsonConverter::operator()(Block const& _node) const { - Json::Value ret = createAstNode(locationOf(_node), "YulBlock"); + Json::Value ret = createAstNode(nativeLocationOf(_node), "YulBlock"); ret["statements"] = vectorOfVariantsToJson(_node.statements); return ret; } @@ -41,7 +41,7 @@ Json::Value AsmJsonConverter::operator()(Block const& _node) const Json::Value AsmJsonConverter::operator()(TypedName const& _node) const { yulAssert(!_node.name.empty(), "Invalid variable name."); - Json::Value ret = createAstNode(locationOf(_node), "YulTypedName"); + Json::Value ret = createAstNode(nativeLocationOf(_node), "YulTypedName"); ret["name"] = _node.name.str(); ret["type"] = _node.type.str(); return ret; @@ -49,7 +49,7 @@ Json::Value AsmJsonConverter::operator()(TypedName const& _node) const Json::Value AsmJsonConverter::operator()(Literal const& _node) const { - Json::Value ret = createAstNode(locationOf(_node), "YulLiteral"); + Json::Value ret = createAstNode(nativeLocationOf(_node), "YulLiteral"); switch (_node.kind) { case LiteralKind::Number: @@ -76,7 +76,7 @@ Json::Value AsmJsonConverter::operator()(Literal const& _node) const Json::Value AsmJsonConverter::operator()(Identifier const& _node) const { yulAssert(!_node.name.empty(), "Invalid identifier"); - Json::Value ret = createAstNode(locationOf(_node), "YulIdentifier"); + Json::Value ret = createAstNode(nativeLocationOf(_node), "YulIdentifier"); ret["name"] = _node.name.str(); return ret; } @@ -84,7 +84,7 @@ Json::Value AsmJsonConverter::operator()(Identifier const& _node) const Json::Value AsmJsonConverter::operator()(Assignment const& _node) const { yulAssert(_node.variableNames.size() >= 1, "Invalid assignment syntax"); - Json::Value ret = createAstNode(locationOf(_node), "YulAssignment"); + Json::Value ret = createAstNode(nativeLocationOf(_node), "YulAssignment"); for (auto const& var: _node.variableNames) ret["variableNames"].append((*this)(var)); ret["value"] = _node.value ? std::visit(*this, *_node.value) : Json::nullValue; @@ -93,7 +93,7 @@ Json::Value AsmJsonConverter::operator()(Assignment const& _node) const Json::Value AsmJsonConverter::operator()(FunctionCall const& _node) const { - Json::Value ret = createAstNode(locationOf(_node), "YulFunctionCall"); + Json::Value ret = createAstNode(nativeLocationOf(_node), "YulFunctionCall"); ret["functionName"] = (*this)(_node.functionName); ret["arguments"] = vectorOfVariantsToJson(_node.arguments); return ret; @@ -101,14 +101,14 @@ Json::Value AsmJsonConverter::operator()(FunctionCall const& _node) const Json::Value AsmJsonConverter::operator()(ExpressionStatement const& _node) const { - Json::Value ret = createAstNode(locationOf(_node), "YulExpressionStatement"); + Json::Value ret = createAstNode(nativeLocationOf(_node), "YulExpressionStatement"); ret["expression"] = std::visit(*this, _node.expression); return ret; } Json::Value AsmJsonConverter::operator()(VariableDeclaration const& _node) const { - Json::Value ret = createAstNode(locationOf(_node), "YulVariableDeclaration"); + Json::Value ret = createAstNode(nativeLocationOf(_node), "YulVariableDeclaration"); for (auto const& var: _node.variables) ret["variables"].append((*this)(var)); @@ -120,7 +120,7 @@ Json::Value AsmJsonConverter::operator()(VariableDeclaration const& _node) const Json::Value AsmJsonConverter::operator()(FunctionDefinition const& _node) const { yulAssert(!_node.name.empty(), "Invalid function name."); - Json::Value ret = createAstNode(locationOf(_node), "YulFunctionDefinition"); + Json::Value ret = createAstNode(nativeLocationOf(_node), "YulFunctionDefinition"); ret["name"] = _node.name.str(); for (auto const& var: _node.parameters) ret["parameters"].append((*this)(var)); @@ -133,7 +133,7 @@ Json::Value AsmJsonConverter::operator()(FunctionDefinition const& _node) const Json::Value AsmJsonConverter::operator()(If const& _node) const { yulAssert(_node.condition, "Invalid if condition."); - Json::Value ret = createAstNode(locationOf(_node), "YulIf"); + Json::Value ret = createAstNode(nativeLocationOf(_node), "YulIf"); ret["condition"] = std::visit(*this, *_node.condition); ret["body"] = (*this)(_node.body); return ret; @@ -142,7 +142,7 @@ Json::Value AsmJsonConverter::operator()(If const& _node) const Json::Value AsmJsonConverter::operator()(Switch const& _node) const { yulAssert(_node.expression, "Invalid expression pointer."); - Json::Value ret = createAstNode(locationOf(_node), "YulSwitch"); + Json::Value ret = createAstNode(nativeLocationOf(_node), "YulSwitch"); ret["expression"] = std::visit(*this, *_node.expression); for (auto const& var: _node.cases) ret["cases"].append((*this)(var)); @@ -151,7 +151,7 @@ Json::Value AsmJsonConverter::operator()(Switch const& _node) const Json::Value AsmJsonConverter::operator()(Case const& _node) const { - Json::Value ret = createAstNode(locationOf(_node), "YulCase"); + Json::Value ret = createAstNode(nativeLocationOf(_node), "YulCase"); ret["value"] = _node.value ? (*this)(*_node.value) : "default"; ret["body"] = (*this)(_node.body); return ret; @@ -160,7 +160,7 @@ Json::Value AsmJsonConverter::operator()(Case const& _node) const Json::Value AsmJsonConverter::operator()(ForLoop const& _node) const { yulAssert(_node.condition, "Invalid for loop condition."); - Json::Value ret = createAstNode(locationOf(_node), "YulForLoop"); + Json::Value ret = createAstNode(nativeLocationOf(_node), "YulForLoop"); ret["pre"] = (*this)(_node.pre); ret["condition"] = std::visit(*this, *_node.condition); ret["post"] = (*this)(_node.post); @@ -170,17 +170,17 @@ Json::Value AsmJsonConverter::operator()(ForLoop const& _node) const Json::Value AsmJsonConverter::operator()(Break const& _node) const { - return createAstNode(locationOf(_node), "YulBreak"); + return createAstNode(nativeLocationOf(_node), "YulBreak"); } Json::Value AsmJsonConverter::operator()(Continue const& _node) const { - return createAstNode(locationOf(_node), "YulContinue"); + return createAstNode(nativeLocationOf(_node), "YulContinue"); } Json::Value AsmJsonConverter::operator()(Leave const& _node) const { - return createAstNode(locationOf(_node), "YulLeave"); + return createAstNode(nativeLocationOf(_node), "YulLeave"); } Json::Value AsmJsonConverter::createAstNode(langutil::SourceLocation const& _location, string _nodeType) const diff --git a/libyul/AsmJsonImporter.cpp b/libyul/AsmJsonImporter.cpp index f74fac4de..7b17d73cb 100644 --- a/libyul/AsmJsonImporter.cpp +++ b/libyul/AsmJsonImporter.cpp @@ -53,9 +53,9 @@ template T AsmJsonImporter::createAsmNode(Json::Value const& _node) { T r; - SourceLocation location = createSourceLocation(_node); - yulAssert(location.hasText(), "Invalid source location in Asm AST"); - r.debugData = DebugData::create(location); + SourceLocation nativeLocation = createSourceLocation(_node); + yulAssert(nativeLocation.hasText(), "Invalid source location in Asm AST"); + r.debugData = DebugData::create(nativeLocation); return r; } diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp index ed39ddb72..ba4bf1115 100644 --- a/libyul/AsmParser.cpp +++ b/libyul/AsmParser.cpp @@ -46,17 +46,6 @@ using namespace solidity::yul; namespace { -[[nodiscard]] -shared_ptr updateLocationEndFrom( - shared_ptr const& _debugData, - langutil::SourceLocation const& _location -) -{ - SourceLocation updatedLocation = _debugData ? _debugData->location : langutil::SourceLocation{}; - updatedLocation.end = _location.end; - return make_shared(updatedLocation); -} - optional toInt(string const& _value) { try @@ -76,15 +65,45 @@ std::shared_ptr Parser::createDebugData() const switch (m_useSourceLocationFrom) { case UseSourceLocationFrom::Scanner: - return DebugData::create(ParserBase::currentLocation()); + return DebugData::create(ParserBase::currentLocation(), ParserBase::currentLocation()); case UseSourceLocationFrom::LocationOverride: - return DebugData::create(m_locationOverride); + return DebugData::create(m_locationOverride, m_locationOverride); case UseSourceLocationFrom::Comments: - return DebugData::create(m_locationFromComment, m_astIDFromComment); + return DebugData::create(ParserBase::currentLocation(), m_locationFromComment, m_astIDFromComment); } solAssert(false, ""); } +void Parser::updateLocationEndFrom( + shared_ptr& _debugData, + SourceLocation const& _location +) const +{ + solAssert(_debugData, ""); + + switch (m_useSourceLocationFrom) + { + case UseSourceLocationFrom::Scanner: + { + DebugData updatedDebugData = *_debugData; + updatedDebugData.nativeLocation.end = _location.end; + updatedDebugData.originLocation.end = _location.end; + _debugData = make_shared(move(updatedDebugData)); + break; + } + case UseSourceLocationFrom::LocationOverride: + // Ignore the update. The location we're overriding with is not supposed to change + break; + case UseSourceLocationFrom::Comments: + { + DebugData updatedDebugData = *_debugData; + updatedDebugData.nativeLocation.end = _location.end; + _debugData = make_shared(move(updatedDebugData)); + break; + } + } +} + unique_ptr Parser::parse(CharStream& _charStream) { m_scanner = make_shared(_charStream); @@ -135,7 +154,7 @@ void Parser::fetchDebugDataFromComment() string_view commentLiteral = m_scanner->currentCommentLiteral(); match_results match; - langutil::SourceLocation sourceLocation = m_locationFromComment; + langutil::SourceLocation originLocation = m_locationFromComment; // Empty for each new node. optional astID; @@ -147,7 +166,7 @@ void Parser::fetchDebugDataFromComment() if (match[1] == "@src") { if (auto parseResult = parseSrcComment(commentLiteral, m_scanner->currentCommentLocation())) - tie(commentLiteral, sourceLocation) = *parseResult; + tie(commentLiteral, originLocation) = *parseResult; else break; } @@ -163,7 +182,7 @@ void Parser::fetchDebugDataFromComment() continue; } - m_locationFromComment = sourceLocation; + m_locationFromComment = originLocation; m_astIDFromComment = astID; } @@ -271,8 +290,7 @@ Block Parser::parseBlock() expectToken(Token::LBrace); while (currentToken() != Token::RBrace) block.statements.emplace_back(parseStatement()); - if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - block.debugData = updateLocationEndFrom(block.debugData, currentLocation()); + updateLocationEndFrom(block.debugData, currentLocation()); advance(); return block; } @@ -294,8 +312,7 @@ Statement Parser::parseStatement() advance(); _if.condition = make_unique(parseExpression()); _if.body = parseBlock(); - if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - _if.debugData = updateLocationEndFrom(_if.debugData, locationOf(_if.body)); + updateLocationEndFrom(_if.debugData, nativeLocationOf(_if.body)); return Statement{move(_if)}; } case Token::Switch: @@ -313,8 +330,7 @@ Statement Parser::parseStatement() fatalParserError(4904_error, "Case not allowed after default case."); if (_switch.cases.empty()) fatalParserError(2418_error, "Switch statement without any cases."); - if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - _switch.debugData = updateLocationEndFrom(_switch.debugData, locationOf(_switch.cases.back().body)); + updateLocationEndFrom(_switch.debugData, nativeLocationOf(_switch.cases.back().body)); return Statement{move(_switch)}; } case Token::For: @@ -396,8 +412,7 @@ Statement Parser::parseStatement() expectToken(Token::AssemblyAssign); assignment.value = make_unique(parseExpression()); - if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - assignment.debugData = updateLocationEndFrom(assignment.debugData, locationOf(*assignment.value)); + updateLocationEndFrom(assignment.debugData, nativeLocationOf(*assignment.value)); return Statement{move(assignment)}; } @@ -427,8 +442,7 @@ Case Parser::parseCase() else yulAssert(false, "Case or default case expected."); _case.body = parseBlock(); - if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - _case.debugData = updateLocationEndFrom(_case.debugData, locationOf(_case.body)); + updateLocationEndFrom(_case.debugData, nativeLocationOf(_case.body)); return _case; } @@ -448,8 +462,7 @@ ForLoop Parser::parseForLoop() forLoop.post = parseBlock(); m_currentForLoopComponent = ForLoopComponent::ForLoopBody; forLoop.body = parseBlock(); - if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - forLoop.debugData = updateLocationEndFrom(forLoop.debugData, locationOf(forLoop.body)); + updateLocationEndFrom(forLoop.debugData, nativeLocationOf(forLoop.body)); m_currentForLoopComponent = outerForLoopComponent; @@ -469,7 +482,7 @@ Expression Parser::parseExpression() if (m_dialect.builtin(_identifier.name)) fatalParserError( 7104_error, - locationOf(_identifier), + nativeLocationOf(_identifier), "Builtin function \"" + _identifier.name.str() + "\" must be called." ); return move(_identifier); @@ -528,8 +541,7 @@ variant Parser::parseLiteralOrIdentifier() if (currentToken() == Token::Colon) { expectToken(Token::Colon); - if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - literal.debugData = updateLocationEndFrom(literal.debugData, currentLocation()); + updateLocationEndFrom(literal.debugData, currentLocation()); literal.type = expectAsmIdentifier(); } @@ -561,11 +573,10 @@ VariableDeclaration Parser::parseVariableDeclaration() { expectToken(Token::AssemblyAssign); varDecl.value = make_unique(parseExpression()); - if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - varDecl.debugData = updateLocationEndFrom(varDecl.debugData, locationOf(*varDecl.value)); + updateLocationEndFrom(varDecl.debugData, nativeLocationOf(*varDecl.value)); } - else if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - varDecl.debugData = updateLocationEndFrom(varDecl.debugData, locationOf(varDecl.variables.back())); + else + updateLocationEndFrom(varDecl.debugData, nativeLocationOf(varDecl.variables.back())); return varDecl; } @@ -611,8 +622,7 @@ FunctionDefinition Parser::parseFunctionDefinition() m_insideFunction = true; funDef.body = parseBlock(); m_insideFunction = preInsideFunction; - if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - funDef.debugData = updateLocationEndFrom(funDef.debugData, locationOf(funDef.body)); + updateLocationEndFrom(funDef.debugData, nativeLocationOf(funDef.body)); m_currentForLoopComponent = outerForLoopComponent; return funDef; @@ -639,8 +649,7 @@ FunctionCall Parser::parseCall(variant&& _initialOp) ret.arguments.emplace_back(parseExpression()); } } - if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - ret.debugData = updateLocationEndFrom(ret.debugData, currentLocation()); + updateLocationEndFrom(ret.debugData, currentLocation()); expectToken(Token::RParen); return ret; } @@ -653,8 +662,7 @@ TypedName Parser::parseTypedName() if (currentToken() == Token::Colon) { expectToken(Token::Colon); - if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - typedName.debugData = updateLocationEndFrom(typedName.debugData, currentLocation()); + updateLocationEndFrom(typedName.debugData, currentLocation()); typedName.type = expectAsmIdentifier(); } else diff --git a/libyul/AsmParser.h b/libyul/AsmParser.h index 4a820cdf4..229c2ef44 100644 --- a/libyul/AsmParser.h +++ b/libyul/AsmParser.h @@ -119,6 +119,11 @@ protected: /// Creates a DebugData object with the correct source location set. std::shared_ptr createDebugData() const; + void updateLocationEndFrom( + std::shared_ptr& _debugData, + langutil::SourceLocation const& _location + ) const; + /// Creates an inline assembly node with the current source location. template T createWithLocation() const { diff --git a/libyul/AsmPrinter.cpp b/libyul/AsmPrinter.cpp index c8f169cd1..68f21bcd7 100644 --- a/libyul/AsmPrinter.cpp +++ b/libyul/AsmPrinter.cpp @@ -306,14 +306,14 @@ string AsmPrinter::formatDebugData(shared_ptr const& _debugData items.emplace_back("@ast-id " + to_string(*id)); if ( - m_lastLocation != _debugData->location && + m_lastLocation != _debugData->originLocation && !m_nameToSourceIndex.empty() ) { - m_lastLocation = _debugData->location; + m_lastLocation = _debugData->originLocation; items.emplace_back(formatSourceLocation( - _debugData->location, + _debugData->originLocation, m_nameToSourceIndex, m_soliditySourceProvider )); diff --git a/libyul/ScopeFiller.cpp b/libyul/ScopeFiller.cpp index 70cd3d80e..8672d898f 100644 --- a/libyul/ScopeFiller.cpp +++ b/libyul/ScopeFiller.cpp @@ -53,7 +53,7 @@ bool ScopeFiller::operator()(ExpressionStatement const& _expr) bool ScopeFiller::operator()(VariableDeclaration const& _varDecl) { for (auto const& variable: _varDecl.variables) - if (!registerVariable(variable, locationOf(_varDecl), *m_currentScope)) + if (!registerVariable(variable, nativeLocationOf(_varDecl), *m_currentScope)) return false; return true; } @@ -68,7 +68,7 @@ bool ScopeFiller::operator()(FunctionDefinition const& _funDef) bool success = true; for (auto const& var: _funDef.parameters + _funDef.returnVariables) - if (!registerVariable(var, locationOf(_funDef), varScope)) + if (!registerVariable(var, nativeLocationOf(_funDef), varScope)) success = false; if (!(*this)(_funDef.body)) @@ -162,7 +162,7 @@ bool ScopeFiller::registerFunction(FunctionDefinition const& _funDef) //@TODO secondary location m_errorReporter.declarationError( 6052_error, - locationOf(_funDef), + nativeLocationOf(_funDef), "Function name " + _funDef.name.str() + " already taken in this scope." ); return false; diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index 3ae8d7144..38eecc245 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -145,13 +145,13 @@ void CodeTransform::operator()(VariableDeclaration const& _varDecl) } else { - m_assembly.setSourceLocation(locationOf(_varDecl)); + m_assembly.setSourceLocation(originLocationOf(_varDecl)); size_t variablesLeft = numVariables; while (variablesLeft--) m_assembly.appendConstant(u256(0)); } - m_assembly.setSourceLocation(locationOf(_varDecl)); + m_assembly.setSourceLocation(originLocationOf(_varDecl)); bool atTopOfStack = true; for (size_t varIndex = 0; varIndex < numVariables; ++varIndex) { @@ -213,13 +213,13 @@ void CodeTransform::operator()(Assignment const& _assignment) std::visit(*this, *_assignment.value); expectDeposit(static_cast(_assignment.variableNames.size()), height); - m_assembly.setSourceLocation(locationOf(_assignment)); + m_assembly.setSourceLocation(originLocationOf(_assignment)); generateMultiAssignment(_assignment.variableNames); } void CodeTransform::operator()(ExpressionStatement const& _statement) { - m_assembly.setSourceLocation(locationOf(_statement)); + m_assembly.setSourceLocation(originLocationOf(_statement)); std::visit(*this, _statement.expression); } @@ -227,13 +227,13 @@ void CodeTransform::operator()(FunctionCall const& _call) { yulAssert(m_scope, ""); - m_assembly.setSourceLocation(locationOf(_call)); + m_assembly.setSourceLocation(originLocationOf(_call)); if (BuiltinFunctionForEVM const* builtin = m_dialect.builtin(_call.functionName.name)) { for (auto&& [i, arg]: _call.arguments | ranges::views::enumerate | ranges::views::reverse) if (!builtin->literalArgument(i)) visitExpression(arg); - m_assembly.setSourceLocation(locationOf(_call)); + m_assembly.setSourceLocation(originLocationOf(_call)); builtin->generateCode(_call, m_assembly, m_builtinContext); } else @@ -250,7 +250,7 @@ void CodeTransform::operator()(FunctionCall const& _call) yulAssert(function->arguments.size() == _call.arguments.size(), ""); for (auto const& arg: _call.arguments | ranges::views::reverse) visitExpression(arg); - m_assembly.setSourceLocation(locationOf(_call)); + m_assembly.setSourceLocation(originLocationOf(_call)); m_assembly.appendJumpTo( functionEntryID(*function), static_cast(function->returns.size() - function->arguments.size()) - 1, @@ -262,7 +262,7 @@ void CodeTransform::operator()(FunctionCall const& _call) void CodeTransform::operator()(Identifier const& _identifier) { - m_assembly.setSourceLocation(locationOf(_identifier)); + m_assembly.setSourceLocation(originLocationOf(_identifier)); // First search internals, then externals. yulAssert(m_scope, ""); if (m_scope->lookup(_identifier.name, GenericVisitor{ @@ -294,19 +294,19 @@ void CodeTransform::operator()(Identifier const& _identifier) void CodeTransform::operator()(Literal const& _literal) { - m_assembly.setSourceLocation(locationOf(_literal)); + m_assembly.setSourceLocation(originLocationOf(_literal)); m_assembly.appendConstant(valueOfLiteral(_literal)); } void CodeTransform::operator()(If const& _if) { visitExpression(*_if.condition); - m_assembly.setSourceLocation(locationOf(_if)); + m_assembly.setSourceLocation(originLocationOf(_if)); m_assembly.appendInstruction(evmasm::Instruction::ISZERO); AbstractAssembly::LabelID end = m_assembly.newLabelId(); m_assembly.appendJumpToIf(end); (*this)(_if.body); - m_assembly.setSourceLocation(locationOf(_if)); + m_assembly.setSourceLocation(originLocationOf(_if)); m_assembly.appendLabel(end); } @@ -321,7 +321,7 @@ void CodeTransform::operator()(Switch const& _switch) if (c.value) { (*this)(*c.value); - m_assembly.setSourceLocation(locationOf(c)); + m_assembly.setSourceLocation(originLocationOf(c)); AbstractAssembly::LabelID bodyLabel = m_assembly.newLabelId(); caseBodies[&c] = bodyLabel; yulAssert(m_assembly.stackHeight() == expressionHeight + 1, ""); @@ -333,24 +333,24 @@ void CodeTransform::operator()(Switch const& _switch) // default case (*this)(c.body); } - m_assembly.setSourceLocation(locationOf(_switch)); + m_assembly.setSourceLocation(originLocationOf(_switch)); m_assembly.appendJumpTo(end); size_t numCases = caseBodies.size(); for (auto const& c: caseBodies) { - m_assembly.setSourceLocation(locationOf(*c.first)); + m_assembly.setSourceLocation(originLocationOf(*c.first)); m_assembly.appendLabel(c.second); (*this)(c.first->body); // Avoid useless "jump to next" for the last case. if (--numCases > 0) { - m_assembly.setSourceLocation(locationOf(*c.first)); + m_assembly.setSourceLocation(originLocationOf(*c.first)); m_assembly.appendJumpTo(end); } } - m_assembly.setSourceLocation(locationOf(_switch)); + m_assembly.setSourceLocation(originLocationOf(_switch)); m_assembly.appendLabel(end); m_assembly.appendInstruction(evmasm::Instruction::POP); } @@ -371,7 +371,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function) m_context->variableStackHeights[&var] = height++; } - m_assembly.setSourceLocation(locationOf(_function)); + m_assembly.setSourceLocation(originLocationOf(_function)); int const stackHeightBefore = m_assembly.stackHeight(); m_assembly.appendLabel(functionEntryID(function)); @@ -407,7 +407,7 @@ void CodeTransform::operator()(FunctionDefinition const& _function) subTransform(_function.body); - m_assembly.setSourceLocation(locationOf(_function)); + m_assembly.setSourceLocation(originLocationOf(_function)); if (!subTransform.m_stackErrors.empty()) { m_assembly.markAsInvalid(); @@ -498,11 +498,11 @@ void CodeTransform::operator()(ForLoop const& _forLoop) AbstractAssembly::LabelID postPart = m_assembly.newLabelId(); AbstractAssembly::LabelID loopEnd = m_assembly.newLabelId(); - m_assembly.setSourceLocation(locationOf(_forLoop)); + m_assembly.setSourceLocation(originLocationOf(_forLoop)); m_assembly.appendLabel(loopStart); visitExpression(*_forLoop.condition); - m_assembly.setSourceLocation(locationOf(_forLoop)); + m_assembly.setSourceLocation(originLocationOf(_forLoop)); m_assembly.appendInstruction(evmasm::Instruction::ISZERO); m_assembly.appendJumpToIf(loopEnd); @@ -510,12 +510,12 @@ void CodeTransform::operator()(ForLoop const& _forLoop) m_context->forLoopStack.emplace(Context::ForLoopLabels{ {postPart, stackHeightBody}, {loopEnd, stackHeightBody} }); (*this)(_forLoop.body); - m_assembly.setSourceLocation(locationOf(_forLoop)); + m_assembly.setSourceLocation(originLocationOf(_forLoop)); m_assembly.appendLabel(postPart); (*this)(_forLoop.post); - m_assembly.setSourceLocation(locationOf(_forLoop)); + m_assembly.setSourceLocation(originLocationOf(_forLoop)); m_assembly.appendJumpTo(loopStart); m_assembly.appendLabel(loopEnd); @@ -535,7 +535,7 @@ int CodeTransform::appendPopUntil(int _targetDepth) void CodeTransform::operator()(Break const& _break) { yulAssert(!m_context->forLoopStack.empty(), "Invalid break-statement. Requires surrounding for-loop in code generation."); - m_assembly.setSourceLocation(locationOf(_break)); + m_assembly.setSourceLocation(originLocationOf(_break)); Context::JumpInfo const& jump = m_context->forLoopStack.top().done; m_assembly.appendJumpTo(jump.label, appendPopUntil(jump.targetStackHeight)); @@ -544,7 +544,7 @@ void CodeTransform::operator()(Break const& _break) void CodeTransform::operator()(Continue const& _continue) { yulAssert(!m_context->forLoopStack.empty(), "Invalid continue-statement. Requires surrounding for-loop in code generation."); - m_assembly.setSourceLocation(locationOf(_continue)); + m_assembly.setSourceLocation(originLocationOf(_continue)); Context::JumpInfo const& jump = m_context->forLoopStack.top().post; m_assembly.appendJumpTo(jump.label, appendPopUntil(jump.targetStackHeight)); @@ -554,7 +554,7 @@ void CodeTransform::operator()(Leave const& _leaveStatement) { yulAssert(m_functionExitLabel, "Invalid leave-statement. Requires surrounding function in code generation."); yulAssert(m_functionExitStackHeight, ""); - m_assembly.setSourceLocation(locationOf(_leaveStatement)); + m_assembly.setSourceLocation(originLocationOf(_leaveStatement)); m_assembly.appendJumpTo(*m_functionExitLabel, appendPopUntil(*m_functionExitStackHeight)); } @@ -683,7 +683,7 @@ void CodeTransform::visitStatements(vector const& _statements) auto const* functionDefinition = std::get_if(&statement); if (functionDefinition && !jumpTarget) { - m_assembly.setSourceLocation(locationOf(*functionDefinition)); + m_assembly.setSourceLocation(originLocationOf(*functionDefinition)); jumpTarget = m_assembly.newLabelId(); m_assembly.appendJumpTo(*jumpTarget, 0); } @@ -704,7 +704,7 @@ void CodeTransform::visitStatements(vector const& _statements) void CodeTransform::finalizeBlock(Block const& _block, optional blockStartStackHeight) { - m_assembly.setSourceLocation(locationOf(_block)); + m_assembly.setSourceLocation(originLocationOf(_block)); freeUnusedVariables(); diff --git a/libyul/backends/evm/OptimizedEVMCodeTransform.cpp b/libyul/backends/evm/OptimizedEVMCodeTransform.cpp index 3aedfec3a..106e636c8 100644 --- a/libyul/backends/evm/OptimizedEVMCodeTransform.cpp +++ b/libyul/backends/evm/OptimizedEVMCodeTransform.cpp @@ -85,7 +85,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::FunctionCall const& _call) // Emit code. { - m_assembly.setSourceLocation(locationOf(_call)); + m_assembly.setSourceLocation(originLocationOf(_call)); m_assembly.appendJumpTo( getFunctionLabel(_call.function), static_cast(_call.function.get().returns.size() - _call.function.get().arguments.size()) - 1, @@ -128,7 +128,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BuiltinCall const& _call) // Emit code. { - m_assembly.setSourceLocation(locationOf(_call)); + m_assembly.setSourceLocation(originLocationOf(_call)); static_cast(_call.builtin.get()).generateCode( _call.functionCall, m_assembly, @@ -231,7 +231,7 @@ void OptimizedEVMCodeTransform::createStackLayout(std::shared_ptr(m_stack.size()), ""); // ::createStackLayout asserts that it has successfully achieved the target layout. - langutil::SourceLocation sourceLocation = _debugData ? _debugData->location : langutil::SourceLocation{}; + langutil::SourceLocation sourceLocation = _debugData ? _debugData->originLocation : langutil::SourceLocation{}; m_assembly.setSourceLocation(sourceLocation); ::createStackLayout( m_stack, @@ -299,7 +299,7 @@ void OptimizedEVMCodeTransform::createStackLayout(std::shared_ptrreturnVariables, _variable)) { - m_assembly.setSourceLocation(locationOf(_variable)); + m_assembly.setSourceLocation(originLocationOf(_variable)); m_assembly.appendConstant(0); m_assembly.setSourceLocation(sourceLocation); return; @@ -351,7 +351,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block) // Assert that this is the first visit of the block and mark as generated. yulAssert(m_generated.insert(&_block).second, ""); - m_assembly.setSourceLocation(locationOf(_block)); + m_assembly.setSourceLocation(originLocationOf(_block)); auto const& blockInfo = m_stackLayout.blockInfos.at(&_block); // Assert that the stack is valid for entering the block. @@ -391,7 +391,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::BasicBlock const& _block) } // Exit the block. - m_assembly.setSourceLocation(locationOf(_block)); + m_assembly.setSourceLocation(originLocationOf(_block)); std::visit(util::GenericVisitor{ [&](CFG::BasicBlock::MainExit const&) { @@ -506,7 +506,7 @@ void OptimizedEVMCodeTransform::operator()(CFG::FunctionInfo const& _functionInf m_stack.emplace_back(param); m_assembly.setStackHeight(static_cast(m_stack.size())); - m_assembly.setSourceLocation(locationOf(_functionInfo)); + m_assembly.setSourceLocation(originLocationOf(_functionInfo)); m_assembly.appendLabel(getFunctionLabel(_functionInfo.function)); // Create the entry layout of the function body block and visit. diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index 0a16aaccb..49152e7f8 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -214,7 +214,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_empty_block) EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); - CHECK_LOCATION(result->debugData->location, "source0", 234, 543); + CHECK_LOCATION(result->debugData->originLocation, "source0", 234, 543); } BOOST_AUTO_TEST_CASE(customSourceLocations_block_with_children) @@ -232,12 +232,12 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_block_with_children) EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result); - CHECK_LOCATION(result->debugData->location, "source0", 234, 543); + CHECK_LOCATION(result->debugData->originLocation, "source0", 234, 543); BOOST_REQUIRE_EQUAL(3, result->statements.size()); - CHECK_LOCATION(locationOf(result->statements.at(0)), "source0", 234, 543); - CHECK_LOCATION(locationOf(result->statements.at(1)), "source0", 123, 432); + CHECK_LOCATION(originLocationOf(result->statements.at(0)), "source0", 234, 543); + CHECK_LOCATION(originLocationOf(result->statements.at(1)), "source0", 123, 432); // [2] is inherited source location - CHECK_LOCATION(locationOf(result->statements.at(2)), "source0", 123, 432); + CHECK_LOCATION(originLocationOf(result->statements.at(2)), "source0", 123, 432); } BOOST_AUTO_TEST_CASE(customSourceLocations_block_different_sources) @@ -255,12 +255,12 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_block_different_sources) EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); - CHECK_LOCATION(result->debugData->location, "source0", 234, 543); + CHECK_LOCATION(result->debugData->originLocation, "source0", 234, 543); BOOST_REQUIRE_EQUAL(3, result->statements.size()); - CHECK_LOCATION(locationOf(result->statements.at(0)), "source0", 234, 543); - CHECK_LOCATION(locationOf(result->statements.at(1)), "source1", 123, 432); + CHECK_LOCATION(originLocationOf(result->statements.at(0)), "source0", 234, 543); + CHECK_LOCATION(originLocationOf(result->statements.at(1)), "source1", 123, 432); // [2] is inherited source location - CHECK_LOCATION(locationOf(result->statements.at(2)), "source1", 123, 432); + CHECK_LOCATION(originLocationOf(result->statements.at(2)), "source1", 123, 432); } BOOST_AUTO_TEST_CASE(customSourceLocations_block_nested) @@ -277,9 +277,9 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_block_nested) EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); - CHECK_LOCATION(result->debugData->location, "source0", 234, 543); + CHECK_LOCATION(result->debugData->originLocation, "source0", 234, 543); BOOST_REQUIRE_EQUAL(2, result->statements.size()); - CHECK_LOCATION(locationOf(result->statements.at(1)), "source0", 343, 434); + CHECK_LOCATION(originLocationOf(result->statements.at(1)), "source0", 343, 434); } BOOST_AUTO_TEST_CASE(customSourceLocations_block_switch_case) @@ -301,19 +301,19 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_block_switch_case) EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); - CHECK_LOCATION(result->debugData->location, "source0", 234, 543); + CHECK_LOCATION(result->debugData->originLocation, "source0", 234, 543); BOOST_REQUIRE_EQUAL(2, result->statements.size()); BOOST_REQUIRE(holds_alternative(result->statements.at(1))); auto const& switchStmt = get(result->statements.at(1)); - CHECK_LOCATION(switchStmt.debugData->location, "source0", 343, 434); + CHECK_LOCATION(switchStmt.debugData->originLocation, "source0", 343, 434); BOOST_REQUIRE_EQUAL(1, switchStmt.cases.size()); - CHECK_LOCATION(switchStmt.cases.at(0).debugData->location, "source0", 3141, 59265); + CHECK_LOCATION(switchStmt.cases.at(0).debugData->originLocation, "source0", 3141, 59265); auto const& caseBody = switchStmt.cases.at(0).body; BOOST_REQUIRE_EQUAL(1, caseBody.statements.size()); - CHECK_LOCATION(locationOf(caseBody.statements.at(0)), "source0", 271, 828); + CHECK_LOCATION(originLocationOf(caseBody.statements.at(0)), "source0", 271, 828); } BOOST_AUTO_TEST_CASE(customSourceLocations_inherit_into_outer_scope) @@ -334,19 +334,19 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_inherit_into_outer_scope) shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); - CHECK_LOCATION(result->debugData->location, "source0", 1, 100); + CHECK_LOCATION(result->debugData->originLocation, "source0", 1, 100); BOOST_REQUIRE_EQUAL(3, result->statements.size()); - CHECK_LOCATION(locationOf(result->statements.at(0)), "source0", 1, 100); + CHECK_LOCATION(originLocationOf(result->statements.at(0)), "source0", 1, 100); // First child element must be a block itself with one statement. BOOST_REQUIRE(holds_alternative(result->statements.at(0))); BOOST_REQUIRE_EQUAL(get(result->statements.at(0)).statements.size(), 1); - CHECK_LOCATION(locationOf(get(result->statements.at(0)).statements.at(0)), "source0", 123, 432); + CHECK_LOCATION(originLocationOf(get(result->statements.at(0)).statements.at(0)), "source0", 123, 432); // The next two elements have an inherited source location from the prior inner scope. - CHECK_LOCATION(locationOf(result->statements.at(1)), "source0", 123, 432); - CHECK_LOCATION(locationOf(result->statements.at(2)), "source0", 123, 432); + CHECK_LOCATION(originLocationOf(result->statements.at(1)), "source0", 123, 432); + CHECK_LOCATION(originLocationOf(result->statements.at(2)), "source0", 123, 432); } BOOST_AUTO_TEST_CASE(customSourceLocations_assign_empty) @@ -365,8 +365,8 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_assign_empty) shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); // should still parse BOOST_REQUIRE_EQUAL(2, result->statements.size()); - CHECK_LOCATION(locationOf(result->statements.at(0)), "source0", 123, 432); - CHECK_LOCATION(locationOf(result->statements.at(1)), "source1", 1, 10); + CHECK_LOCATION(originLocationOf(result->statements.at(0)), "source0", 123, 432); + CHECK_LOCATION(originLocationOf(result->statements.at(1)), "source1", 1, 10); } BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_source_index) @@ -407,10 +407,10 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_mixed_locations_1) BOOST_REQUIRE(!!result && errorList.size() == 0); BOOST_REQUIRE_EQUAL(1, result->statements.size()); - CHECK_LOCATION(locationOf(result->statements.at(0)), "source0", 123, 432); + CHECK_LOCATION(originLocationOf(result->statements.at(0)), "source0", 123, 432); BOOST_REQUIRE(holds_alternative(result->statements.at(0))); VariableDeclaration const& varDecl = get(result->statements.at(0)); - CHECK_LOCATION(locationOf(*varDecl.value), "source0", 234, 2026); + CHECK_LOCATION(originLocationOf(*varDecl.value), "source0", 234, 2026); } BOOST_AUTO_TEST_CASE(customSourceLocations_mixed_locations_2) @@ -429,20 +429,20 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_mixed_locations_2) shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); BOOST_REQUIRE_EQUAL(1, result->statements.size()); - CHECK_LOCATION(result->debugData->location, "source0", 0, 5); + CHECK_LOCATION(result->debugData->originLocation, "source0", 0, 5); // `let x := add(1, ` BOOST_REQUIRE(holds_alternative(result->statements.at(0))); VariableDeclaration const& varDecl = get(result->statements.at(0)); - CHECK_LOCATION(varDecl.debugData->location, "source0", 0, 5); + CHECK_LOCATION(varDecl.debugData->originLocation, "source0", 0, 5); BOOST_REQUIRE(!!varDecl.value); BOOST_REQUIRE(holds_alternative(*varDecl.value)); FunctionCall const& call = get(*varDecl.value); - CHECK_LOCATION(call.debugData->location, "source1", 2, 3); + CHECK_LOCATION(call.debugData->originLocation, "source1", 2, 3); // `2` BOOST_REQUIRE_EQUAL(2, call.arguments.size()); - CHECK_LOCATION(locationOf(call.arguments.at(1)), "source0", 4, 8); + CHECK_LOCATION(originLocationOf(call.arguments.at(1)), "source0", 4, 8); } BOOST_AUTO_TEST_CASE(customSourceLocations_mixed_locations_3) @@ -463,24 +463,24 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_mixed_locations_3) shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); BOOST_REQUIRE_EQUAL(2, result->statements.size()); - CHECK_LOCATION(result->debugData->location, "source1", 23, 45); + CHECK_LOCATION(result->debugData->originLocation, "source1", 23, 45); BOOST_REQUIRE(holds_alternative(result->statements.at(0))); Block const& innerBlock = get(result->statements.at(0)); - CHECK_LOCATION(innerBlock.debugData->location, "source1", 23, 45); + CHECK_LOCATION(innerBlock.debugData->originLocation, "source1", 23, 45); BOOST_REQUIRE_EQUAL(1, innerBlock.statements.size()); BOOST_REQUIRE(holds_alternative(result->statements.at(1))); ExpressionStatement const& sstoreStmt = get(innerBlock.statements.at(0)); BOOST_REQUIRE(holds_alternative(sstoreStmt.expression)); FunctionCall const& sstoreCall = get(sstoreStmt.expression); - CHECK_LOCATION(sstoreCall.debugData->location, "source1", 23, 45); + CHECK_LOCATION(sstoreCall.debugData->originLocation, "source1", 23, 45); BOOST_REQUIRE(holds_alternative(result->statements.at(1))); ExpressionStatement mstoreStmt = get(result->statements.at(1)); BOOST_REQUIRE(holds_alternative(mstoreStmt.expression)); FunctionCall const& mstoreCall = get(mstoreStmt.expression); - CHECK_LOCATION(mstoreCall.debugData->location, "source0", 420, 680); + CHECK_LOCATION(mstoreCall.debugData->originLocation, "source0", 420, 680); } BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_comments_after_valid) @@ -499,11 +499,11 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_comments_after_valid) shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); BOOST_REQUIRE_EQUAL(1, result->statements.size()); - CHECK_LOCATION(result->debugData->location, "source1", 23, 45); + CHECK_LOCATION(result->debugData->originLocation, "source1", 23, 45); BOOST_REQUIRE(holds_alternative(result->statements.at(0))); VariableDeclaration const& varDecl = get(result->statements.at(0)); - CHECK_LOCATION(varDecl.debugData->location, "source0", 420, 680); + CHECK_LOCATION(varDecl.debugData->originLocation, "source0", 420, 680); } BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_suffix) @@ -520,7 +520,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_suffix) BOOST_REQUIRE(errorList.size() == 1); BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); BOOST_TEST(errorList[0]->errorId() == 8387_error); - CHECK_LOCATION(result->debugData->location, "", -1, -1); + CHECK_LOCATION(result->debugData->originLocation, "", -1, -1); } BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_prefix) @@ -534,7 +534,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_invalid_prefix) EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); - CHECK_LOCATION(result->debugData->location, "", -1, -1); + CHECK_LOCATION(result->debugData->originLocation, "", -1, -1); } BOOST_AUTO_TEST_CASE(customSourceLocations_unspecified) @@ -548,7 +548,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_unspecified) EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); - CHECK_LOCATION(result->debugData->location, "", -1, -1); + CHECK_LOCATION(result->debugData->originLocation, "", -1, -1); } BOOST_AUTO_TEST_CASE(customSourceLocations_non_integer) @@ -565,7 +565,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_non_integer) BOOST_REQUIRE(errorList.size() == 1); BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); BOOST_TEST(errorList[0]->errorId() == 8387_error); - CHECK_LOCATION(result->debugData->location, "", -1, -1); + CHECK_LOCATION(result->debugData->originLocation, "", -1, -1); } BOOST_AUTO_TEST_CASE(customSourceLocations_bad_integer) @@ -582,7 +582,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_bad_integer) BOOST_REQUIRE(errorList.size() == 1); BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); BOOST_TEST(errorList[0]->errorId() == 6367_error); - CHECK_LOCATION(result->debugData->location, "", -1, -1); + CHECK_LOCATION(result->debugData->originLocation, "", -1, -1); } BOOST_AUTO_TEST_CASE(customSourceLocations_ensure_last_match) @@ -604,7 +604,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_ensure_last_match) VariableDeclaration const& varDecl = get(result->statements.at(0)); // Ensure the latest @src per documentation-comment is used (0:30:40). - CHECK_LOCATION(varDecl.debugData->location, "source0", 30, 40); + CHECK_LOCATION(varDecl.debugData->originLocation, "source0", 30, 40); } BOOST_AUTO_TEST_CASE(customSourceLocations_two_locations_no_whitespace) @@ -621,7 +621,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_two_locations_no_whitespace) BOOST_REQUIRE(errorList.size() == 1); BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); BOOST_TEST(errorList[0]->errorId() == 8387_error); - CHECK_LOCATION(result->debugData->location, "", -1, -1); + CHECK_LOCATION(result->debugData->originLocation, "", -1, -1); } BOOST_AUTO_TEST_CASE(customSourceLocations_two_locations_separated_with_single_space) @@ -635,7 +635,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_two_locations_separated_with_single_s EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); - CHECK_LOCATION(result->debugData->location, "source1", 333, 444); + CHECK_LOCATION(result->debugData->originLocation, "source1", 333, 444); } BOOST_AUTO_TEST_CASE(customSourceLocations_leading_trailing_whitespace) @@ -646,7 +646,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_leading_trailing_whitespace) EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); - CHECK_LOCATION(result->debugData->location, "source0", 111, 222); + CHECK_LOCATION(result->debugData->originLocation, "source0", 111, 222); } BOOST_AUTO_TEST_CASE(customSourceLocations_reference_original_sloc) @@ -667,7 +667,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_reference_original_sloc) VariableDeclaration const& varDecl = get(result->statements.at(0)); // -1 points to original source code, which in this case is `"source0"` (which is also - CHECK_LOCATION(varDecl.debugData->location, "", 10, 20); + CHECK_LOCATION(varDecl.debugData->originLocation, "", 10, 20); } BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets) @@ -689,14 +689,14 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets) BOOST_REQUIRE(holds_alternative(result->statements.at(0))); VariableDeclaration const& varX = get(result->statements.at(0)); - CHECK_LOCATION(varX.debugData->location, "source0", 149, 156); + CHECK_LOCATION(varX.debugData->originLocation, "source0", 149, 156); BOOST_REQUIRE(holds_alternative(result->statements.at(1))); VariableDeclaration const& varY = get(result->statements.at(1)); BOOST_REQUIRE(!!varY.value); BOOST_REQUIRE(holds_alternative(*varY.value)); Literal const& literal128 = get(*varY.value); - CHECK_LOCATION(literal128.debugData->location, "source1", 96, 165); + CHECK_LOCATION(literal128.debugData->originLocation, "source1", 96, 165); } BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets_empty_snippet) @@ -710,7 +710,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets_empty_snippet) EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); - CHECK_LOCATION(result->debugData->location, "source0", 111, 222); + CHECK_LOCATION(result->debugData->originLocation, "source0", 111, 222); } BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets_no_whitespace_before_snippet) @@ -727,7 +727,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets_no_whitespace_befo BOOST_REQUIRE(errorList.size() == 1); BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); BOOST_TEST(errorList[0]->errorId() == 8387_error); - CHECK_LOCATION(result->debugData->location, "", -1, -1); + CHECK_LOCATION(result->debugData->originLocation, "", -1, -1); } BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets_no_whitespace_after_snippet) @@ -741,7 +741,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets_no_whitespace_afte EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); - CHECK_LOCATION(result->debugData->location, "source0", 111, 222); + CHECK_LOCATION(result->debugData->originLocation, "source0", 111, 222); } BOOST_AUTO_TEST_CASE(customSourceLocations_two_locations_with_snippets_no_whitespace) @@ -755,7 +755,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_two_locations_with_snippets_no_whites EVMDialectTyped const& dialect = EVMDialectTyped::instance(EVMVersion{}); shared_ptr result = parse(sourceText, dialect, reporter); BOOST_REQUIRE(!!result && errorList.size() == 0); - CHECK_LOCATION(result->debugData->location, "source1", 333, 444); + CHECK_LOCATION(result->debugData->originLocation, "source1", 333, 444); } BOOST_AUTO_TEST_CASE(customSourceLocations_two_locations_with_snippets_unterminated_quote) @@ -772,7 +772,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_two_locations_with_snippets_untermina BOOST_REQUIRE(errorList.size() == 1); BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); BOOST_TEST(errorList[0]->errorId() == 1544_error); - CHECK_LOCATION(result->debugData->location, "", -1, -1); + CHECK_LOCATION(result->debugData->originLocation, "", -1, -1); } BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets_with_nested_locations) @@ -794,14 +794,14 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_with_code_snippets_with_nested_locati BOOST_REQUIRE(holds_alternative(result->statements.at(0))); VariableDeclaration const& varX = get(result->statements.at(0)); - CHECK_LOCATION(varX.debugData->location, "source0", 149, 156); + CHECK_LOCATION(varX.debugData->originLocation, "source0", 149, 156); BOOST_REQUIRE(holds_alternative(result->statements.at(1))); VariableDeclaration const& varY = get(result->statements.at(1)); BOOST_REQUIRE(!!varY.value); BOOST_REQUIRE(holds_alternative(*varY.value)); Literal const& literal128 = get(*varY.value); - CHECK_LOCATION(literal128.debugData->location, "source1", 96, 165); + CHECK_LOCATION(literal128.debugData->originLocation, "source1", 96, 165); } BOOST_AUTO_TEST_CASE(astid) @@ -876,7 +876,7 @@ BOOST_AUTO_TEST_CASE(astid_invalid) BOOST_REQUIRE(errorList.size() == 1); BOOST_TEST(errorList[0]->type() == Error::Type::SyntaxError); BOOST_TEST(errorList[0]->errorId() == 1749_error); - CHECK_LOCATION(result->debugData->location, "", -1, -1); + CHECK_LOCATION(result->debugData->originLocation, "", -1, -1); } BOOST_AUTO_TEST_CASE(astid_too_large) @@ -948,7 +948,7 @@ BOOST_AUTO_TEST_CASE(customSourceLocations_multiple_src_tags_on_one_line) BOOST_REQUIRE(holds_alternative(result->statements.at(0))); VariableDeclaration const& varX = get(result->statements.at(0)); - CHECK_LOCATION(varX.debugData->location, "source1", 4, 5); + CHECK_LOCATION(varX.debugData->originLocation, "source1", 4, 5); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libyul/yulSyntaxTests/invalid/leave_items_on_stack_with_debug_info.yul b/test/libyul/yulSyntaxTests/invalid/leave_items_on_stack_with_debug_info.yul index e8df2c6ea..ce93dd922 100644 --- a/test/libyul/yulSyntaxTests/invalid/leave_items_on_stack_with_debug_info.yul +++ b/test/libyul/yulSyntaxTests/invalid/leave_items_on_stack_with_debug_info.yul @@ -6,4 +6,4 @@ object "C" { } } // ---- -// TypeError 3083: (0-0): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. +// TypeError 3083: (82-97): Top-level expressions are not supposed to return values (this expression returns 1 value). Use ``pop()`` or assign them. diff --git a/test/libyul/yulSyntaxTests/invalid_tuple_assignment_with_debug_info.yul b/test/libyul/yulSyntaxTests/invalid_tuple_assignment_with_debug_info.yul index 39476217e..8ea0302eb 100644 --- a/test/libyul/yulSyntaxTests/invalid_tuple_assignment_with_debug_info.yul +++ b/test/libyul/yulSyntaxTests/invalid_tuple_assignment_with_debug_info.yul @@ -5,4 +5,4 @@ object "C" { } } // ---- -// DeclarationError 3812: Variable count mismatch for declaration of "x, y": 2 variables and 1 values. +// DeclarationError 3812: (59-72): Variable count mismatch for declaration of "x, y": 2 variables and 1 values. diff --git a/test/libyul/yulSyntaxTests/name_clash_sub_scope_with_debug_info.yul b/test/libyul/yulSyntaxTests/name_clash_sub_scope_with_debug_info.yul index 4c88c2a42..b6c2ab66c 100644 --- a/test/libyul/yulSyntaxTests/name_clash_sub_scope_with_debug_info.yul +++ b/test/libyul/yulSyntaxTests/name_clash_sub_scope_with_debug_info.yul @@ -8,4 +8,4 @@ object "C" { } } // ---- -// DeclarationError 6052: (0-0): Function name g already taken in this scope. +// DeclarationError 6052: (109-124): Function name g already taken in this scope. From d23754eafd24038b81a8742d0bc2980b00d8722d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 21 Sep 2021 14:33:43 +0200 Subject: [PATCH 153/232] AsmParser: Don't use locationOverride as current location when location from comments is selected --- libyul/AsmParser.h | 7 ++++--- .../literals_on_stack_disallowed_with_debug_info.yul | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/libyul/AsmParser.h b/libyul/AsmParser.h index 229c2ef44..da4f09ed2 100644 --- a/libyul/AsmParser.h +++ b/libyul/AsmParser.h @@ -97,9 +97,10 @@ public: protected: langutil::SourceLocation currentLocation() const override { - if (m_useSourceLocationFrom == UseSourceLocationFrom::Scanner) - return ParserBase::currentLocation(); - return m_locationOverride; + if (m_useSourceLocationFrom == UseSourceLocationFrom::LocationOverride) + return m_locationOverride; + + return ParserBase::currentLocation(); } langutil::Token advance() override; diff --git a/test/libyul/yulSyntaxTests/invalid/literals_on_stack_disallowed_with_debug_info.yul b/test/libyul/yulSyntaxTests/invalid/literals_on_stack_disallowed_with_debug_info.yul index f27be64f5..79ba4f83d 100644 --- a/test/libyul/yulSyntaxTests/invalid/literals_on_stack_disallowed_with_debug_info.yul +++ b/test/libyul/yulSyntaxTests/invalid/literals_on_stack_disallowed_with_debug_info.yul @@ -5,5 +5,5 @@ object "C" { } } // ---- -// ParserError 6913: Call or assignment expected. +// ParserError 6913: (65-66): Call or assignment expected. // ParserError 2314: (67-68): Expected end of source but got '}' From fc7e8c56dc1390336e45da39c486fe8d329930bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 22 Sep 2021 11:59:59 +0200 Subject: [PATCH 154/232] Fill out originLocation with nativeLocation when importing Yul AST --- libsolidity/analysis/ControlFlowBuilder.cpp | 9 +++++++-- libsolidity/analysis/ReferencesResolver.cpp | 8 +++++++- libyul/AsmJsonImporter.cpp | 5 ++++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/libsolidity/analysis/ControlFlowBuilder.cpp b/libsolidity/analysis/ControlFlowBuilder.cpp index 3b87f6515..9e3ac3ae1 100644 --- a/libsolidity/analysis/ControlFlowBuilder.cpp +++ b/libsolidity/analysis/ControlFlowBuilder.cpp @@ -409,6 +409,7 @@ bool ControlFlowBuilder::visit(InlineAssembly const& _inlineAssembly) void ControlFlowBuilder::visit(yul::Statement const& _statement) { solAssert(m_currentNode && m_inlineAssembly, ""); + solAssert(nativeLocationOf(_statement) == originLocationOf(_statement), ""); m_currentNode->location = langutil::SourceLocation::smallestCovering(m_currentNode->location, nativeLocationOf(_statement)); ASTWalker::visit(_statement); } @@ -496,14 +497,15 @@ void ControlFlowBuilder::operator()(yul::Identifier const& _identifier) solAssert(m_currentNode && m_inlineAssembly, ""); auto const& externalReferences = m_inlineAssembly->annotation().externalReferences; if (externalReferences.count(&_identifier)) - { if (auto const* declaration = dynamic_cast(externalReferences.at(&_identifier).declaration)) + { + solAssert(nativeLocationOf(_identifier) == originLocationOf(_identifier), ""); m_currentNode->variableOccurrences.emplace_back( *declaration, VariableOccurrence::Kind::Access, nativeLocationOf(_identifier) ); - } + } } void ControlFlowBuilder::operator()(yul::Assignment const& _assignment) @@ -514,11 +516,14 @@ void ControlFlowBuilder::operator()(yul::Assignment const& _assignment) for (auto const& variable: _assignment.variableNames) if (externalReferences.count(&variable)) if (auto const* declaration = dynamic_cast(externalReferences.at(&variable).declaration)) + { + solAssert(nativeLocationOf(variable) == originLocationOf(variable), ""); m_currentNode->variableOccurrences.emplace_back( *declaration, VariableOccurrence::Kind::Assignment, nativeLocationOf(variable) ); + } } void ControlFlowBuilder::operator()(yul::FunctionCall const& _functionCall) diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index ae2d82827..ee0c7d726 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -201,9 +201,13 @@ bool ReferencesResolver::visit(Return const& _return) void ReferencesResolver::operator()(yul::FunctionDefinition const& _function) { + solAssert(nativeLocationOf(_function) == originLocationOf(_function), ""); validateYulIdentifierName(_function.name, nativeLocationOf(_function)); for (yul::TypedName const& varName: _function.parameters + _function.returnVariables) + { + solAssert(nativeLocationOf(varName) == originLocationOf(varName), ""); validateYulIdentifierName(varName.name, nativeLocationOf(varName)); + } bool wasInsideFunction = m_yulInsideFunction; m_yulInsideFunction = true; @@ -213,6 +217,8 @@ void ReferencesResolver::operator()(yul::FunctionDefinition const& _function) void ReferencesResolver::operator()(yul::Identifier const& _identifier) { + solAssert(nativeLocationOf(_identifier) == originLocationOf(_identifier), ""); + static set suffixes{"slot", "offset", "length"}; string suffix; for (string const& s: suffixes) @@ -275,9 +281,9 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl) { for (auto const& identifier: _varDecl.variables) { + solAssert(nativeLocationOf(identifier) == originLocationOf(identifier), ""); validateYulIdentifierName(identifier.name, nativeLocationOf(identifier)); - if ( auto declarations = m_resolver.nameFromCurrentScope(identifier.name.str()); !declarations.empty() diff --git a/libyul/AsmJsonImporter.cpp b/libyul/AsmJsonImporter.cpp index 7b17d73cb..8fb4eaeb3 100644 --- a/libyul/AsmJsonImporter.cpp +++ b/libyul/AsmJsonImporter.cpp @@ -55,7 +55,10 @@ T AsmJsonImporter::createAsmNode(Json::Value const& _node) T r; SourceLocation nativeLocation = createSourceLocation(_node); yulAssert(nativeLocation.hasText(), "Invalid source location in Asm AST"); - r.debugData = DebugData::create(nativeLocation); + // TODO: We should add originLocation to the AST. + // While it's not included, we'll use nativeLocation for it because we only support importing + // inline assembly as a part of a Solidity AST and there these locations are always the same. + r.debugData = DebugData::create(nativeLocation, nativeLocation); return r; } From 9f8406ad37c07aa8e20f77ee357340e0f6669c61 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 15 Jul 2021 16:06:38 +0200 Subject: [PATCH 155/232] Add protection against mixing "viaIR" and "non-viaIR". --- libsolidity/interface/CompilerStack.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 1703aa6cc..4767651de 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -741,9 +741,10 @@ Json::Value CompilerStack::generatedSources(string const& _contractName, bool _r return sources.init([&]{ Json::Value sources{Json::arrayValue}; // If there is no compiler, then no bytecode was generated and thus no - // sources were generated. + // sources were generated (or we compiled "via IR"). if (c.compiler) { + solAssert(!m_viaIR, ""); string source = _runtime ? c.compiler->runtimeGeneratedYulUtilityCode() : @@ -1251,6 +1252,7 @@ void CompilerStack::compileContract( map>& _otherCompilers ) { + solAssert(!m_viaIR, ""); solAssert(m_stackState >= AnalysisPerformed, ""); if (m_hasError) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Called compile with errors.")); From 34b84776641c7228409aba2c17659b20c3bb7a9a Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 22 Sep 2021 23:54:05 +0100 Subject: [PATCH 156/232] Improve `--optimize-runs` text --- solc/CommandLineParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index a72a010ab..a2b8676fc 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -724,7 +724,7 @@ General Information)").c_str(), // TODO: The type in OptimiserSettings is size_t but we only accept values up to 2**32-1 // on the CLI and in Standard JSON. We should just switch to uint32_t everywhere. po::value()->value_name("n")->default_value(static_cast(OptimiserSettings{}.expectedExecutionsPerDeployment)), - "Set for how many contract runs to optimize. " + "The number of runs specifies roughly how often each opcode of the deployed code will be executed across the lifetime of the contract. " "Lower values will optimize more for initial deployment cost, higher values will optimize more for high-frequency usage." ) ( From 15318638350bac8edb75311aefa9cd1f44b114d1 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 16 Sep 2021 16:33:28 +0200 Subject: [PATCH 157/232] Split Common.h into Numeric.h. --- libevmasm/Assembly.cpp | 26 +-- libevmasm/AssemblyItem.cpp | 14 +- libevmasm/BlockDeduplicator.h | 2 + libevmasm/ConstantOptimiser.cpp | 8 +- libevmasm/ControlFlowGraph.h | 6 +- libevmasm/ExpressionClasses.cpp | 1 + libevmasm/Inliner.cpp | 2 +- libevmasm/Instruction.h | 3 +- libevmasm/JumpdestRemover.cpp | 2 + libevmasm/KnownState.cpp | 2 +- libevmasm/KnownState.h | 17 +- liblangutil/Scanner.cpp | 1 + liblangutil/SemVerHandler.cpp | 1 + libsmtutil/SolverInterface.h | 1 + libsolidity/analysis/ConstantEvaluator.cpp | 2 + libsolidity/ast/AST.cpp | 2 +- libsolidity/ast/Types.cpp | 4 +- libsolidity/ast/Types.h | 1 + libsolidity/codegen/CompilerContext.h | 1 + libsolidity/codegen/CompilerUtils.cpp | 2 +- libsolidity/codegen/ContractCompiler.cpp | 1 + .../codegen/ir/IRGeneratorForStatements.cpp | 2 +- libsolidity/formal/SMTEncoder.cpp | 2 +- libsolidity/interface/CompilerStack.cpp | 7 +- libsolutil/CMakeLists.txt | 3 +- libsolutil/Common.h | 56 ------ libsolutil/CommonData.h | 90 +-------- libsolutil/CommonIO.h | 17 +- libsolutil/FixedHash.h | 1 + libsolutil/IpfsHash.cpp | 1 + libsolutil/{Common.cpp => Numeric.cpp} | 2 +- libsolutil/Numeric.h | 171 ++++++++++++++++++ libsolutil/StringUtils.h | 6 +- libyul/Object.h | 1 + libyul/Utilities.h | 1 + libyul/backends/evm/AbstractAssembly.h | 1 + libyul/backends/evm/ControlFlowGraph.h | 2 + libyul/backends/evm/EthAssemblyAdapter.h | 2 + libyul/backends/evm/StackHelpers.h | 2 +- libyul/backends/wasm/TextTransform.cpp | 5 +- libyul/backends/wasm/WasmCodeTransform.cpp | 1 + libyul/backends/wasm/WasmCodeTransform.h | 1 + libyul/backends/wasm/WordSizeTransform.cpp | 1 + libyul/optimiser/DeadCodeEliminator.cpp | 1 + libyul/optimiser/ExpressionJoiner.cpp | 2 + libyul/optimiser/KnowledgeBase.h | 1 + libyul/optimiser/Semantics.cpp | 2 + libyul/optimiser/SimplificationRules.cpp | 2 +- libyul/optimiser/StackLimitEvader.cpp | 2 +- libyul/optimiser/StackToMemoryMover.cpp | 2 +- libyul/optimiser/StackToMemoryMover.h | 1 + libyul/optimiser/VarNameCleaner.cpp | 1 + test/ExecutionFramework.cpp | 9 +- test/ExecutionFramework.h | 2 +- test/libsolidity/ErrorCheck.cpp | 1 + test/libsolidity/SemanticTest.cpp | 6 +- test/libsolidity/SolidityOptimizer.cpp | 1 + test/libsolidity/util/BytesUtils.cpp | 5 +- test/libsolidity/util/TestFileParserTests.cpp | 2 +- test/libyul/ObjectCompilerTest.cpp | 4 +- test/tools/ossfuzz/protoToAbiV2.h | 3 +- .../EVMInstructionInterpreter.cpp | 5 +- .../EVMInstructionInterpreter.h | 1 + .../EwasmBuiltinInterpreter.cpp | 5 +- tools/solidityUpgrade/UpgradeChange.cpp | 1 + 65 files changed, 318 insertions(+), 215 deletions(-) rename libsolutil/{Common.cpp => Numeric.cpp} (97%) create mode 100644 libsolutil/Numeric.h diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 6004930a9..4295bd343 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -36,10 +36,12 @@ #include -#include #include #include +#include +#include + using namespace std; using namespace solidity; using namespace solidity::evmasm; @@ -67,7 +69,7 @@ unsigned Assembly::codeSize(unsigned subTagSize) const for (AssemblyItem const& i: m_items) ret += i.bytesRequired(tagSize); - if (util::numberEncodingSize(ret) <= tagSize) + if (numberEncodingSize(ret) <= tagSize) return static_cast(ret); } } @@ -178,7 +180,7 @@ void Assembly::assemblyStream(ostream& _out, string const& _prefix, StringMap co _out << _prefix << "stop" << endl; for (auto const& i: m_data) if (u256(i.first) >= m_subs.size()) - _out << _prefix << "data_" << toHex(u256(i.first)) << " " << toHex(i.second) << endl; + _out << _prefix << "data_" << toHex(u256(i.first)) << " " << util::toHex(i.second) << endl; for (size_t i = 0; i < m_subs.size(); ++i) { @@ -189,7 +191,7 @@ void Assembly::assemblyStream(ostream& _out, string const& _prefix, StringMap co } if (m_auxiliaryData.size() > 0) - _out << endl << _prefix << "auxdata: 0x" << toHex(m_auxiliaryData) << endl; + _out << endl << _prefix << "auxdata: 0x" << util::toHex(m_auxiliaryData) << endl; } string Assembly::assemblyString(StringMap const& _sourceCodes) const @@ -309,7 +311,7 @@ Json::Value Assembly::assemblyJSON(map const& _sourceIndices) collection.append(createJsonValue("PUSH data", sourceIndex, i.location().start, i.location().end, toStringInHex(i.data()))); break; case VerbatimBytecode: - collection.append(createJsonValue("VERBATIM", sourceIndex, i.location().start, i.location().end, toHex(i.verbatimData()))); + collection.append(createJsonValue("VERBATIM", sourceIndex, i.location().start, i.location().end, util::toHex(i.verbatimData()))); break; default: assertThrow(false, InvalidOpcode, ""); @@ -321,7 +323,7 @@ Json::Value Assembly::assemblyJSON(map const& _sourceIndices) Json::Value& data = root[".data"] = Json::objectValue; for (auto const& i: m_data) if (u256(i.first) >= m_subs.size()) - data[toStringInHex((u256)i.first)] = toHex(i.second); + data[toStringInHex((u256)i.first)] = util::toHex(i.second); for (size_t i = 0; i < m_subs.size(); ++i) { @@ -332,7 +334,7 @@ Json::Value Assembly::assemblyJSON(map const& _sourceIndices) } if (m_auxiliaryData.size() > 0) - root[".auxdata"] = toHex(m_auxiliaryData); + root[".auxdata"] = util::toHex(m_auxiliaryData); return root; } @@ -596,14 +598,14 @@ LinkerObject const& Assembly::assemble() const multimap dataRef; multimap subRef; vector sizeRef; ///< Pointers to code locations where the size of the program is inserted - unsigned bytesPerTag = util::numberEncodingSize(bytesRequiredForCode); + unsigned bytesPerTag = numberEncodingSize(bytesRequiredForCode); uint8_t tagPush = static_cast(pushInstruction(bytesPerTag)); unsigned bytesRequiredIncludingData = bytesRequiredForCode + 1 + static_cast(m_auxiliaryData.size()); for (auto const& sub: m_subs) bytesRequiredIncludingData += static_cast(sub->assemble().bytecode.size()); - unsigned bytesPerDataRef = util::numberEncodingSize(bytesRequiredIncludingData); + unsigned bytesPerDataRef = numberEncodingSize(bytesRequiredIncludingData); uint8_t dataRefPush = static_cast(pushInstruction(bytesPerDataRef)); ret.bytecode.reserve(bytesRequiredIncludingData); @@ -620,7 +622,7 @@ LinkerObject const& Assembly::assemble() const break; case Push: { - unsigned b = max(1, util::numberEncodingSize(i.data())); + unsigned b = max(1, numberEncodingSize(i.data())); ret.bytecode.push_back(static_cast(pushInstruction(b))); ret.bytecode.resize(ret.bytecode.size() + b); bytesRef byr(&ret.bytecode.back() + 1 - b, b); @@ -650,7 +652,7 @@ LinkerObject const& Assembly::assemble() const assertThrow(i.data() <= numeric_limits::max(), AssemblyException, ""); auto s = subAssemblyById(static_cast(i.data()))->assemble().bytecode.size(); i.setPushedValue(u256(s)); - unsigned b = max(1, util::numberEncodingSize(s)); + unsigned b = max(1, numberEncodingSize(s)); ret.bytecode.push_back(static_cast(pushInstruction(b))); ret.bytecode.resize(ret.bytecode.size() + b); bytesRef byr(&ret.bytecode.back() + 1 - b, b); @@ -755,7 +757,7 @@ LinkerObject const& Assembly::assemble() const assertThrow(tagId < tagPositions.size(), AssemblyException, "Reference to non-existing tag."); size_t pos = tagPositions[tagId]; assertThrow(pos != numeric_limits::max(), AssemblyException, "Reference to tag without position."); - assertThrow(util::numberEncodingSize(pos) <= bytesPerTag, AssemblyException, "Tag too large for reserved space."); + assertThrow(numberEncodingSize(pos) <= bytesPerTag, AssemblyException, "Tag too large for reserved space."); bytesRef r(ret.bytecode.data() + i.first, bytesPerTag); toBigEndian(pos, r); } diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index 6c10428dc..a34870eda 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -21,11 +21,13 @@ #include #include +#include #include #include #include #include +#include using namespace std; using namespace solidity; @@ -71,7 +73,7 @@ size_t AssemblyItem::bytesRequired(size_t _addressLength) const case Tag: // 1 byte for the JUMPDEST return 1; case Push: - return 1 + max(1, util::numberEncodingSize(data())); + return 1 + max(1, numberEncodingSize(data())); case PushSubSize: case PushProgramSize: return 1 + 4; // worst case: a 16MB program @@ -189,7 +191,7 @@ string AssemblyItem::toAssemblyText(Assembly const& _assembly) const break; } case Push: - text = toHex(util::toCompactBigEndian(data(), 1), util::HexPrefix::Add); + text = toHex(toCompactBigEndian(data(), 1), util::HexPrefix::Add); break; case PushTag: { @@ -207,7 +209,7 @@ string AssemblyItem::toAssemblyText(Assembly const& _assembly) const text = string("tag_") + to_string(static_cast(data())) + ":"; break; case PushData: - text = string("data_") + util::toHex(data()); + text = string("data_") + toHex(data()); break; case PushSub: case PushSubSize: @@ -226,16 +228,16 @@ string AssemblyItem::toAssemblyText(Assembly const& _assembly) const text = string("bytecodeSize"); break; case PushLibraryAddress: - text = string("linkerSymbol(\"") + util::toHex(data()) + string("\")"); + text = string("linkerSymbol(\"") + toHex(data()) + string("\")"); break; case PushDeployTimeAddress: text = string("deployTimeAddress()"); break; case PushImmutable: - text = string("immutable(\"") + toHex(util::toCompactBigEndian(data(), 1), util::HexPrefix::Add) + "\")"; + text = string("immutable(\"") + "0x" + util::toHex(toCompactBigEndian(data(), 1)) + "\")"; break; case AssignImmutable: - text = string("assignImmutable(\"") + toHex(util::toCompactBigEndian(data(), 1), util::HexPrefix::Add) + "\")"; + text = string("assignImmutable(\"") + "0x" + util::toHex(toCompactBigEndian(data(), 1)) + "\")"; break; case UndefinedItem: assertThrow(false, AssemblyException, "Invalid assembly item."); diff --git a/libevmasm/BlockDeduplicator.h b/libevmasm/BlockDeduplicator.h index 9069b70ce..fb83b317e 100644 --- a/libevmasm/BlockDeduplicator.h +++ b/libevmasm/BlockDeduplicator.h @@ -25,6 +25,8 @@ #pragma once #include +#include + #include #include diff --git a/libevmasm/ConstantOptimiser.cpp b/libevmasm/ConstantOptimiser.cpp index 3b582b7f4..6800baef3 100644 --- a/libevmasm/ConstantOptimiser.cpp +++ b/libevmasm/ConstantOptimiser.cpp @@ -133,7 +133,7 @@ bigint LiteralMethod::gasNeeded() const return combineGas( simpleRunGas({Instruction::PUSH1}), // PUSHX plus data - (m_params.isCreation ? GasCosts::txDataNonZeroGas(m_params.evmVersion) : GasCosts::createDataGas) + dataGas(util::toCompactBigEndian(m_value, 1)), + (m_params.isCreation ? GasCosts::txDataNonZeroGas(m_params.evmVersion) : GasCosts::createDataGas) + dataGas(toCompactBigEndian(m_value, 1)), 0 ); } @@ -146,13 +146,13 @@ bigint CodeCopyMethod::gasNeeded() const // Data gas for copy routines: Some bytes are zero, but we ignore them. bytesRequired(copyRoutine()) * (m_params.isCreation ? GasCosts::txDataNonZeroGas(m_params.evmVersion) : GasCosts::createDataGas), // Data gas for data itself - dataGas(util::toBigEndian(m_value)) + dataGas(toBigEndian(m_value)) ); } AssemblyItems CodeCopyMethod::execute(Assembly& _assembly) const { - bytes data = util::toBigEndian(m_value); + bytes data = toBigEndian(m_value); assertThrow(data.size() == 32, OptimizerException, "Invalid number encoding."); AssemblyItems actualCopyRoutine = copyRoutine(); actualCopyRoutine[4] = _assembly.newData(data); @@ -192,7 +192,7 @@ AssemblyItems ComputeMethod::findRepresentation(u256 const& _value) if (_value < 0x10000) // Very small value, not worth computing return AssemblyItems{_value}; - else if (util::numberEncodingSize(~_value) < util::numberEncodingSize(_value)) + else if (numberEncodingSize(~_value) < numberEncodingSize(_value)) // Negated is shorter to represent return findRepresentation(~_value) + AssemblyItems{Instruction::NOT}; else diff --git a/libevmasm/ControlFlowGraph.h b/libevmasm/ControlFlowGraph.h index d27702c2a..ef6dd2f88 100644 --- a/libevmasm/ControlFlowGraph.h +++ b/libevmasm/ControlFlowGraph.h @@ -24,12 +24,14 @@ #pragma once -#include -#include #include #include #include +#include +#include +#include + namespace solidity::evmasm { diff --git a/libevmasm/ExpressionClasses.cpp b/libevmasm/ExpressionClasses.cpp index 8df523842..c17ff9c29 100644 --- a/libevmasm/ExpressionClasses.cpp +++ b/libevmasm/ExpressionClasses.cpp @@ -29,6 +29,7 @@ #include #include +#include using namespace std; using namespace solidity; diff --git a/libevmasm/Inliner.cpp b/libevmasm/Inliner.cpp index d0f1a06f5..8d95bdc3b 100644 --- a/libevmasm/Inliner.cpp +++ b/libevmasm/Inliner.cpp @@ -36,7 +36,7 @@ #include #include - +#include using namespace std; using namespace solidity; diff --git a/libevmasm/Instruction.h b/libevmasm/Instruction.h index 10035b854..ad6bc9796 100644 --- a/libevmasm/Instruction.h +++ b/libevmasm/Instruction.h @@ -25,6 +25,7 @@ #include #include #include +#include #include namespace solidity::evmasm @@ -301,7 +302,7 @@ bool isValidInstruction(Instruction _inst); extern const std::map c_instructions; /// Iterate through EVM code and call a function on each instruction. -void eachInstruction(bytes const& _mem, std::function const& _onInstruction); +void eachInstruction(bytes const& _mem, std::function const& _onInstruction); /// Convert from EVM code to simple EVM assembly language. std::string disassemble(bytes const& _mem, std::string const& _delimiter = " "); diff --git a/libevmasm/JumpdestRemover.cpp b/libevmasm/JumpdestRemover.cpp index c4901700f..2c0c5875e 100644 --- a/libevmasm/JumpdestRemover.cpp +++ b/libevmasm/JumpdestRemover.cpp @@ -24,6 +24,8 @@ #include +#include + using namespace std; using namespace solidity; using namespace solidity::util; diff --git a/libevmasm/KnownState.cpp b/libevmasm/KnownState.cpp index 67445cb75..841affab0 100644 --- a/libevmasm/KnownState.cpp +++ b/libevmasm/KnownState.cpp @@ -415,7 +415,7 @@ KnownState::Id KnownState::applyKeccak256( { bytes data; for (Id a: arguments) - data += util::toBigEndian(*m_expressionClasses->knownConstant(a)); + data += toBigEndian(*m_expressionClasses->knownConstant(a)); data.resize(length); v = m_expressionClasses->find(AssemblyItem(u256(util::keccak256(data)), _location)); } diff --git a/libevmasm/KnownState.h b/libevmasm/KnownState.h index 235b6361b..723170610 100644 --- a/libevmasm/KnownState.h +++ b/libevmasm/KnownState.h @@ -24,14 +24,6 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include - #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wredeclared-class-member" @@ -58,6 +50,15 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include + namespace solidity::langutil { struct SourceLocation; diff --git a/liblangutil/Scanner.cpp b/liblangutil/Scanner.cpp index 87be458fd..fede6d3f8 100644 --- a/liblangutil/Scanner.cpp +++ b/liblangutil/Scanner.cpp @@ -59,6 +59,7 @@ #include #include #include +#include using namespace std; diff --git a/liblangutil/SemVerHandler.cpp b/liblangutil/SemVerHandler.cpp index ede1cd7be..ceb562aed 100644 --- a/liblangutil/SemVerHandler.cpp +++ b/liblangutil/SemVerHandler.cpp @@ -26,6 +26,7 @@ #include #include +#include using namespace std; using namespace solidity; diff --git a/libsmtutil/SolverInterface.h b/libsmtutil/SolverInterface.h index e5cf33ece..87ee78013 100644 --- a/libsmtutil/SolverInterface.h +++ b/libsmtutil/SolverInterface.h @@ -22,6 +22,7 @@ #include #include +#include #include diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp index 965fba5ed..0fc6761f7 100644 --- a/libsolidity/analysis/ConstantEvaluator.cpp +++ b/libsolidity/analysis/ConstantEvaluator.cpp @@ -27,6 +27,8 @@ #include #include +#include + using namespace std; using namespace solidity; using namespace solidity::frontend; diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 3e2376a4f..c36aee5b3 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -274,7 +274,7 @@ uint32_t ContractDefinition::interfaceId() const { uint32_t result{0}; for (auto const& function: interfaceFunctionList(false)) - result ^= util::fromBigEndian(function.first.ref()); + result ^= fromBigEndian(function.first.ref()); return result; } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index ffb8dea4b..3173d2763 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1135,7 +1135,7 @@ IntegerType const* RationalNumberType::integerType() const return nullptr; else return TypeProvider::integer( - max(util::numberEncodingSize(value), 1u) * 8, + max(numberEncodingSize(value), 1u) * 8, negative ? IntegerType::Modifier::Signed : IntegerType::Modifier::Unsigned ); } @@ -1169,7 +1169,7 @@ FixedPointType const* RationalNumberType::fixedPointType() const if (v > u256(-1)) return nullptr; - unsigned totalBits = max(util::numberEncodingSize(v), 1u) * 8; + unsigned totalBits = max(numberEncodingSize(v), 1u) * 8; solAssert(totalBits <= 256, ""); return TypeProvider::fixedPoint( diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index b092628fb..3e6c52467 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -29,6 +29,7 @@ #include #include +#include #include #include #include diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index b36397864..cd71d5a4d 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -46,6 +46,7 @@ #include #include #include +#include namespace solidity::frontend { diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 61eed4abd..b27bd7930 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -40,7 +40,7 @@ using namespace solidity::langutil; using solidity::util::Whiskers; using solidity::util::h256; -using solidity::util::toCompactHexWithPrefix; +using solidity::toCompactHexWithPrefix; unsigned const CompilerUtils::dataStartOffset = 4; size_t const CompilerUtils::freeMemoryPointer = 64; diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 5c51a9bb9..5df08e0cb 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -52,6 +52,7 @@ #include #include +#include using namespace std; using namespace solidity; diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 5a1ec592a..e097c753b 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -266,7 +266,7 @@ void IRGeneratorForStatements::initializeStateVar(VariableDeclaration const& _va _varDecl.immutable() ? IRLValue{*_varDecl.annotation().type, IRLValue::Immutable{&_varDecl}} : IRLValue{*_varDecl.annotation().type, IRLValue::Storage{ - util::toCompactHexWithPrefix(m_context.storageLocationOfStateVariable(_varDecl).first), + toCompactHexWithPrefix(m_context.storageLocationOfStateVariable(_varDecl).first), m_context.storageLocationOfStateVariable(_varDecl).second }}, *_varDecl.value() diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index 7411383de..e011b1756 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -34,7 +34,7 @@ #include - +#include #include using namespace std; diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 4767651de..b023cf46a 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -78,10 +78,11 @@ #include +#include + #include #include - -#include +#include using namespace std; using namespace solidity; @@ -1558,7 +1559,7 @@ public: // The already encoded key-value pairs ret += m_data; // 16-bit big endian length - ret += util::toCompactBigEndian(size, 2); + ret += toCompactBigEndian(size, 2); return ret; } diff --git a/libsolutil/CMakeLists.txt b/libsolutil/CMakeLists.txt index 535b2b90f..e055317be 100644 --- a/libsolutil/CMakeLists.txt +++ b/libsolutil/CMakeLists.txt @@ -2,7 +2,6 @@ set(sources Algorithms.h AnsiColorized.h Assertions.h - Common.cpp Common.h CommonData.cpp CommonData.h @@ -24,6 +23,8 @@ set(sources Keccak256.h LazyInit.h LEB128.h + Numeric.cpp + Numeric.h picosha2.h Result.h SetOnce.h diff --git a/libsolutil/Common.h b/libsolutil/Common.h index 75de12747..5c7814613 100644 --- a/libsolutil/Common.h +++ b/libsolutil/Common.h @@ -45,8 +45,6 @@ #error "Unsupported Boost version. At least 1.65 required." #endif -#include - #include #include #include @@ -61,66 +59,12 @@ using bytes = std::vector; using bytesRef = util::vector_ref; using bytesConstRef = util::vector_ref; -// Numeric types. -using bigint = boost::multiprecision::number>; -using u256 = boost::multiprecision::number>; -using s256 = boost::multiprecision::number>; - // Map types. using StringMap = std::map; // String types. using strings = std::vector; -/// Interprets @a _u as a two's complement signed number and returns the resulting s256. -inline s256 u2s(u256 _u) -{ - static bigint const c_end = bigint(1) << 256; - if (boost::multiprecision::bit_test(_u, 255)) - return s256(-(c_end - _u)); - else - return s256(_u); -} - -/// @returns the two's complement signed representation of the signed number _u. -inline u256 s2u(s256 _u) -{ - static bigint const c_end = bigint(1) << 256; - if (_u >= 0) - return u256(_u); - else - return u256(c_end + _u); -} - -inline u256 exp256(u256 _base, u256 _exponent) -{ - using boost::multiprecision::limb_type; - u256 result = 1; - while (_exponent) - { - if (boost::multiprecision::bit_test(_exponent, 0)) - result *= _base; - _base *= _base; - _exponent >>= 1; - } - return result; -} - -/// Checks whether _mantissa * (X ** _exp) fits into 4096 bits, -/// where X is given indirectly via _log2OfBase = log2(X). -bool fitsPrecisionBaseX(bigint const& _mantissa, double _log2OfBase, uint32_t _exp); - -inline std::ostream& operator<<(std::ostream& os, bytes const& _bytes) -{ - std::ostringstream ss; - ss << std::hex; - std::copy(_bytes.begin(), _bytes.end(), std::ostream_iterator(ss, ",")); - std::string result = ss.str(); - result.pop_back(); - os << "[" + result + "]"; - return os; -} - /// RAII utility class whose destructor calls a given function. class ScopeGuard { diff --git a/libsolutil/CommonData.h b/libsolutil/CommonData.h index 71387558c..0d5a75282 100644 --- a/libsolutil/CommonData.h +++ b/libsolutil/CommonData.h @@ -36,6 +36,8 @@ #include #include #include +#include +#include /// Operators need to stay in the global namespace. @@ -431,94 +433,6 @@ inline bytes asBytes(std::string const& _b) return bytes((uint8_t const*)_b.data(), (uint8_t const*)(_b.data() + _b.size())); } -// Big-endian to/from host endian conversion functions. - -/// Converts a templated integer value to the big-endian byte-stream represented on a templated collection. -/// The size of the collection object will be unchanged. If it is too small, it will not represent the -/// value properly, if too big then the additional elements will be zeroed out. -/// @a Out will typically be either std::string or bytes. -/// @a T will typically by unsigned, u160, u256 or bigint. -template -inline void toBigEndian(T _val, Out& o_out) -{ - static_assert(std::is_same::value || !std::numeric_limits::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift - for (auto i = o_out.size(); i != 0; _val >>= 8, i--) - { - T v = _val & (T)0xff; - o_out[i - 1] = (typename Out::value_type)(uint8_t)v; - } -} - -/// Converts a big-endian byte-stream represented on a templated collection to a templated integer value. -/// @a In will typically be either std::string or bytes. -/// @a T will typically by unsigned, u256 or bigint. -template -inline T fromBigEndian(In const& _bytes) -{ - T ret = (T)0; - for (auto i: _bytes) - ret = (T)((ret << 8) | (uint8_t)(typename std::make_unsigned::type)i); - return ret; -} -inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; } - -/// Convenience function for toBigEndian. -/// @returns a byte array just big enough to represent @a _val. -template -inline bytes toCompactBigEndian(T _val, unsigned _min = 0) -{ - static_assert(std::is_same::value || !std::numeric_limits::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift - unsigned i = 0; - for (T v = _val; v; ++i, v >>= 8) {} - bytes ret(std::max(_min, i), 0); - toBigEndian(_val, ret); - return ret; -} - -/// Convenience function for conversion of a u256 to hex -inline std::string toHex(u256 val, HexPrefix prefix = HexPrefix::DontAdd) -{ - std::string str = toHex(toBigEndian(val)); - return (prefix == HexPrefix::Add) ? "0x" + str : str; -} - -template -inline std::string toCompactHexWithPrefix(T _value) -{ - return toHex(toCompactBigEndian(_value, 1), HexPrefix::Add); -} - -/// Returns decimal representation for small numbers and hex for large numbers. -inline std::string formatNumber(bigint const& _value) -{ - if (_value < 0) - return "-" + formatNumber(-_value); - if (_value > 0x1000000) - return toHex(toCompactBigEndian(_value, 1), HexPrefix::Add); - else - return _value.str(); -} - -inline std::string formatNumber(u256 const& _value) -{ - if (_value > 0x1000000) - return toCompactHexWithPrefix(_value); - else - return _value.str(); -} - - -// Algorithms for string and string-like collections. - -/// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero. -template -inline unsigned numberEncodingSize(T _i) -{ - static_assert(std::is_same::value || !std::numeric_limits::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift - unsigned i = 0; - for (; _i != 0; ++i, _i >>= 8) {} - return i; -} template bool contains(T const& _t, V const& _v) { diff --git a/libsolutil/CommonIO.h b/libsolutil/CommonIO.h index e8b87fe85..ab0000f86 100644 --- a/libsolutil/CommonIO.h +++ b/libsolutil/CommonIO.h @@ -31,7 +31,21 @@ #include #include -namespace solidity::util +namespace solidity +{ + +inline std::ostream& operator<<(std::ostream& os, bytes const& _bytes) +{ + std::ostringstream ss; + ss << std::hex; + std::copy(_bytes.begin(), _bytes.end(), std::ostream_iterator(ss, ",")); + std::string result = ss.str(); + result.pop_back(); + os << "[" + result + "]"; + return os; +} + +namespace util { /// Retrieves and returns the contents of the given file as a std::string. @@ -62,3 +76,4 @@ std::string absolutePath(std::string const& _path, std::string const& _reference std::string sanitizePath(std::string const& _path); } +} diff --git a/libsolutil/FixedHash.h b/libsolutil/FixedHash.h index dffeb7a17..97a80603a 100644 --- a/libsolutil/FixedHash.h +++ b/libsolutil/FixedHash.h @@ -25,6 +25,7 @@ #pragma once #include +#include #include #include diff --git a/libsolutil/IpfsHash.cpp b/libsolutil/IpfsHash.cpp index bf1527261..a34ee035b 100644 --- a/libsolutil/IpfsHash.cpp +++ b/libsolutil/IpfsHash.cpp @@ -21,6 +21,7 @@ #include #include #include +#include using namespace std; using namespace solidity; diff --git a/libsolutil/Common.cpp b/libsolutil/Numeric.cpp similarity index 97% rename from libsolutil/Common.cpp rename to libsolutil/Numeric.cpp index 3f77e5d25..f1d4057e0 100644 --- a/libsolutil/Common.cpp +++ b/libsolutil/Numeric.cpp @@ -16,7 +16,7 @@ */ // SPDX-License-Identifier: GPL-3.0 -#include +#include #include diff --git a/libsolutil/Numeric.h b/libsolutil/Numeric.h new file mode 100644 index 000000000..557f7e2bc --- /dev/null +++ b/libsolutil/Numeric.h @@ -0,0 +1,171 @@ +/* + 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 +/** + * Definition of u256 and similar types and helper functions. + */ + +#pragma once + +#include +#include + +#include +#if (BOOST_VERSION < 106500) +#error "Unsupported Boost version. At least 1.65 required." +#endif + +#include + +#include + +namespace solidity +{ + +// Numeric types. +using bigint = boost::multiprecision::number>; +using u256 = boost::multiprecision::number>; +using s256 = boost::multiprecision::number>; + +/// Interprets @a _u as a two's complement signed number and returns the resulting s256. +inline s256 u2s(u256 _u) +{ + static bigint const c_end = bigint(1) << 256; + if (boost::multiprecision::bit_test(_u, 255)) + return s256(-(c_end - _u)); + else + return s256(_u); +} + +/// @returns the two's complement signed representation of the signed number _u. +inline u256 s2u(s256 _u) +{ + static bigint const c_end = bigint(1) << 256; + if (_u >= 0) + return u256(_u); + else + return u256(c_end + _u); +} + +inline u256 exp256(u256 _base, u256 _exponent) +{ + using boost::multiprecision::limb_type; + u256 result = 1; + while (_exponent) + { + if (boost::multiprecision::bit_test(_exponent, 0)) + result *= _base; + _base *= _base; + _exponent >>= 1; + } + return result; +} + +/// Checks whether _mantissa * (X ** _exp) fits into 4096 bits, +/// where X is given indirectly via _log2OfBase = log2(X). +bool fitsPrecisionBaseX(bigint const& _mantissa, double _log2OfBase, uint32_t _exp); + + +// Big-endian to/from host endian conversion functions. + +/// Converts a templated integer value to the big-endian byte-stream represented on a templated collection. +/// The size of the collection object will be unchanged. If it is too small, it will not represent the +/// value properly, if too big then the additional elements will be zeroed out. +/// @a Out will typically be either std::string or bytes. +/// @a T will typically by unsigned, u160, u256 or bigint. +template +inline void toBigEndian(T _val, Out& o_out) +{ + static_assert(std::is_same::value || !std::numeric_limits::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift + for (auto i = o_out.size(); i != 0; _val >>= 8, i--) + { + T v = _val & (T)0xff; + o_out[i - 1] = (typename Out::value_type)(uint8_t)v; + } +} + +/// Converts a big-endian byte-stream represented on a templated collection to a templated integer value. +/// @a In will typically be either std::string or bytes. +/// @a T will typically by unsigned, u256 or bigint. +template +inline T fromBigEndian(In const& _bytes) +{ + T ret = (T)0; + for (auto i: _bytes) + ret = (T)((ret << 8) | (uint8_t)(typename std::make_unsigned::type)i); + return ret; +} +inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; } + +/// Convenience function for toBigEndian. +/// @returns a byte array just big enough to represent @a _val. +template +inline bytes toCompactBigEndian(T _val, unsigned _min = 0) +{ + static_assert(std::is_same::value || !std::numeric_limits::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift + unsigned i = 0; + for (T v = _val; v; ++i, v >>= 8) {} + bytes ret(std::max(_min, i), 0); + toBigEndian(_val, ret); + return ret; +} + +/// Convenience function for conversion of a u256 to hex +inline std::string toHex(u256 val) +{ + return util::toHex(toBigEndian(val)); +} + +template +inline std::string toCompactHexWithPrefix(T _value) +{ + return "0x" + util::toHex(toCompactBigEndian(_value, 1)); +} + +/// Returns decimal representation for small numbers and hex for large numbers. +inline std::string formatNumber(bigint const& _value) +{ + if (_value < 0) + return "-" + formatNumber(-_value); + if (_value > 0x1000000) + return "0x" + util::toHex(toCompactBigEndian(_value, 1)); + else + return _value.str(); +} + +inline std::string formatNumber(u256 const& _value) +{ + if (_value > 0x1000000) + return toCompactHexWithPrefix(_value); + else + return _value.str(); +} + + +// Algorithms for string and string-like collections. + +/// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero. +template +inline unsigned numberEncodingSize(T _i) +{ + static_assert(std::is_same::value || !std::numeric_limits::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift + unsigned i = 0; + for (; _i != 0; ++i, _i >>= 8) {} + return i; +} + +} diff --git a/libsolutil/StringUtils.h b/libsolutil/StringUtils.h index 646cda505..09aa30be9 100644 --- a/libsolutil/StringUtils.h +++ b/libsolutil/StringUtils.h @@ -24,11 +24,13 @@ #pragma once +#include +#include + +#include #include #include -#include - namespace solidity::util { diff --git a/libyul/Object.h b/libyul/Object.h index 480b7e553..1b08821ce 100644 --- a/libyul/Object.h +++ b/libyul/Object.h @@ -30,6 +30,7 @@ #include #include +#include namespace solidity::yul { diff --git a/libyul/Utilities.h b/libyul/Utilities.h index b9077eeae..e4d496cd4 100644 --- a/libyul/Utilities.h +++ b/libyul/Utilities.h @@ -22,6 +22,7 @@ #pragma once #include +#include #include namespace solidity::yul diff --git a/libyul/backends/evm/AbstractAssembly.h b/libyul/backends/evm/AbstractAssembly.h index 60a745bee..66d5333e2 100644 --- a/libyul/backends/evm/AbstractAssembly.h +++ b/libyul/backends/evm/AbstractAssembly.h @@ -27,6 +27,7 @@ #include #include +#include #include #include diff --git a/libyul/backends/evm/ControlFlowGraph.h b/libyul/backends/evm/ControlFlowGraph.h index 0099b9924..6196697fc 100644 --- a/libyul/backends/evm/ControlFlowGraph.h +++ b/libyul/backends/evm/ControlFlowGraph.h @@ -27,6 +27,8 @@ #include #include +#include + #include #include #include diff --git a/libyul/backends/evm/EthAssemblyAdapter.h b/libyul/backends/evm/EthAssemblyAdapter.h index e47b79956..c11b375f6 100644 --- a/libyul/backends/evm/EthAssemblyAdapter.h +++ b/libyul/backends/evm/EthAssemblyAdapter.h @@ -24,7 +24,9 @@ #include #include #include + #include +#include namespace solidity::evmasm { diff --git a/libyul/backends/evm/StackHelpers.h b/libyul/backends/evm/StackHelpers.h index 302c6c029..38d0ddf4b 100644 --- a/libyul/backends/evm/StackHelpers.h +++ b/libyul/backends/evm/StackHelpers.h @@ -39,7 +39,7 @@ inline std::string stackSlotToString(StackSlot const& _slot) [](FunctionCallReturnLabelSlot const& _ret) -> std::string { return "RET[" + _ret.call.get().functionName.name.str() + "]"; }, [](FunctionReturnLabelSlot const&) -> std::string { return "RET"; }, [](VariableSlot const& _var) { return _var.variable.get().name.str(); }, - [](LiteralSlot const& _lit) { return util::toCompactHexWithPrefix(_lit.value); }, + [](LiteralSlot const& _lit) { return toCompactHexWithPrefix(_lit.value); }, [](TemporarySlot const& _tmp) -> std::string { return "TMP[" + _tmp.call.get().functionName.name.str() + ", " + std::to_string(_tmp.index) + "]"; }, [](JunkSlot const&) -> std::string { return "JUNK"; } }, _slot); diff --git a/libyul/backends/wasm/TextTransform.cpp b/libyul/backends/wasm/TextTransform.cpp index b8cae94b7..9880f5ee5 100644 --- a/libyul/backends/wasm/TextTransform.cpp +++ b/libyul/backends/wasm/TextTransform.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -54,7 +55,7 @@ string TextTransform::run(wasm::Module const& _module) " ;; (@custom \"" + name + "\" \"" + - toHex(BinaryTransform::run(module)) + + util::toHex(BinaryTransform::run(module)) + "\")\n"; for (auto const& [name, data]: _module.customSections) ret += @@ -62,7 +63,7 @@ string TextTransform::run(wasm::Module const& _module) " ;; (@custom \"" + name + "\" \"" + - toHex(data) + + util::toHex(data) + "\")\n"; for (wasm::FunctionImport const& imp: _module.imports) { diff --git a/libyul/backends/wasm/WasmCodeTransform.cpp b/libyul/backends/wasm/WasmCodeTransform.cpp index f1254875a..32c774533 100644 --- a/libyul/backends/wasm/WasmCodeTransform.cpp +++ b/libyul/backends/wasm/WasmCodeTransform.cpp @@ -31,6 +31,7 @@ #include #include +#include using namespace std; using namespace solidity; diff --git a/libyul/backends/wasm/WasmCodeTransform.h b/libyul/backends/wasm/WasmCodeTransform.h index 98b761e8d..1026f17c6 100644 --- a/libyul/backends/wasm/WasmCodeTransform.h +++ b/libyul/backends/wasm/WasmCodeTransform.h @@ -28,6 +28,7 @@ #include #include +#include #include #include diff --git a/libyul/backends/wasm/WordSizeTransform.cpp b/libyul/backends/wasm/WordSizeTransform.cpp index e796b1f8f..ad723717b 100644 --- a/libyul/backends/wasm/WordSizeTransform.cpp +++ b/libyul/backends/wasm/WordSizeTransform.cpp @@ -27,6 +27,7 @@ #include #include #include +#include using namespace std; using namespace solidity; diff --git a/libyul/optimiser/DeadCodeEliminator.cpp b/libyul/optimiser/DeadCodeEliminator.cpp index d8162397c..6a279487f 100644 --- a/libyul/optimiser/DeadCodeEliminator.cpp +++ b/libyul/optimiser/DeadCodeEliminator.cpp @@ -27,6 +27,7 @@ #include #include +#include using namespace std; using namespace solidity; diff --git a/libyul/optimiser/ExpressionJoiner.cpp b/libyul/optimiser/ExpressionJoiner.cpp index 2f3441fa1..9d1df8694 100644 --- a/libyul/optimiser/ExpressionJoiner.cpp +++ b/libyul/optimiser/ExpressionJoiner.cpp @@ -31,6 +31,8 @@ #include +#include + using namespace std; using namespace solidity; using namespace solidity::yul; diff --git a/libyul/optimiser/KnowledgeBase.h b/libyul/optimiser/KnowledgeBase.h index 91dbaa58e..75e060eb1 100644 --- a/libyul/optimiser/KnowledgeBase.h +++ b/libyul/optimiser/KnowledgeBase.h @@ -25,6 +25,7 @@ #include #include +#include #include diff --git a/libyul/optimiser/Semantics.cpp b/libyul/optimiser/Semantics.cpp index d51af2de2..bdd08710e 100644 --- a/libyul/optimiser/Semantics.cpp +++ b/libyul/optimiser/Semantics.cpp @@ -31,6 +31,8 @@ #include #include +#include + using namespace std; using namespace solidity; using namespace solidity::yul; diff --git a/libyul/optimiser/SimplificationRules.cpp b/libyul/optimiser/SimplificationRules.cpp index 4a0e0668c..55c30d2f2 100644 --- a/libyul/optimiser/SimplificationRules.cpp +++ b/libyul/optimiser/SimplificationRules.cpp @@ -241,7 +241,7 @@ Expression Pattern::toExpression(shared_ptr const& _debugData) if (m_kind == PatternKind::Constant) { assertThrow(m_data, OptimizerException, "No match group and no constant value given."); - return Literal{_debugData, LiteralKind::Number, YulString{util::formatNumber(*m_data)}, {}}; + return Literal{_debugData, LiteralKind::Number, YulString{formatNumber(*m_data)}, {}}; } else if (m_kind == PatternKind::Operation) { diff --git a/libyul/optimiser/StackLimitEvader.cpp b/libyul/optimiser/StackLimitEvader.cpp index 8a632af53..1c7903b1f 100644 --- a/libyul/optimiser/StackLimitEvader.cpp +++ b/libyul/optimiser/StackLimitEvader.cpp @@ -163,6 +163,6 @@ void StackLimitEvader::run( { Literal* literal = std::get_if(&memoryGuardCall->arguments.front()); yulAssert(literal && literal->kind == LiteralKind::Number, ""); - literal->value = YulString{util::toCompactHexWithPrefix(reservedMemory)}; + literal->value = YulString{toCompactHexWithPrefix(reservedMemory)}; } } diff --git a/libyul/optimiser/StackToMemoryMover.cpp b/libyul/optimiser/StackToMemoryMover.cpp index 87976e116..dcc5f45f6 100644 --- a/libyul/optimiser/StackToMemoryMover.cpp +++ b/libyul/optimiser/StackToMemoryMover.cpp @@ -315,7 +315,7 @@ optional StackToMemoryMover::VariableMemoryOffsetTracker::operator()( { uint64_t slot = m_memorySlots.at(_variable); yulAssert(slot < m_numRequiredSlots, ""); - return YulString{util::toCompactHexWithPrefix(m_reservedMemory + 32 * (m_numRequiredSlots - slot - 1))}; + return YulString{toCompactHexWithPrefix(m_reservedMemory + 32 * (m_numRequiredSlots - slot - 1))}; } else return nullopt; diff --git a/libyul/optimiser/StackToMemoryMover.h b/libyul/optimiser/StackToMemoryMover.h index 0f92a4d56..64c661c0b 100644 --- a/libyul/optimiser/StackToMemoryMover.h +++ b/libyul/optimiser/StackToMemoryMover.h @@ -26,6 +26,7 @@ #include #include +#include #include diff --git a/libyul/optimiser/VarNameCleaner.cpp b/libyul/optimiser/VarNameCleaner.cpp index 55fc71fd6..09093f5aa 100644 --- a/libyul/optimiser/VarNameCleaner.cpp +++ b/libyul/optimiser/VarNameCleaner.cpp @@ -27,6 +27,7 @@ #include #include #include +#include using namespace std; using namespace solidity::yul; diff --git a/test/ExecutionFramework.cpp b/test/ExecutionFramework.cpp index b65a94f52..c153cd471 100644 --- a/test/ExecutionFramework.cpp +++ b/test/ExecutionFramework.cpp @@ -40,6 +40,7 @@ #include #include +#include using namespace std; using namespace solidity; @@ -102,8 +103,8 @@ std::pair ExecutionFramework::compareAndCreateMessage( std::string message = "Invalid encoded data\n" " Result Expectation\n"; - auto resultHex = boost::replace_all_copy(toHex(_result), "0", "."); - auto expectedHex = boost::replace_all_copy(toHex(_expectation), "0", "."); + auto resultHex = boost::replace_all_copy(util::toHex(_result), "0", "."); + auto expectedHex = boost::replace_all_copy(util::toHex(_expectation), "0", "."); for (size_t i = 0; i < std::max(resultHex.size(), expectedHex.size()); i += 0x40) { std::string result{i >= resultHex.size() ? string{} : resultHex.substr(i, 0x40)}; @@ -163,7 +164,7 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256 cout << "CALL " << m_sender.hex() << " -> " << m_contractAddress.hex() << ":" << endl; if (_value > 0) cout << " value: " << _value << endl; - cout << " in: " << toHex(_data) << endl; + cout << " in: " << util::toHex(_data) << endl; } evmc_message message = {}; message.input_data = _data.data(); @@ -194,7 +195,7 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256 if (m_showMessages) { - cout << " out: " << toHex(m_output) << endl; + cout << " out: " << util::toHex(m_output) << endl; cout << " result: " << static_cast(result.status_code) << endl; cout << " gas used: " << m_gasUsed.str() << endl; } diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h index 7a10d72e3..0ee0214d4 100644 --- a/test/ExecutionFramework.h +++ b/test/ExecutionFramework.h @@ -169,7 +169,7 @@ public: static bytes encode(size_t _value) { return encode(u256(_value)); } static bytes encode(char const* _value) { return encode(std::string(_value)); } static bytes encode(uint8_t _value) { return bytes(31, 0) + bytes{_value}; } - static bytes encode(u256 const& _value) { return util::toBigEndian(_value); } + static bytes encode(u256 const& _value) { return toBigEndian(_value); } /// @returns the fixed-point encoding of a rational number with a given /// number of fractional bits. static bytes encode(std::pair const& _valueAndPrecision) diff --git a/test/libsolidity/ErrorCheck.cpp b/test/libsolidity/ErrorCheck.cpp index 42b527e5b..418d7cc99 100644 --- a/test/libsolidity/ErrorCheck.cpp +++ b/test/libsolidity/ErrorCheck.cpp @@ -25,6 +25,7 @@ #include #include +#include using namespace std; using namespace solidity; diff --git a/test/libsolidity/SemanticTest.cpp b/test/libsolidity/SemanticTest.cpp index 50d7dfcc0..56e1b1a8b 100644 --- a/test/libsolidity/SemanticTest.cpp +++ b/test/libsolidity/SemanticTest.cpp @@ -131,7 +131,7 @@ map SemanticTest::makeBuiltins() "isoltest_builtin_test", [](FunctionCall const&) -> optional { - return util::toBigEndian(u256(0x1234)); + return toBigEndian(u256(0x1234)); } }, { @@ -139,7 +139,7 @@ map SemanticTest::makeBuiltins() [](FunctionCall const& _call) -> optional { if (_call.arguments.parameters.empty()) - return util::toBigEndian(0); + return toBigEndian(0); else return _call.arguments.rawBytes(); } @@ -154,7 +154,7 @@ map SemanticTest::makeBuiltins() address = h160(_call.arguments.parameters.at(0).rawString); else address = m_contractAddress; - return util::toBigEndian(balanceAt(address)); + return toBigEndian(balanceAt(address)); } }, { diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index b9accf7bb..9c9d9a7e6 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -32,6 +32,7 @@ #include #include #include +#include using namespace std; using namespace solidity::util; diff --git a/test/libsolidity/util/BytesUtils.cpp b/test/libsolidity/util/BytesUtils.cpp index 25638764e..6745bd1df 100644 --- a/test/libsolidity/util/BytesUtils.cpp +++ b/test/libsolidity/util/BytesUtils.cpp @@ -21,6 +21,7 @@ #include #include +#include #include @@ -108,7 +109,7 @@ bytes BytesUtils::convertFixedPoint(string const& _literal, size_t& o_fractional u256 value(valueInteger); if (negative) value = s2u(-u2s(value)); - return util::toBigEndian(value); + return toBigEndian(value); } catch (std::exception const&) { @@ -193,7 +194,7 @@ string BytesUtils::formatHexString(bytes const& _bytes) { stringstream os; - os << "hex\"" << toHex(_bytes) << "\""; + os << "hex\"" << util::toHex(_bytes) << "\""; return os.str(); } diff --git a/test/libsolidity/util/TestFileParserTests.cpp b/test/libsolidity/util/TestFileParserTests.cpp index df75dcad1..6f9aec64d 100644 --- a/test/libsolidity/util/TestFileParserTests.cpp +++ b/test/libsolidity/util/TestFileParserTests.cpp @@ -963,7 +963,7 @@ BOOST_AUTO_TEST_CASE(call_effects) std::map builtins; builtins["builtin_returning_call_effect"] = [](FunctionCall const&) -> std::optional { - return util::toBigEndian(u256(0x1234)); + return toBigEndian(u256(0x1234)); }; builtins["builtin_returning_call_effect_no_ret"] = [](FunctionCall const&) -> std::optional { diff --git a/test/libyul/ObjectCompilerTest.cpp b/test/libyul/ObjectCompilerTest.cpp index 2c3560726..37b1688a9 100644 --- a/test/libyul/ObjectCompilerTest.cpp +++ b/test/libyul/ObjectCompilerTest.cpp @@ -81,7 +81,7 @@ TestCase::TestResult ObjectCompilerTest::run(ostream& _stream, string const& _li solAssert(obj.bytecode, ""); m_obtainedResult = "Text:\n" + obj.assembly + "\n"; - m_obtainedResult += "Binary:\n" + toHex(obj.bytecode->bytecode) + "\n"; + m_obtainedResult += "Binary:\n" + util::toHex(obj.bytecode->bytecode) + "\n"; } else { @@ -95,7 +95,7 @@ TestCase::TestResult ObjectCompilerTest::run(ostream& _stream, string const& _li else m_obtainedResult += "Bytecode: " + - toHex(obj.bytecode->bytecode) + + util::toHex(obj.bytecode->bytecode) + "\nOpcodes: " + boost::trim_copy(evmasm::disassemble(obj.bytecode->bytecode)) + "\nSourceMappings:" + diff --git a/test/tools/ossfuzz/protoToAbiV2.h b/test/tools/ossfuzz/protoToAbiV2.h index a2be558e8..83246ac53 100644 --- a/test/tools/ossfuzz/protoToAbiV2.h +++ b/test/tools/ossfuzz/protoToAbiV2.h @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -505,7 +506,7 @@ public: // Note: Don't change HexPrefix::Add. See comment in fixedByteValueAsString(). static std::string maskUnsignedIntToHex(unsigned _counter, unsigned _numMaskNibbles) { - return toHex(maskUnsignedInt(_counter, _numMaskNibbles), util::HexPrefix::Add); + return "0x" + toHex(maskUnsignedInt(_counter, _numMaskNibbles)); } /// Dynamically sized arrays can have a length of at least zero diff --git a/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp b/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp index 476c95357..1e030d098 100644 --- a/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp +++ b/test/tools/yulInterpreter/EVMInstructionInterpreter.cpp @@ -29,6 +29,9 @@ #include #include +#include + +#include using namespace std; using namespace solidity; @@ -511,7 +514,7 @@ void EVMInstructionInterpreter::logTrace(std::string const& _pseudoInstruction, { string message = _pseudoInstruction + "("; for (size_t i = 0; i < _arguments.size(); ++i) - message += (i > 0 ? ", " : "") + util::formatNumber(_arguments[i]); + message += (i > 0 ? ", " : "") + formatNumber(_arguments[i]); message += ")"; if (!_data.empty()) message += " [" + util::toHex(_data) + "]"; diff --git a/test/tools/yulInterpreter/EVMInstructionInterpreter.h b/test/tools/yulInterpreter/EVMInstructionInterpreter.h index 25f9f2519..2da5b45e5 100644 --- a/test/tools/yulInterpreter/EVMInstructionInterpreter.h +++ b/test/tools/yulInterpreter/EVMInstructionInterpreter.h @@ -24,6 +24,7 @@ #include #include +#include #include diff --git a/test/tools/yulInterpreter/EwasmBuiltinInterpreter.cpp b/test/tools/yulInterpreter/EwasmBuiltinInterpreter.cpp index 776c1c305..25349f5d1 100644 --- a/test/tools/yulInterpreter/EwasmBuiltinInterpreter.cpp +++ b/test/tools/yulInterpreter/EwasmBuiltinInterpreter.cpp @@ -29,6 +29,9 @@ #include #include +#include + +#include using namespace std; using namespace solidity; @@ -601,7 +604,7 @@ void EwasmBuiltinInterpreter::logTrace(std::string const& _pseudoInstruction, st { string message = _pseudoInstruction + "("; for (size_t i = 0; i < _arguments.size(); ++i) - message += (i > 0 ? ", " : "") + util::formatNumber(_arguments[i]); + message += (i > 0 ? ", " : "") + formatNumber(_arguments[i]); message += ")"; if (!_data.empty()) message += " [" + util::toHex(_data) + "]"; diff --git a/tools/solidityUpgrade/UpgradeChange.cpp b/tools/solidityUpgrade/UpgradeChange.cpp index 2976efe5d..ce1627d0a 100644 --- a/tools/solidityUpgrade/UpgradeChange.cpp +++ b/tools/solidityUpgrade/UpgradeChange.cpp @@ -19,6 +19,7 @@ #include #include +#include using namespace std; using namespace solidity; From 9326b2eaeb70588a62f02c9e0de277550b048693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 22 Sep 2021 11:19:15 +0200 Subject: [PATCH 158/232] ASTImportTest.sh: Print an error when AST reimport fails instead of just exiting silently --- scripts/ASTImportTest.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scripts/ASTImportTest.sh b/scripts/ASTImportTest.sh index 212e547f6..ba8f33d3c 100755 --- a/scripts/ASTImportTest.sh +++ b/scripts/ASTImportTest.sh @@ -42,15 +42,24 @@ function testImportExportEquivalence { if $SOLC "$nth_input_file" "${all_input_files[@]}" > /dev/null 2>&1 then + ! [[ -e stderr.txt ]] || { echo "stderr.txt already exists. Refusing to overwrite."; exit 1; } + # save exported json as expected result (silently) $SOLC --combined-json ast,compact-format --pretty-json "$nth_input_file" "${all_input_files[@]}" > expected.json 2> /dev/null # import it, and export it again as obtained result (silently) - if ! $SOLC --import-ast --combined-json ast,compact-format --pretty-json expected.json > obtained.json 2> /dev/null + if ! $SOLC --import-ast --combined-json ast,compact-format --pretty-json expected.json > obtained.json 2> stderr.txt then # For investigating, use exit 1 here so the script stops at the # first failing test # exit 1 FAILED=$((FAILED + 1)) + echo -e "ERROR: AST reimport failed for input file $nth_input_file" + echo + echo "Compiler stderr:" + cat ./stderr.txt + echo + echo "Compiler stdout:" + cat ./obtained.json return 1 fi DIFF="$(diff expected.json obtained.json)" @@ -72,6 +81,7 @@ function testImportExportEquivalence { fi TESTED=$((TESTED + 1)) rm expected.json obtained.json + rm -f stderr.txt else # echo "contract $solfile could not be compiled " UNCOMPILABLE=$((UNCOMPILABLE + 1)) From caccd0a3e041d5bea9182c91f030647e3b9107c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 24 Sep 2021 14:17:48 +0200 Subject: [PATCH 159/232] Always refer to the latest version of Boost in URLs --- docs/contributing.rst | 13 +++++++------ libevmasm/RuleList.h | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index 1d621d4a9..6b2db9546 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -100,12 +100,13 @@ Running the Tests ----------------- Solidity includes different types of tests, most of them bundled into the -`Boost C++ Test Framework `_ application ``soltest``. +`Boost C++ Test Framework `_ application ``soltest``. Running ``build/test/soltest`` or its wrapper ``scripts/soltest.sh`` is sufficient for most changes. The ``./scripts/tests.sh`` script executes most Solidity tests automatically, -including those bundled into the `Boost C++ Test Framework `_ application ``soltest`` (or its wrapper ``scripts/soltest.sh``), -as well as command line tests and compilation tests. +including those bundled into the `Boost C++ Test Framework `_ +application ``soltest`` (or its wrapper ``scripts/soltest.sh``), as well as command line tests and +compilation tests. The test system automatically tries to discover the location of the ``evmone`` library starting from the current directory. The required file is called ``libevmone.so`` on Linux systems, @@ -137,9 +138,9 @@ Or, for example, to run all the tests for the yul disambiguator: See especially: -- `show_progress (-p) `_ to show test completion, -- `run_test (-t) `_ to run specific tests cases, and -- `report-level (-r) `_ give a more detailed report. +- `show_progress (-p) `_ to show test completion, +- `run_test (-t) `_ to run specific tests cases, and +- `report-level (-r) `_ give a more detailed report. .. note :: diff --git a/libevmasm/RuleList.h b/libevmasm/RuleList.h index fda7f0c7f..ec0970e65 100644 --- a/libevmasm/RuleList.h +++ b/libevmasm/RuleList.h @@ -51,7 +51,7 @@ template S modWorkaround(S const& _a, S const& _b) } // This works around a bug fixed with Boost 1.64. -// https://www.boost.org/doc/libs/1_68_0/libs/multiprecision/doc/html/boost_multiprecision/map/hist.html#boost_multiprecision.map.hist.multiprecision_2_3_1_boost_1_64 +// https://www.boost.org/doc/libs/release/libs/multiprecision/doc/html/boost_multiprecision/map/hist.html#boost_multiprecision.map.hist.multiprecision_2_3_1_boost_1_64 template S shlWorkaround(S const& _x, unsigned _amount) { return u256((bigint(_x) << _amount) & u256(-1)); From 67041fb37f1d12316730208e876d3a3b6fd242ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 24 Sep 2021 14:37:51 +0200 Subject: [PATCH 160/232] Put versions of packages downloaded by scripts in variables to reduce duplication --- .circleci/osx_install_dependencies.sh | 35 +++++++++++++---------- scripts/create_source_tarball.sh | 4 ++- scripts/install_obsolete_jsoncpp_1_7_4.sh | 8 ++++-- 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/.circleci/osx_install_dependencies.sh b/.circleci/osx_install_dependencies.sh index 0505aa6db..6b8b990c3 100755 --- a/.circleci/osx_install_dependencies.sh +++ b/.circleci/osx_install_dependencies.sh @@ -48,23 +48,28 @@ then ./scripts/install_obsolete_jsoncpp_1_7_4.sh # z3 - z3_version="z3-4.8.12" - osx_version="osx-10.15.7" - wget "https://github.com/Z3Prover/z3/releases/download/$z3_version/$z3_version-x64-$osx_version.zip" - unzip "$z3_version-x64-$osx_version.zip" - rm -f "$z3_version-x64-$osx_version.zip" - cp "$z3_version-x64-$osx_version/bin/libz3.a" /usr/local/lib - cp "$z3_version-x64-$osx_version/bin/z3" /usr/local/bin - cp "$z3_version-x64-$osx_version"/include/* /usr/local/include - rm -rf "$z3_version-x64-$osx_version" + z3_version="4.8.12" + z3_dir="z3-${z3_version}-x64-osx-10.15.7" + z3_package="${z3_dir}.zip" + wget "https://github.com/Z3Prover/z3/releases/download/z3-${z3_version}/${z3_package}" + unzip "$z3_package" + rm -f "$z3_package" + cp "${z3_dir}/bin/libz3.a" /usr/local/lib + cp "${z3_dir}/bin/z3" /usr/local/bin + cp "${z3_dir}/include/"* /usr/local/include + rm -rf "$z3_dir" # evmone - wget https://github.com/ethereum/evmone/releases/download/v0.8.0/evmone-0.8.0-darwin-x86_64.tar.gz - tar xzpf evmone-0.8.0-darwin-x86_64.tar.gz -C /usr/local - rm -f evmone-0.8.0-darwin-x86_64.tar.gz + evmone_version="0.8.0" + evmone_package="evmone-${evmone_version}-darwin-x86_64.tar.gz" + wget "https://github.com/ethereum/evmone/releases/download/v${evmone_version}/${evmone_package}" + tar xzpf "$evmone_package" -C /usr/local + rm -f "$evmone_package" # hera - wget https://github.com/ewasm/hera/releases/download/v0.5.0/hera-0.5.0-darwin-x86_64.tar.gz - tar xzpf hera-0.5.0-darwin-x86_64.tar.gz -C /usr/local - rm -f hera-0.5.0-darwin-x86_64.tar.gz + hera_version="0.5.0" + hera_package="hera-${hera_version}-darwin-x86_64.tar.gz" + wget "https://github.com/ewasm/hera/releases/download/v${hera_version}/${hera_package}" + tar xzpf "$hera_package" -C /usr/local + rm -f "$hera_package" fi diff --git a/scripts/create_source_tarball.sh b/scripts/create_source_tarball.sh index df5c2967e..3ba18cf87 100755 --- a/scripts/create_source_tarball.sh +++ b/scripts/create_source_tarball.sh @@ -31,7 +31,9 @@ REPO_ROOT="$(dirname "$0")"/.. fi # Add dependencies mkdir -p "$SOLDIR/deps/downloads/" 2>/dev/null || true - wget -O "$SOLDIR/deps/downloads/jsoncpp-1.9.3.tar.gz" https://github.com/open-source-parsers/jsoncpp/archive/1.9.3.tar.gz + jsoncpp_version="1.9.3" + jsoncpp_package_path="$SOLDIR/deps/downloads/jsoncpp-${jsoncpp_version}.tar.gz" + wget -O "$jsoncpp_package_path" "https://github.com/open-source-parsers/jsoncpp/archive/${jsoncpp_version}.tar.gz" mkdir -p "$REPO_ROOT/upload" tar --owner 0 --group 0 -czf "$REPO_ROOT/upload/solidity_$versionstring.tar.gz" -C "$TEMPDIR" "solidity_$versionstring" rm -r "$TEMPDIR" diff --git a/scripts/install_obsolete_jsoncpp_1_7_4.sh b/scripts/install_obsolete_jsoncpp_1_7_4.sh index eb617e651..f4ac76006 100755 --- a/scripts/install_obsolete_jsoncpp_1_7_4.sh +++ b/scripts/install_obsolete_jsoncpp_1_7_4.sh @@ -4,9 +4,11 @@ set -eu TEMPDIR=$(mktemp -d) ( cd "$TEMPDIR" - wget https://github.com/open-source-parsers/jsoncpp/archive/1.7.4.tar.gz - tar xvzf "1.7.4.tar.gz" - cd "jsoncpp-1.7.4" + jsoncpp_version="1.7.4" + jsoncpp_package="jsoncpp-${jsoncpp_version}.tar.gz" + wget -O "$jsoncpp_package" https://github.com/open-source-parsers/jsoncpp/archive/${jsoncpp_version}.tar.gz + tar xvzf "$jsoncpp_package" + cd "jsoncpp-${jsoncpp_version}" mkdir -p build cd build cmake -DARCHIVE_INSTALL_DIR=. -G "Unix Makefiles" .. From 59e8bbb1d7f2a632ca88bdc0dadc2554b5816bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 24 Sep 2021 14:38:29 +0200 Subject: [PATCH 161/232] Do not use --force with rm if not needed --- .circleci/osx_install_dependencies.sh | 8 ++++---- scripts/install_obsolete_jsoncpp_1_7_4.sh | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.circleci/osx_install_dependencies.sh b/.circleci/osx_install_dependencies.sh index 6b8b990c3..6a4e29807 100755 --- a/.circleci/osx_install_dependencies.sh +++ b/.circleci/osx_install_dependencies.sh @@ -53,23 +53,23 @@ then z3_package="${z3_dir}.zip" wget "https://github.com/Z3Prover/z3/releases/download/z3-${z3_version}/${z3_package}" unzip "$z3_package" - rm -f "$z3_package" + rm "$z3_package" cp "${z3_dir}/bin/libz3.a" /usr/local/lib cp "${z3_dir}/bin/z3" /usr/local/bin cp "${z3_dir}/include/"* /usr/local/include - rm -rf "$z3_dir" + rm -r "$z3_dir" # evmone evmone_version="0.8.0" evmone_package="evmone-${evmone_version}-darwin-x86_64.tar.gz" wget "https://github.com/ethereum/evmone/releases/download/v${evmone_version}/${evmone_package}" tar xzpf "$evmone_package" -C /usr/local - rm -f "$evmone_package" + rm "$evmone_package" # hera hera_version="0.5.0" hera_package="hera-${hera_version}-darwin-x86_64.tar.gz" wget "https://github.com/ewasm/hera/releases/download/v${hera_version}/${hera_package}" tar xzpf "$hera_package" -C /usr/local - rm -f "$hera_package" + rm "$hera_package" fi diff --git a/scripts/install_obsolete_jsoncpp_1_7_4.sh b/scripts/install_obsolete_jsoncpp_1_7_4.sh index f4ac76006..e184e3059 100755 --- a/scripts/install_obsolete_jsoncpp_1_7_4.sh +++ b/scripts/install_obsolete_jsoncpp_1_7_4.sh @@ -15,4 +15,4 @@ TEMPDIR=$(mktemp -d) make make install ) -rm -rf "$TEMPDIR" +rm -r "$TEMPDIR" From 091e15d6da03bf25da5e82626fb6621f4ed98354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 24 Sep 2021 14:38:52 +0200 Subject: [PATCH 162/232] Verify checksums of packages downloaded by scripts --- .circleci/osx_install_dependencies.sh | 18 ++++++++++++++++++ scripts/create_source_tarball.sh | 6 ++++++ scripts/install_deps.ps1 | 6 ++++++ scripts/install_obsolete_jsoncpp_1_7_4.sh | 6 ++++++ 4 files changed, 36 insertions(+) diff --git a/.circleci/osx_install_dependencies.sh b/.circleci/osx_install_dependencies.sh index 6a4e29807..b2f4b4e10 100755 --- a/.circleci/osx_install_dependencies.sh +++ b/.circleci/osx_install_dependencies.sh @@ -35,6 +35,21 @@ set -eu +function validate_checksum { + local package="$1" + local expected_checksum="$2" + + local actual_checksum + actual_checksum=$(sha256sum "$package") + if [[ $actual_checksum != "${expected_checksum} ${package}" ]] + then + >&2 echo "ERROR: Wrong checksum for package $package." + >&2 echo "Actual: $actual_checksum" + >&2 echo "Expected: $expected_checksum" + exit 1 + fi +} + if [ ! -f /usr/local/lib/libz3.a ] # if this file does not exists (cache was not restored), rebuild dependencies then git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow @@ -52,6 +67,7 @@ then z3_dir="z3-${z3_version}-x64-osx-10.15.7" z3_package="${z3_dir}.zip" wget "https://github.com/Z3Prover/z3/releases/download/z3-${z3_version}/${z3_package}" + validate_checksum "$z3_package" a1f6ef3c99456147c4d3f2652dc6bc90951c4ab3fe7741a255eb794f0ab8938c unzip "$z3_package" rm "$z3_package" cp "${z3_dir}/bin/libz3.a" /usr/local/lib @@ -63,6 +79,7 @@ then evmone_version="0.8.0" evmone_package="evmone-${evmone_version}-darwin-x86_64.tar.gz" wget "https://github.com/ethereum/evmone/releases/download/v${evmone_version}/${evmone_package}" + validate_checksum "$evmone_package" e8efef478822f0ed6d0493e89004181e895893f93963152a2a81589acc3a0828 tar xzpf "$evmone_package" -C /usr/local rm "$evmone_package" @@ -70,6 +87,7 @@ then hera_version="0.5.0" hera_package="hera-${hera_version}-darwin-x86_64.tar.gz" wget "https://github.com/ewasm/hera/releases/download/v${hera_version}/${hera_package}" + validate_checksum "$hera_package" 190050d7ace384ecd79ec1b1f607a9ff40e196b4eec75932958d4814d221d059 tar xzpf "$hera_package" -C /usr/local rm "$hera_package" fi diff --git a/scripts/create_source_tarball.sh b/scripts/create_source_tarball.sh index 3ba18cf87..1ea8c0b57 100755 --- a/scripts/create_source_tarball.sh +++ b/scripts/create_source_tarball.sh @@ -33,7 +33,13 @@ REPO_ROOT="$(dirname "$0")"/.. mkdir -p "$SOLDIR/deps/downloads/" 2>/dev/null || true jsoncpp_version="1.9.3" jsoncpp_package_path="$SOLDIR/deps/downloads/jsoncpp-${jsoncpp_version}.tar.gz" + jsoncpp_sha256=8593c1d69e703563d94d8c12244e2e18893eeb9a8a9f8aa3d09a327aa45c8f7d wget -O "$jsoncpp_package_path" "https://github.com/open-source-parsers/jsoncpp/archive/${jsoncpp_version}.tar.gz" + if ! [ "$(sha256sum "$jsoncpp_package_path")" = "${jsoncpp_sha256} ${jsoncpp_package_path}" ] + then + >&2 echo "ERROR: Downloaded jsoncpp source package has wrong checksum." + exit 1 + fi mkdir -p "$REPO_ROOT/upload" tar --owner 0 --group 0 -czf "$REPO_ROOT/upload/solidity_$versionstring.tar.gz" -C "$TEMPDIR" "solidity_$versionstring" rm -r "$TEMPDIR" diff --git a/scripts/install_deps.ps1 b/scripts/install_deps.ps1 index 02f0419c9..00c439e3a 100644 --- a/scripts/install_deps.ps1 +++ b/scripts/install_deps.ps1 @@ -7,12 +7,18 @@ if ( -not (Test-Path "$PSScriptRoot\..\deps\boost") ) { New-Item -ItemType Directory -Force -Path "$PSScriptRoot\..\deps" Invoke-WebRequest -URI "https://github.com/Kitware/CMake/releases/download/v3.18.2/cmake-3.18.2-win64-x64.zip" -OutFile cmake.zip + if ((Get-FileHash cmake.zip).Hash -ne "5f4ec834fbd9b62fbf73bc48ed459fa2ea6a86c403106c90fedc2ac76d51612d") { + throw 'Downloaded CMake source package has wrong checksum.' + } tar -xf cmake.zip mv cmake-3.18.2-win64-x64 "$PSScriptRoot\..\deps\cmake" # FIXME: The default user agent results in Artifactory treating Invoke-WebRequest as a browser # and serving it a page that requires JavaScript. Invoke-WebRequest -URI "https://boostorg.jfrog.io/artifactory/main/release/1.74.0/source/boost_1_74_0.zip" -OutFile boost.zip -UserAgent "" + if ((Get-FileHash boost.zip).Hash -ne "a0e7ce67c52d816708fdeccdd8c9725626ba61254c13c18770498cacd514710a") { + throw 'Downloaded Boost source package has wrong checksum.' + } tar -xf boost.zip cd boost_1_74_0 .\bootstrap.bat diff --git a/scripts/install_obsolete_jsoncpp_1_7_4.sh b/scripts/install_obsolete_jsoncpp_1_7_4.sh index e184e3059..825d1a58a 100755 --- a/scripts/install_obsolete_jsoncpp_1_7_4.sh +++ b/scripts/install_obsolete_jsoncpp_1_7_4.sh @@ -6,7 +6,13 @@ TEMPDIR=$(mktemp -d) cd "$TEMPDIR" jsoncpp_version="1.7.4" jsoncpp_package="jsoncpp-${jsoncpp_version}.tar.gz" + jsoncpp_sha256=10dcd0677e80727e572a1e462193e51a5fde3e023b99e144b2ee1a469835f769 wget -O "$jsoncpp_package" https://github.com/open-source-parsers/jsoncpp/archive/${jsoncpp_version}.tar.gz + if ! [ "$(sha256sum "$jsoncpp_package")" = "${jsoncpp_sha256} ${jsoncpp_package}" ] + then + >&2 echo "ERROR: Downloaded jsoncpp source package has wrong checksum." + exit 1 + fi tar xvzf "$jsoncpp_package" cd "jsoncpp-${jsoncpp_version}" mkdir -p build From 8b04ac38ab30b06fb5f06c70c1d35c63dc50b715 Mon Sep 17 00:00:00 2001 From: soroosh-sdi Date: Fri, 17 Sep 2021 00:10:00 +0430 Subject: [PATCH 163/232] Require latest Z3 by default and allow relaxing the requirement with STRICT_Z3_VERSION=OFF Signed-off-by: soroosh-sdi --- .circleci/build_win.ps1 | 2 +- CMakeLists.txt | 24 +++++++++++++++++++++++- docs/installing-solidity.rst | 10 ++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/.circleci/build_win.ps1 b/.circleci/build_win.ps1 index 2681cf67d..9be967c97 100644 --- a/.circleci/build_win.ps1 +++ b/.circleci/build_win.ps1 @@ -18,7 +18,7 @@ else { mkdir build cd build $boost_dir=(Resolve-Path $PSScriptRoot\..\deps\boost\lib\cmake\Boost-*) -..\deps\cmake\bin\cmake -G "Visual Studio 16 2019" -DBoost_DIR="$boost_dir\" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DCMAKE_INSTALL_PREFIX="$PSScriptRoot\..\upload" .. +..\deps\cmake\bin\cmake -G "Visual Studio 16 2019" -DBoost_DIR="$boost_dir\" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DCMAKE_INSTALL_PREFIX="$PSScriptRoot\..\upload" -DUSE_Z3=OFF .. if ( -not $? ) { throw "CMake configure failed." } msbuild solidity.sln /p:Configuration=Release /m:5 /v:minimal if ( -not $? ) { throw "Build failed." } diff --git a/CMakeLists.txt b/CMakeLists.txt index e835a66ff..d6f1c3001 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ endif() option(SOLC_LINK_STATIC "Link solc executable statically on supported platforms" OFF) option(SOLC_STATIC_STDLIBS "Link solc against static versions of libgcc and libstdc++ on supported platforms" OFF) +option(STRICT_Z3_VERSION "Use the latest version of Z3" ON) # Setup cccache. include(EthCcache) @@ -63,8 +64,29 @@ configure_file("${CMAKE_SOURCE_DIR}/cmake/templates/license.h.in" include/licens include(EthOptions) configure_project(TESTS) +set(LATEST_Z3_VERSION "4.8.12") +set(MINIMUM_Z3_VERSION "4.8.0") +find_package(Z3) +if (${Z3_FOUND}) + if (${STRICT_Z3_VERSION}) + if (NOT ("${Z3_VERSION_STRING}" VERSION_EQUAL ${LATEST_Z3_VERSION})) + message( + FATAL_ERROR + "SMTChecker tests require Z3 ${LATEST_Z3_VERSION} for all tests to pass.\n\ +Build with -DSTRICT_Z3_VERSION=OFF if you want to use a different version. \ +You can also use -DUSE_Z3=OFF to build without Z3. In both cases use --no-smt when running tests." + ) + endif() + else() + if ("${Z3_VERSION_STRING}" VERSION_LESS ${MINIMUM_Z3_VERSION}) + message( + FATAL_ERROR + "Solidity requires Z3 ${MINIMUM_Z3_VERSION} or newer. You can also use -DUSE_Z3=OFF to build without Z3." + ) + endif() + endif() +endif() -find_package(Z3 4.8.0) if(${USE_Z3_DLOPEN}) add_definitions(-DHAVE_Z3) add_definitions(-DHAVE_Z3_DLOPEN) diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst index a0857e038..ef07ee8e1 100644 --- a/docs/installing-solidity.rst +++ b/docs/installing-solidity.rst @@ -335,6 +335,16 @@ The following are dependencies for all builds of Solidity: Starting from 0.5.10 linking against Boost 1.70+ should work without manual intervention. +.. note:: + The default build configuration requires a specific Z3 version (the latest one at the time the + code was last updated). Changes introduced between Z3 releases often result in slightly different + (but still valid) results being returned. Our SMT tests do not account for these differences and + will likely fail with a different version than the one they were written for. This does not mean + that a build using a different version is faulty. If you pass ``-DSTRICT_Z3_VERSION=OFF`` option + to CMake, you can build with any version that satisfies the requirement given in the table above. + If you do this, however, please remember to pass the ``--no-smt`` option to ``scripts/tests.sh`` + to skip the SMT tests. + Minimum Compiler Versions ^^^^^^^^^^^^^^^^^^^^^^^^^ From e2bb3a334780a087dd14f400f2d211a014ef24a2 Mon Sep 17 00:00:00 2001 From: CrimsonGlory Date: Sat, 25 Sep 2021 21:48:20 -0300 Subject: [PATCH 164/232] [docs] Add bitwise assignment operators Add bitwise assignment operators to the list of operators involving LValues [skip ci] --- docs/types/operators.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/types/operators.rst b/docs/types/operators.rst index 733dc806d..29962588f 100644 --- a/docs/types/operators.rst +++ b/docs/types/operators.rst @@ -7,7 +7,7 @@ If ``a`` is an LValue (i.e. a variable or something that can be assigned to), th following operators are available as shorthands: ``a += e`` is equivalent to ``a = a + e``. The operators ``-=``, ``*=``, ``/=``, ``%=``, -``|=``, ``&=`` and ``^=`` are defined accordingly. ``a++`` and ``a--`` are equivalent +``|=``, ``&=``, ``^=``, ``<<=`` and ``>>=`` are defined accordingly. ``a++`` and ``a--`` are equivalent to ``a += 1`` / ``a -= 1`` but the expression itself still has the previous value of ``a``. In contrast, ``--a`` and ``++a`` have the same effect on ``a`` but return the value after the change. From 4a6b22885e0fb78be0f2bbeb785fc0332988bcc8 Mon Sep 17 00:00:00 2001 From: Harikrishnan Mulackal Date: Mon, 27 Sep 2021 12:27:12 +0200 Subject: [PATCH 165/232] Clarification in changelog --- Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index bb44b8122..7d07627f2 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,7 +2,7 @@ Language Features: * Inheritance: A function that overrides only a single interface function does not require the ``override`` specifier. - * Type System: Support ``type().min`` and ``type().max`` for enums. + * Type System: Support ``type(E).min`` and ``type(E).max`` for enums. * User Defined Value Type: allows creating a zero cost abstraction over a value type with stricter type requirements. From ddcd515a3d9b5e82d32df19875830712f2baa0da Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 27 Sep 2021 13:00:19 +0200 Subject: [PATCH 166/232] Sort changelog. --- Changelog.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Changelog.md b/Changelog.md index 7d07627f2..c36241f7e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,10 +10,10 @@ Compiler Features: * Commandline Interface: Do not implicitly run evm bytecode generation unless needed for the requested output. * Commandline Interface: Normalize paths specified on the command line and make them relative for files located inside base path. * Immutable variables can be read at construction time once they are initialized. - * SMTChecker: Support low level ``call`` as external calls to unknown code. * SMTChecker: Add constraints to better correlate ``address(this).balance`` and ``msg.value``. - * SMTChecker: Support the ``value`` option for external function calls. * SMTChecker: Support constants via modules. + * SMTChecker: Support low level ``call`` as external calls to unknown code. + * SMTChecker: Support the ``value`` option for external function calls. * SMTChecker: Support user defined value types. From 226f040e257d94a24dcfa3bd53d7061f4016efc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 28 Jul 2021 02:36:30 +0200 Subject: [PATCH 167/232] Ensure that native path separators are always used in symlink targets on Windows --- test/FilesystemUtils.cpp | 6 +++++- test/FilesystemUtils.h | 2 +- test/solc/CommandLineInterface.cpp | 5 ----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/test/FilesystemUtils.cpp b/test/FilesystemUtils.cpp index c016f7fd1..159568c62 100644 --- a/test/FilesystemUtils.cpp +++ b/test/FilesystemUtils.cpp @@ -53,13 +53,17 @@ void solidity::test::createFileWithContent(boost::filesystem::path const& _path, } bool solidity::test::createSymlinkIfSupportedByFilesystem( - boost::filesystem::path const& _targetPath, + boost::filesystem::path _targetPath, boost::filesystem::path const& _linkName, bool _directorySymlink ) { boost::system::error_code symlinkCreationError; + // NOTE: On Windows / works as a separator in a symlink target only if the target is absolute. + // Convert path separators to native ones to avoid this problem. + _targetPath.make_preferred(); + if (_directorySymlink) boost::filesystem::create_directory_symlink(_targetPath, _linkName, symlinkCreationError); else diff --git a/test/FilesystemUtils.h b/test/FilesystemUtils.h index f993ce03d..731260505 100644 --- a/test/FilesystemUtils.h +++ b/test/FilesystemUtils.h @@ -46,7 +46,7 @@ void createFileWithContent(boost::filesystem::path const& _path, std::string con /// support symlinks. /// Throws an exception of the operation fails for a different reason. bool createSymlinkIfSupportedByFilesystem( - boost::filesystem::path const& _targetPath, + boost::filesystem::path _targetPath, boost::filesystem::path const& _linkName, bool _directorySymlink ); diff --git a/test/solc/CommandLineInterface.cpp b/test/solc/CommandLineInterface.cpp index 0023e9f57..b76d86ee8 100644 --- a/test/solc/CommandLineInterface.cpp +++ b/test/solc/CommandLineInterface.cpp @@ -786,12 +786,7 @@ BOOST_AUTO_TEST_CASE(cli_paths_to_source_unit_names_symlinks) TemporaryWorkingDirectory tempWorkDir(tempDir.path() / "r"); if ( -#if !defined(_WIN32) !createSymlinkIfSupportedByFilesystem("../x/y", tempDir.path() / "r/sym", true) || -#else - // NOTE: On Windows / works as a separator in a symlink target only if the target is absolute - !createSymlinkIfSupportedByFilesystem("..\\x\\y", tempDir.path() / "r/sym", true) || -#endif !createSymlinkIfSupportedByFilesystem("contract.sol", tempDir.path() / "x/y/z/contract_symlink.sol", false) ) return; From d06dc7613e1005b250b91309ae66fb359b722a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 28 Jul 2021 02:49:39 +0200 Subject: [PATCH 168/232] Print diagnostic info for more exception types in the default import callback --- libsolidity/interface/FileReader.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libsolidity/interface/FileReader.cpp b/libsolidity/interface/FileReader.cpp index f00102e9e..3064d5b89 100644 --- a/libsolidity/interface/FileReader.cpp +++ b/libsolidity/interface/FileReader.cpp @@ -101,6 +101,10 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so { return ReadCallback::Result{false, "Exception in read callback: " + boost::diagnostic_information(_exception)}; } + catch (std::exception const& _exception) + { + return ReadCallback::Result{false, "Exception in read callback: " + boost::diagnostic_information(_exception)}; + } catch (...) { return ReadCallback::Result{false, "Unknown exception in read callback."}; From b9b35a0def16110a1367a6c56f4524945d609cec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 22 Jul 2021 21:54:31 +0200 Subject: [PATCH 169/232] Tests for allowed paths (current state) --- test/CMakeLists.txt | 1 + test/solc/CommandLineInterfaceAllowPaths.cpp | 536 +++++++++++++++++++ test/solc/Common.cpp | 19 +- test/solc/Common.h | 2 + 4 files changed, 557 insertions(+), 1 deletion(-) create mode 100644 test/solc/CommandLineInterfaceAllowPaths.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f35660741..3135b53d5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -160,6 +160,7 @@ set(solcli_sources solc/Common.cpp solc/Common.h solc/CommandLineInterface.cpp + solc/CommandLineInterfaceAllowPaths.cpp solc/CommandLineParser.cpp ) detect_stray_source_files("${solcli_sources}" "solc/") diff --git a/test/solc/CommandLineInterfaceAllowPaths.cpp b/test/solc/CommandLineInterfaceAllowPaths.cpp new file mode 100644 index 000000000..ba71188ef --- /dev/null +++ b/test/solc/CommandLineInterfaceAllowPaths.cpp @@ -0,0 +1,536 @@ +/* + 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 + +/// Unit tests for solc/CommandLineInterface.h + +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace std; +using namespace solidity::frontend; +using namespace solidity::test; + +#define TEST_CASE_NAME (boost::unit_test::framework::current_test_case().p_name) + +namespace +{ + +struct ImportCheck +{ + enum class Result + { + Unknown, ///< Status is unknown due to a failure of the status check. + OK, ///< Passed compilation without errors. + FileNotFound, ///< Error was reported: file not found. + PathDisallowed, ///< Error was reported: file not allowed paths. + }; + + bool operator==(ImportCheck const& _other) const { return result == _other.result && message == _other.message; } + bool operator!=(ImportCheck const& _other) const { return !(*this == _other); } + + operator bool() const { return this->result == Result::OK; } + + static ImportCheck const OK() { return {Result::OK, ""}; } + static ImportCheck const FileNotFound() { return {Result::FileNotFound, ""}; } + static ImportCheck const PathDisallowed() { return {Result::PathDisallowed, ""}; } + static ImportCheck const Unknown(const string& _message) { return {Result::Unknown, _message}; } + + Result result; + std::string message; +}; + +ImportCheck checkImport( + string const& _import, + vector const& _cliOptions +) +{ + soltestAssert(regex_match(_import, regex{R"(import '[^']*')"}), ""); + for (string const& option: _cliOptions) + soltestAssert( + boost::starts_with(option, "--base-path") || + boost::starts_with(option, "--allow-paths") || + !boost::starts_with(option, "--"), + "" + ); + + vector commandLine = { + "solc", + "-", + "--no-color", + "--error-codes", + }; + commandLine += _cliOptions; + + string standardInputContent = + "// SPDX-License-Identifier: GPL-3.0\n" + "pragma solidity >=0.0;\n" + + _import + ";"; + + test::OptionsReaderAndMessages cliResult = test::parseCommandLineAndReadInputFiles( + commandLine, + standardInputContent, + true /* processInput */ + ); + if (cliResult.success) + return ImportCheck::OK(); + + static regex const sourceNotFoundErrorRegex{ + R"(^Error \(6275\): Source ".+" not found: (.*)\.\n)" + R"(\s*--> .*:\d+:\d+:\n)" + R"(\s*\|\n)" + R"(\d+\s*\| import '.+';\n)" + R"(\s*\| \^+\n\s*$)" + }; + + smatch submatches; + if (!regex_match(cliResult.stderrContent, submatches, sourceNotFoundErrorRegex)) + return ImportCheck::Unknown("Unexpected stderr content: '" + cliResult.stderrContent + "'"); + if (submatches[1] != "File not found" && submatches[1] != "File outside of allowed directories") + return ImportCheck::Unknown("Unexpected error message: '" + cliResult.stderrContent + "'"); + + if (submatches[1] == "File not found") + return ImportCheck::FileNotFound(); + else if (submatches[1] == "File outside of allowed directories") + return ImportCheck::PathDisallowed(); + else + return ImportCheck::Unknown("Unexpected error message '" + submatches[1].str() + "'"); +} + +class AllowPathsFixture +{ +protected: + AllowPathsFixture(): + m_tempDir({"code/", "work/"}, TEST_CASE_NAME), + m_tempWorkDir(m_tempDir.path() / "work"), + m_codeDir(m_tempDir.path() / "code"), + m_workDir(m_tempDir.path() / "work"), + m_portablePrefix(("/" / boost::filesystem::canonical(m_codeDir).relative_path()).generic_string()) + { + createFilesWithParentDirs( + { + m_codeDir / "a/b/c/d.sol", + m_codeDir / "a/b/c.sol", + m_codeDir / "a/b/X.sol", + m_codeDir / "a/X/c.sol", + m_codeDir / "X/b/c.sol", + + m_codeDir / "a/bc/d.sol", + m_codeDir / "X/bc/d.sol", + + m_codeDir / "x/y/z.sol", + m_codeDir / "contract.sol", + + m_workDir / "a/b/c/d.sol", + m_workDir / "a/b/c.sol", + m_workDir / "a/b/X.sol", + m_workDir / "a/X/c.sol", + m_workDir / "X/b/c.sol", + + m_workDir / "contract.sol", + }, + "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;" + ); + + if ( + !createSymlinkIfSupportedByFilesystem("b", m_codeDir / "a/b_sym", true) || + !createSymlinkIfSupportedByFilesystem("../x/y", m_codeDir / "a/y_sym", true) || + !createSymlinkIfSupportedByFilesystem("../../a/b/c.sol", m_codeDir / "a/b/c_sym.sol", false) || + !createSymlinkIfSupportedByFilesystem("../../x/y/z.sol", m_codeDir / "a/b/z_sym.sol", false) + ) + return; + + m_caseSensitiveFilesystem = boost::filesystem::create_directories(m_codeDir / "A/B/C"); + soltestAssert(boost::filesystem::equivalent(m_codeDir / "a/b/c", m_codeDir / "A/B/C") != m_caseSensitiveFilesystem, ""); + } + + TemporaryDirectory m_tempDir; + TemporaryWorkingDirectory m_tempWorkDir; + boost::filesystem::path const m_codeDir; + boost::filesystem::path const m_workDir; + string m_portablePrefix; + bool m_caseSensitiveFilesystem = true; +}; + +ostream& operator<<(ostream& _out, ImportCheck const& _value) +{ + switch (_value.result) + { + case ImportCheck::Result::Unknown: _out << "Unknown"; break; + case ImportCheck::Result::OK: _out << "OK"; break; + case ImportCheck::Result::FileNotFound: _out << "FileNotFound"; break; + case ImportCheck::Result::PathDisallowed: _out << "PathDisallowed"; break; + } + if (_value.message != "") + _out << "(" << _value.message << ")"; + return _out; +} + +} // namespace + +namespace boost::test_tools::tt_detail +{ + +// Boost won't find the << operator unless we put it in the std namespace which is illegal. +// The recommended solution is to overload print_log_value<> struct and make it use our operator. + +template<> +struct print_log_value +{ + void operator()(std::ostream& _out, ImportCheck const& _value) { ::operator<<(_out, _value); } +}; + +} // namespace boost::test_tools::tt_detail + +namespace solidity::frontend::test +{ + +BOOST_AUTO_TEST_SUITE(CommandLineInterfaceAllowPathsTest) + +BOOST_FIXTURE_TEST_CASE(allow_path_multiple_paths, AllowPathsFixture) +{ + string allowedPaths = + m_codeDir.generic_string() + "/a/b/X.sol," + + m_codeDir.generic_string() + "/X/," + + m_codeDir.generic_string() + "/z," + + m_codeDir.generic_string() + "/a/b"; + + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", allowedPaths})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", allowedPaths})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", allowedPaths}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", allowedPaths})); +} + +BOOST_FIXTURE_TEST_CASE(allow_path_should_work_with_various_path_forms, AllowPathsFixture) +{ + string import = "import '" + m_portablePrefix + "/a/b/c.sol'"; + + // Without --allow-path + BOOST_TEST(checkImport(import, {}) == ImportCheck::PathDisallowed()); + + // Absolute paths allowed + BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string()})); + BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a"})); + BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a/"})); + BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a/b"})); + BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a/b/c.sol"})); + + // Relative paths allowed + BOOST_TEST(checkImport(import, {"--allow-paths=../code/a"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths=../code/a/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths=../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + + // Non-normalized paths allowed + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/."}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/./"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/.."}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/../"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/./b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/../a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a///b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/b//"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/b///"}) == ImportCheck::PathDisallowed()); + + // Root path allowed + BOOST_TEST(checkImport(import, {"--allow-paths=/"})); + BOOST_TEST(checkImport(import, {"--allow-paths=///"})); + + // UNC paths should be treated differently from normal paths + soltestAssert(FileReader::isUNCPath("/" + m_portablePrefix), ""); + BOOST_TEST(checkImport(import, {"--allow-paths=//"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths=/" + m_portablePrefix}) == ImportCheck::PathDisallowed()); + + // Paths going beyond root allowed + BOOST_TEST(checkImport(import, {"--allow-paths=/../../"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths=/../.."}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths=/../../a/../"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths=/../../" + m_portablePrefix}) == ImportCheck::PathDisallowed()); + + // File named like a directory + BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a/b/c.sol/"})); +} + +BOOST_FIXTURE_TEST_CASE(allow_path_should_handle_empty_paths, AllowPathsFixture) +{ + // Work dir is base path + BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", ""})); + BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "x,,y"})); + BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", ""})); + BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "x,,y"})); + + // Work dir is not base path + BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "", "--base-path=../code/"})); + BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "x,,y", "--base-path=../code/"})); + BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "", "--base-path=../code/"})); + BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "x,,y", "--base-path=../code/"})); +} + +BOOST_FIXTURE_TEST_CASE(allow_path_case_sensitive, AllowPathsFixture) +{ + // Allowed paths are case-sensitive even on case-insensitive filesystems + BOOST_TEST( + checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", m_codeDir.string() + "/A/B/"}) == + ImportCheck::PathDisallowed() + ); +} + +BOOST_FIXTURE_TEST_CASE(allow_path_should_work_with_various_import_forms, AllowPathsFixture) +{ + // Absolute import paths + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a/b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", "../code/a/b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a/b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a/b/"}) == ImportCheck::PathDisallowed()); + + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed()); + + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", "../code/a"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a"}) == ImportCheck::PathDisallowed()); + + // Relative import paths + // NOTE: Base path is whitelisted by default so we need the 'a/../../code/' part to get + // outside of it. And it can't be just '../code/' because that would not be a direct import. + BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/../../code/X/b/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/../../code/a/X/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/../../code/a/b/X.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed()); + + // Non-normalized relative import paths + BOOST_TEST(checkImport("import 'a/../../code/a/./b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/../../code/a/../a/b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/../../code/a///b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + + // UNC paths in imports + string uncImportPath = "/" + m_portablePrefix + "/a/b/c.sol"; + soltestAssert(FileReader::isUNCPath(uncImportPath), ""); + BOOST_TEST(checkImport("import '" + uncImportPath + "'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); +} + +BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_input_files, AllowPathsFixture) +{ + // By default none of the files is whitelisted + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {}) == ImportCheck::PathDisallowed()); + + // Compiling a file whitelists its directory and subdirectories + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_codeDir.string() + "/a/b/c.sol"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {m_codeDir.string() + "/a/b/c.sol"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {m_codeDir.string() + "/a/b/c.sol"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {m_codeDir.string() + "/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {m_codeDir.string() + "/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {m_codeDir.string() + "/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + + // If only file name is specified, its parent dir path is empty. This should be equivalent to + // whitelisting the work dir. + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/contract.sol'", {"contract.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'contract.sol'", {"contract.sol"})); +} + +BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_remappings, AllowPathsFixture) +{ + // Adding a remapping whitelists target's parent directory and subdirectories + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=/contract.sol"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=/contract.sol/"}) == ImportCheck::PathDisallowed()); + + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b=../code/X/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b/=../code/X/b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {m_portablePrefix + "/a/b=../code/X/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {m_portablePrefix + "/a/b/=../code/X/b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b:y/z=x/w"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b:y/z=x/w"}) == ImportCheck::PathDisallowed()); + + // Adding a remapping whitelists the target and subdirectories when the target is a directory + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/c/"}) == ImportCheck::PathDisallowed()); + + // Adding a remapping whitelists target's parent directory and subdirectories when the target + // is a directory but does not have a trailing slash + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {"x=../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"x=../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/c"}) == ImportCheck::PathDisallowed()); + + // Adding a remapping to a relative target at VFS root whitelists the work dir + BOOST_TEST(checkImport("import '/../../x/y/z.sol'", {"x=contract.sol", "--base-path=../code/a/b/"})); + BOOST_TEST(checkImport("import '/../../../work/a/b/c.sol'", {"x=contract.sol", "--base-path=../code/a/b/"})); + + BOOST_TEST(checkImport("import '/../../x/y/z.sol'", {"x=contract.sol/", "--base-path=../code/a/b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '/../../../work/a/b/c.sol'", {"x=contract.sol/", "--base-path=../code/a/b/"}) == ImportCheck::PathDisallowed()); + + // Adding a remapping with an empty target does not whitelist anything + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "="}) == ImportCheck::FileNotFound()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"../code/="})); + BOOST_TEST(checkImport("import '/../work/a/b/c.sol'", {"../code/=", "--base-path", m_portablePrefix})); + + // Adding a remapping that includes .. or . segments whitelists the parent dir and subdirectories + // of the resolved target + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=."})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=."})); + + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=./"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=./"}) == ImportCheck::PathDisallowed()); + + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=.."})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=.."})); + + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../"}) == ImportCheck::PathDisallowed()); + + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./.."}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./.."}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./.."}) == ImportCheck::PathDisallowed()); + + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./../"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./../"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./../"}) == ImportCheck::PathDisallowed()); + + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./../b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./../b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./../b"}) == ImportCheck::PathDisallowed()); + + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./../b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./../b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./../b/"}) == ImportCheck::PathDisallowed()); + + // If the target is just a file name, its parent dir path is empty. This should be equivalent to + // whitelisting the work dir. + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/contract.sol'", {"x=contract.sol"})); + BOOST_TEST(checkImport("import 'contract.sol'", {"x=contract.sol"})); +} + +BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_base_path, AllowPathsFixture) +{ + // Relative base path whitelists its content + BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path=../code/a"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path=../code/a"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path=../code/a"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path=../code/a"}) == ImportCheck::PathDisallowed()); + + BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path=../code/a/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path=../code/a/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path=../code/a/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path=../code/a/"}) == ImportCheck::PathDisallowed()); + + BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path=../code/."}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path=../code/./"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'code/a/b/c.sol'", {"--base-path=.."}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'code/a/b/c.sol'", {"--base-path=../"}) == ImportCheck::PathDisallowed()); + + // Absolute base path whitelists its content + BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path", m_codeDir.string() + "/a"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path", m_codeDir.string() + "/a"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path", m_codeDir.string() + "/a"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path", m_codeDir.string() + "/a"}) == ImportCheck::PathDisallowed()); +} + +BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_work_dir, AllowPathsFixture) +{ + // Work dir is only automatically whitelisted if it matches base path + BOOST_TEST(checkImport("import 'b/../../../work/a/b/c.sol'", {"--base-path=../code/a/"}) == ImportCheck::PathDisallowed()); + + // Compiling a file in the work dir whitelists it even if it's not in base path + BOOST_TEST(checkImport("import 'b/../../../work/a/b/c.sol'", {"--base-path", "../code/a/", "a/b/c.sol"})); + + // Work dir can also be whitelisted manually + BOOST_TEST(checkImport("import 'b/../../../work/a/b/c.sol'", {"--base-path", "../code/a/", "--allow-paths=."})); + + // Not setting base path whitelists the working directory + BOOST_TEST(checkImport("import 'a/b/c.sol'", {}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/b/c/d.sol'", {}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/b/X.sol'", {}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/X/c.sol'", {}) == ImportCheck::PathDisallowed()); + + // Setting base path to an empty value whitelists the working directory + BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path", ""}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/b/c/d.sol'", {"--base-path", ""}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/b/X.sol'", {"--base-path", ""}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/X/c.sol'", {"--base-path", ""}) == ImportCheck::PathDisallowed()); +} + +BOOST_FIXTURE_TEST_CASE(allow_path_symlinks_within_whitelisted_dir, AllowPathsFixture) +{ + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths=../code/a/b_sym/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b_sym/"}) == ImportCheck::PathDisallowed()); + + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths=../code/a/b_sym"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b_sym"}) == ImportCheck::PathDisallowed()); + + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c_sym.sol'", {"--allow-paths=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths=../code/a/b/c_sym.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c_sym.sol'", {"--allow-paths=../code/a/b/c_sym.sol"}) == ImportCheck::PathDisallowed()); +} + +BOOST_FIXTURE_TEST_CASE(allow_path_symlinks_outside_whitelisted_dir, AllowPathsFixture) +{ + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/y_sym/z.sol'", {"--allow-paths=../code/a/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/y_sym/z.sol'", {"--allow-paths=../code/x/"}) == ImportCheck::PathDisallowed()); + + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/a/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/x/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/a/b/z_sym.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/x/y/z.sol"}) == ImportCheck::PathDisallowed()); +} + +BOOST_AUTO_TEST_SUITE_END() + +} // namespace solidity::frontend::test diff --git a/test/solc/Common.cpp b/test/solc/Common.cpp index 1bd209067..28263e21e 100644 --- a/test/solc/Common.cpp +++ b/test/solc/Common.cpp @@ -54,5 +54,22 @@ test::OptionsReaderAndMessages test::parseCommandLineAndReadInputFiles( if (success && _processInput) success = cli.processInput(); - return {success, cli.options(), cli.fileReader(), cli.standardJsonInput(), sout.str(), serr.str()}; + return { + success, + cli.options(), + cli.fileReader(), + cli.standardJsonInput(), + sout.str(), + stripPreReleaseWarning(serr.str()), + }; +} + +string test::stripPreReleaseWarning(string const& _stderrContent) +{ + static regex const preReleaseWarningRegex{ + R"(Warning( \(3805\))?: This is a pre-release compiler version, please do not use it in production\.\n)" + R"((\n)?)" + }; + + return regex_replace(_stderrContent, preReleaseWarningRegex, ""); } diff --git a/test/solc/Common.h b/test/solc/Common.h index 6d5e3875d..958d63054 100644 --- a/test/solc/Common.h +++ b/test/solc/Common.h @@ -50,4 +50,6 @@ OptionsReaderAndMessages parseCommandLineAndReadInputFiles( bool _processInput = false ); +std::string stripPreReleaseWarning(std::string const& _stderrContent); + } // namespace solidity::frontend::test From f0dceffe1d5e3e5d313986e52e802b15f11a6e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 23 Jul 2021 23:43:10 +0200 Subject: [PATCH 170/232] Refactor parsing of remappings to remove duplication and improve readability --- libsolidity/interface/ImportRemapper.cpp | 33 ++++++++++++++---------- libsolidity/interface/ImportRemapper.h | 7 +++-- solc/CommandLineParser.cpp | 29 +++++++++++---------- 3 files changed, 40 insertions(+), 29 deletions(-) diff --git a/libsolidity/interface/ImportRemapper.cpp b/libsolidity/interface/ImportRemapper.cpp index 134101f40..9d5561013 100644 --- a/libsolidity/interface/ImportRemapper.cpp +++ b/libsolidity/interface/ImportRemapper.cpp @@ -20,10 +20,12 @@ #include using std::equal; +using std::find; using std::move; +using std::nullopt; using std::optional; using std::string; -using std::string; +using std::string_view; using std::vector; namespace solidity::frontend @@ -77,24 +79,29 @@ SourceUnitName ImportRemapper::apply(ImportPath const& _path, string const& _con return path; } -optional ImportRemapper::parseRemapping(string const& _remapping) +bool ImportRemapper::isRemapping(string_view _input) { - auto eq = find(_remapping.begin(), _remapping.end(), '='); - if (eq == _remapping.end()) - return {}; + return _input.find("=") != string::npos; +} - auto colon = find(_remapping.begin(), eq, ':'); +optional ImportRemapper::parseRemapping(string_view _input) +{ + auto equals = find(_input.cbegin(), _input.cend(), '='); + if (equals == _input.end()) + return nullopt; - Remapping r; + auto const colon = find(_input.cbegin(), equals, ':'); - r.context = colon == eq ? string() : string(_remapping.begin(), colon); - r.prefix = colon == eq ? string(_remapping.begin(), eq) : string(colon + 1, eq); - r.target = string(eq + 1, _remapping.end()); + Remapping remapping{ + (colon == equals ? "" : string(_input.cbegin(), colon)), + (colon == equals ? string(_input.cbegin(), equals) : string(colon + 1, equals)), + string(equals + 1, _input.cend()), + }; - if (r.prefix.empty()) - return {}; + if (remapping.prefix.empty()) + return nullopt; - return r; + return remapping; } } diff --git a/libsolidity/interface/ImportRemapper.h b/libsolidity/interface/ImportRemapper.h index 4451f0291..66946d091 100644 --- a/libsolidity/interface/ImportRemapper.h +++ b/libsolidity/interface/ImportRemapper.h @@ -56,8 +56,11 @@ public: SourceUnitName apply(ImportPath const& _path, std::string const& _context) const; - // Parses a remapping of the format "context:prefix=target". - static std::optional parseRemapping(std::string const& _remapping); + /// @returns true if the string can be parsed as a remapping + static bool isRemapping(std::string_view _input); + + /// Parses a remapping of the format "context:prefix=target". + static std::optional parseRemapping(std::string_view _input); private: /// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index a2b8676fc..d62745ec9 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -338,11 +338,17 @@ bool CommandLineParser::parseInputPathsAndRemappings() m_options.input.ignoreMissingFiles = (m_args.count(g_strIgnoreMissingFiles) > 0); if (m_args.count(g_strInputFile)) - for (string path: m_args[g_strInputFile].as>()) + for (string const& positionalArg: m_args[g_strInputFile].as>()) { - auto eq = find(path.begin(), path.end(), '='); - if (eq != path.end()) + if (ImportRemapper::isRemapping(positionalArg)) { + optional remapping = ImportRemapper::parseRemapping(positionalArg); + if (!remapping.has_value()) + { + serr() << "Invalid remapping: \"" << positionalArg << "\"." << endl; + return false; + } + if (m_options.input.mode == InputMode::StandardJson) { serr() << "Import remappings are not accepted on the command line in Standard JSON mode." << endl; @@ -350,21 +356,16 @@ bool CommandLineParser::parseInputPathsAndRemappings() return false; } - if (auto r = ImportRemapper::parseRemapping(path)) - m_options.input.remappings.emplace_back(std::move(*r)); - else - { - serr() << "Invalid remapping: \"" << path << "\"." << endl; - return false; - } + boost::filesystem::path remappingDir = remapping->target; + remappingDir.remove_filename(); + m_options.input.allowedDirectories.insert(remappingDir); - string remappingTarget(eq + 1, path.end()); - m_options.input.allowedDirectories.insert(boost::filesystem::path(remappingTarget).remove_filename()); + m_options.input.remappings.emplace_back(move(remapping.value())); } - else if (path == "-") + else if (positionalArg == "-") m_options.input.addStdin = true; else - m_options.input.paths.insert(path); + m_options.input.paths.insert(positionalArg); } if (m_options.input.mode == InputMode::StandardJson) From a436abfb25eae7fbc1e461d1311ff5d6b72357da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 21 Jul 2021 18:52:12 +0200 Subject: [PATCH 171/232] normalizeCLIPathForVFS(): Add an option for resolving symlinks --- libsolidity/interface/FileReader.cpp | 32 ++- libsolidity/interface/FileReader.h | 14 +- test/libsolidity/interface/FileReader.cpp | 318 +++++++++++++--------- 3 files changed, 234 insertions(+), 130 deletions(-) diff --git a/libsolidity/interface/FileReader.cpp b/libsolidity/interface/FileReader.cpp index 3064d5b89..28f52d834 100644 --- a/libsolidity/interface/FileReader.cpp +++ b/libsolidity/interface/FileReader.cpp @@ -111,7 +111,10 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so } } -boost::filesystem::path FileReader::normalizeCLIPathForVFS(boost::filesystem::path const& _path) +boost::filesystem::path FileReader::normalizeCLIPathForVFS( + boost::filesystem::path const& _path, + SymlinkResolution _symlinkResolution +) { // Detailed normalization rules: // - Makes the path either be absolute or have slash as root (note that on Windows paths with @@ -125,7 +128,8 @@ boost::filesystem::path FileReader::normalizeCLIPathForVFS(boost::filesystem::pa // path to the current working directory. // // Also note that this function: - // - Does NOT resolve symlinks (except for symlinks in the path to the current working directory). + // - Does NOT resolve symlinks (except for symlinks in the path to the current working directory) + // unless explicitly requested. // - Does NOT check if the path refers to a file or a directory. If the path ends with a slash, // the slash is preserved even if it's a file. // - The only exception are paths where the file name is a dot (e.g. '.' or 'a/b/.'). These @@ -139,9 +143,27 @@ boost::filesystem::path FileReader::normalizeCLIPathForVFS(boost::filesystem::pa // Windows it does not. To get consistent results we resolve them on all platforms. boost::filesystem::path absolutePath = boost::filesystem::absolute(_path, canonicalWorkDir); - // NOTE: boost path preserves certain differences that are ignored by its operator ==. - // E.g. "a//b" vs "a/b" or "a/b/" vs "a/b/.". lexically_normal() does remove these differences. - boost::filesystem::path normalizedPath = absolutePath.lexically_normal(); + boost::filesystem::path normalizedPath; + if (_symlinkResolution == SymlinkResolution::Enabled) + { + // NOTE: weakly_canonical() will not convert a relative path into an absolute one if no + // directory included in the path actually exists. + normalizedPath = boost::filesystem::weakly_canonical(absolutePath); + + // The three corner cases in which lexically_normal() includes a trailing slash in the + // normalized path but weakly_canonical() does not. Note that the trailing slash is not + // ignored when comparing paths with ==. + if ((_path == "." || _path == "./" || _path == "../") && !boost::ends_with(normalizedPath.generic_string(), "/")) + normalizedPath = normalizedPath.parent_path() / (normalizedPath.filename().string() + "/"); + } + else + { + solAssert(_symlinkResolution == SymlinkResolution::Disabled, ""); + + // NOTE: boost path preserves certain differences that are ignored by its operator ==. + // E.g. "a//b" vs "a/b" or "a/b/" vs "a/b/.". lexically_normal() does remove these differences. + normalizedPath = absolutePath.lexically_normal(); + } solAssert(normalizedPath.is_absolute() || normalizedPath.root_path() == "/", ""); // If the path is on the same drive as the working dir, for portability we prefer not to diff --git a/libsolidity/interface/FileReader.h b/libsolidity/interface/FileReader.h index bbe24d264..53d4ef9b8 100644 --- a/libsolidity/interface/FileReader.h +++ b/libsolidity/interface/FileReader.h @@ -39,6 +39,11 @@ public: using PathMap = std::map; using FileSystemPathSet = std::set; + enum SymlinkResolution { + Disabled, ///< Do not resolve symbolic links in the path. + Enabled, ///< Follow symbolic links. The path should contain no symlinks. + }; + /// Constructs a FileReader with a base path and a set of allowed directories that /// will be used when requesting files from this file reader instance. explicit FileReader( @@ -90,11 +95,16 @@ public: /// Normalizes a filesystem path to make it include all components up to the filesystem root, /// remove small, inconsequential differences that do not affect the meaning and make it look - /// the same on all platforms (if possible). Symlinks in the path are not resolved. + /// the same on all platforms (if possible). /// The resulting path uses forward slashes as path separators, has no redundant separators, /// has no redundant . or .. segments and has no root name if removing it does not change the meaning. /// The path does not have to actually exist. - static boost::filesystem::path normalizeCLIPathForVFS(boost::filesystem::path const& _path); + /// @param _path Path to normalize. + /// @param _symlinkResolution If @a Disabled, any symlinks present in @a _path are preserved. + static boost::filesystem::path normalizeCLIPathForVFS( + boost::filesystem::path const& _path, + SymlinkResolution _symlinkResolution = SymlinkResolution::Disabled + ); /// @returns true if all the path components of @a _prefix are present at the beginning of @a _path. /// Both paths must be absolute (or have slash as root) and normalized (no . or .. segments, no diff --git a/test/libsolidity/interface/FileReader.cpp b/test/libsolidity/interface/FileReader.cpp index fd1eb52cc..866a4435a 100644 --- a/test/libsolidity/interface/FileReader.cpp +++ b/test/libsolidity/interface/FileReader.cpp @@ -36,31 +36,36 @@ using namespace solidity::test; namespace solidity::frontend::test { +using SymlinkResolution = FileReader::SymlinkResolution; + BOOST_AUTO_TEST_SUITE(FileReaderTest) BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_absolute_path) { - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/"), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./"), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./."), "/"); + for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled}) + { + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/.", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./.", resolveSymlinks), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a"), "/a"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/"), "/a/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/."), "/a/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a"), "/a"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a/"), "/a/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a/."), "/a/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b"), "/a/b"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/"), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a", resolveSymlinks), "/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/", resolveSymlinks), "/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/.", resolveSymlinks), "/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a", resolveSymlinks), "/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a/", resolveSymlinks), "/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/./a/.", resolveSymlinks), "/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b", resolveSymlinks), "/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/", resolveSymlinks), "/a/b/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/./b/"), "/a/b/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../a/b/"), "/a/b/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/.."), "/a/b"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../"), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/./b/", resolveSymlinks), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../a/b/", resolveSymlinks), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/..", resolveSymlinks), "/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../", resolveSymlinks), "/a/b/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../.."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../../"), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../../", resolveSymlinks), "/"); + } } BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_relative_path) @@ -75,54 +80,60 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_relative_path) expectedPrefix = "/" / expectedPrefix.relative_path(); soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", ""); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("."), expectedPrefix / "x/y/z/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./"), expectedPrefix / "x/y/z/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".//"), expectedPrefix / "x/y/z/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".."), expectedPrefix / "x/y"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../"), expectedPrefix / "x/y/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("..//"), expectedPrefix / "x/y/"); + for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled}) + { + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".", resolveSymlinks), expectedPrefix / "x/y/z/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./", resolveSymlinks), expectedPrefix / "x/y/z/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".//", resolveSymlinks), expectedPrefix / "x/y/z/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("..", resolveSymlinks), expectedPrefix / "x/y"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../", resolveSymlinks), expectedPrefix / "x/y/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("..//", resolveSymlinks), expectedPrefix / "x/y/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a"), expectedPrefix / "x/y/z/a"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/"), expectedPrefix / "x/y/z/a/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/."), expectedPrefix / "x/y/z/a/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a"), expectedPrefix / "x/y/z/a"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/"), expectedPrefix / "x/y/z/a/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/."), expectedPrefix / "x/y/z/a/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/./"), expectedPrefix / "x/y/z/a/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/.//"), expectedPrefix / "x/y/z/a/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/./."), expectedPrefix / "x/y/z/a/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/././"), expectedPrefix / "x/y/z/a/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/././/"), expectedPrefix / "x/y/z/a/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b"), expectedPrefix / "x/y/z/a/b"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/"), expectedPrefix / "x/y/z/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a", resolveSymlinks), expectedPrefix / "x/y/z/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/", resolveSymlinks), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/.", resolveSymlinks), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a", resolveSymlinks), expectedPrefix / "x/y/z/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/", resolveSymlinks), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/.", resolveSymlinks), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/./", resolveSymlinks), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/.//", resolveSymlinks), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/./.", resolveSymlinks), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/././", resolveSymlinks), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/././/", resolveSymlinks), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b", resolveSymlinks), expectedPrefix / "x/y/z/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/", resolveSymlinks), expectedPrefix / "x/y/z/a/b/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/b"), expectedPrefix / "x/y/a/b"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/b"), expectedPrefix / "x/a/b"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/b"), expectedPrefix / "x/y/z/a/b"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("././a/b"), expectedPrefix / "x/y/z/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/b", resolveSymlinks), expectedPrefix / "x/y/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/b", resolveSymlinks), expectedPrefix / "x/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/b", resolveSymlinks), expectedPrefix / "x/y/z/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("././a/b", resolveSymlinks), expectedPrefix / "x/y/z/a/b"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/./b/"), expectedPrefix / "x/y/z/a/b/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../a/b/"), expectedPrefix / "x/y/z/a/b/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/.."), expectedPrefix / "x/y/z/a/b"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../"), expectedPrefix / "x/y/z/a/b/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/..//"), expectedPrefix / "x/y/z/a/b/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../.."), expectedPrefix / "x/y/z/a"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../../"), expectedPrefix / "x/y/z/a/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../..//"), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/./b/", resolveSymlinks), expectedPrefix / "x/y/z/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../a/b/", resolveSymlinks), expectedPrefix / "x/y/z/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/..", resolveSymlinks), expectedPrefix / "x/y/z/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../", resolveSymlinks), expectedPrefix / "x/y/z/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/..//", resolveSymlinks), expectedPrefix / "x/y/z/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../..", resolveSymlinks), expectedPrefix / "x/y/z/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../../", resolveSymlinks), expectedPrefix / "x/y/z/a/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../..//", resolveSymlinks), expectedPrefix / "x/y/z/a/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/.././../p/../q/../a/b"), expectedPrefix / "a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/.././../p/../q/../a/b", resolveSymlinks), expectedPrefix / "a/b"); + } } BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_redundant_slashes) { - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("///"), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("////"), "/"); + for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled}) + { + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("///", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("////", resolveSymlinks), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("////a/b/"), "/a/b/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a//b/"), "/a/b/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a////b/"), "/a/b/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b//"), "/a/b/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b////"), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("////a/b/", resolveSymlinks), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a//b/", resolveSymlinks), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a////b/", resolveSymlinks), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b//", resolveSymlinks), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b////", resolveSymlinks), "/a/b/"); + } } BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_unc_path) @@ -134,23 +145,26 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_unc_path) boost::filesystem::path expectedWorkDir = "/" / boost::filesystem::current_path().relative_path(); soltestAssert(expectedWorkDir.is_absolute() || expectedWorkDir.root_path() == "/", ""); - // UNC paths start with // or \\ followed by a name. They are used for network shares on Windows. - // On UNIX systems they are not supported but still treated in a special way. - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/"), "//host/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/a/b"), "//host/a/b"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/a/b/"), "//host/a/b/"); + for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled}) + { + // UNC paths start with // or \\ followed by a name. They are used for network shares on Windows. + // On UNIX systems they are not supported but still treated in a special way. + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/", resolveSymlinks), "//host/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/a/b", resolveSymlinks), "//host/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host/a/b/", resolveSymlinks), "//host/a/b/"); #if defined(_WIN32) - // On Windows an UNC path can also start with \\ instead of // - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/"), "//host/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b"), "//host/a/b"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/"), "//host/a/b/"); + // On Windows an UNC path can also start with \\ instead of // + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/", resolveSymlinks), "//host/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b", resolveSymlinks), "//host/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/", resolveSymlinks), "//host/a/b/"); #else - // On UNIX systems it's just a fancy relative path instead - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/"), expectedWorkDir / "\\\\host/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b"), expectedWorkDir / "\\\\host/a/b"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/"), expectedWorkDir / "\\\\host/a/b/"); + // On UNIX systems it's just a fancy relative path instead + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/", resolveSymlinks), expectedWorkDir / "\\\\host/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b", resolveSymlinks), expectedWorkDir / "\\\\host/a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("\\\\host/a/b/", resolveSymlinks), expectedWorkDir / "\\\\host/a/b/"); #endif + } } BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_root_name_only) @@ -167,20 +181,23 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_root_name_only) // C:\ represents the root directory of drive C: but C: on its own refers to the current working // directory. - // UNC paths - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//"), "//" / expectedWorkDir); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host"), "//host" / expectedWorkDir); + for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled}) + { + // UNC paths + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//", resolveSymlinks), "//" / expectedWorkDir); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("//host", resolveSymlinks), "//host" / expectedWorkDir); - // On UNIX systems root name is empty. - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(""), expectedWorkDir); + // On UNIX systems root name is empty. + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("", resolveSymlinks), expectedWorkDir); #if defined(_WIN32) - boost::filesystem::path driveLetter = boost::filesystem::current_path().root_name(); - solAssert(!driveLetter.empty(), ""); - solAssert(driveLetter.is_relative(), ""); + boost::filesystem::path driveLetter = boost::filesystem::current_path().root_name(); + solAssert(!driveLetter.empty(), ""); + solAssert(driveLetter.is_relative(), ""); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(driveLetter), expectedWorkDir); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(driveLetter, resolveSymlinks), expectedWorkDir); #endif + } } BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_stripping_root_name) @@ -193,41 +210,50 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_stripping_root_name) soltestAssert(!boost::filesystem::current_path().root_name().empty(), ""); #endif - boost::filesystem::path normalizedPath = FileReader::normalizeCLIPathForVFS(boost::filesystem::current_path()); - BOOST_CHECK_EQUAL(normalizedPath, "/" / boost::filesystem::current_path().relative_path()); - BOOST_TEST(normalizedPath.root_name().empty()); - BOOST_CHECK_EQUAL(normalizedPath.root_directory(), "/"); + for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled}) + { + boost::filesystem::path normalizedPath = FileReader::normalizeCLIPathForVFS( + boost::filesystem::current_path(), + resolveSymlinks + ); + BOOST_CHECK_EQUAL(normalizedPath, "/" / boost::filesystem::current_path().relative_path()); + BOOST_TEST(normalizedPath.root_name().empty()); + BOOST_CHECK_EQUAL(normalizedPath.root_directory(), "/"); + } } BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_beyond_root) { TemporaryWorkingDirectory tempWorkDir("/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/.."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../"), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../.."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a"), "/a"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/.."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/../.."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a"), "/a"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/.."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/../.."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../.."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../../b/../.."), "/"); + for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled}) + { + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../.", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a", resolveSymlinks), "/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/../..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a", resolveSymlinks), "/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/../..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../../b/../..", resolveSymlinks), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(".."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../"), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../.."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a"), "/a"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/.."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/../.."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a"), "/a"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/.."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/../.."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../.."), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../../b/../.."), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../.", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a", resolveSymlinks), "/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/../..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a", resolveSymlinks), "/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/../..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../../b/../..", resolveSymlinks), "/"); + } } BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_case_sensitivity) @@ -235,22 +261,31 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_case_sensitivity) TemporaryDirectory tempDir(TEST_CASE_NAME); TemporaryWorkingDirectory tempWorkDir(tempDir); - boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path(); - soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", ""); + boost::filesystem::path workDirNoSymlinks = boost::filesystem::weakly_canonical(tempDir); + boost::filesystem::path expectedPrefix = "/" / workDirNoSymlinks.relative_path(); - BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc") == expectedPrefix / "abc"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc") != expectedPrefix / "ABC"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "ABC") != expectedPrefix / "abc"); - BOOST_TEST(FileReader::normalizeCLIPathForVFS(tempDir.path() / "ABC") == expectedPrefix / "ABC"); + for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled}) + { + BOOST_TEST(FileReader::normalizeCLIPathForVFS(workDirNoSymlinks / "abc", resolveSymlinks) == expectedPrefix / "abc"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS(workDirNoSymlinks / "abc", resolveSymlinks) != expectedPrefix / "ABC"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS(workDirNoSymlinks / "ABC", resolveSymlinks) != expectedPrefix / "abc"); + BOOST_TEST(FileReader::normalizeCLIPathForVFS(workDirNoSymlinks / "ABC", resolveSymlinks) == expectedPrefix / "ABC"); + } } BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_separators) { - // Even on Windows we want / as a separator. - BOOST_TEST((FileReader::normalizeCLIPathForVFS("/a/b/c").native() == boost::filesystem::path("/a/b/c").native())); + for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled}) + { + // Even on Windows we want / as a separator. + BOOST_TEST(( + FileReader::normalizeCLIPathForVFS("/a/b/c", resolveSymlinks).native() == + boost::filesystem::path("/a/b/c").native() + )); + } } -BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_not_resolve_symlinks) +BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_not_resolve_symlinks_unless_requested) { TemporaryDirectory tempDir({"abc/"}, TEST_CASE_NAME); soltestAssert(tempDir.path().is_absolute(), ""); @@ -258,11 +293,26 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_not_resolve_symlinks) if (!createSymlinkIfSupportedByFilesystem(tempDir.path() / "abc", tempDir.path() / "sym", true)) return; - boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path(); - soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", ""); + boost::filesystem::path expectedPrefixWithSymlinks = "/" / tempDir.path().relative_path(); + boost::filesystem::path expectedPrefixWithoutSymlinks = "/" / boost::filesystem::weakly_canonical(tempDir).relative_path(); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol"), expectedPrefix / "sym/contract.sol"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol"), expectedPrefix / "abc/contract.sol"); + BOOST_CHECK_EQUAL( + FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol", SymlinkResolution::Disabled), + expectedPrefixWithSymlinks / "sym/contract.sol" + ); + BOOST_CHECK_EQUAL( + FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol", SymlinkResolution::Disabled), + expectedPrefixWithSymlinks / "abc/contract.sol" + ); + + BOOST_CHECK_EQUAL( + FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol", SymlinkResolution::Enabled), + expectedPrefixWithoutSymlinks / "abc/contract.sol" + ); + BOOST_CHECK_EQUAL( + FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol", SymlinkResolution::Enabled), + expectedPrefixWithoutSymlinks / "abc/contract.sol" + ); } BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_resolve_symlinks_in_workdir_when_path_is_relative) @@ -280,9 +330,31 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_should_resolve_symlinks_in_workdir_w boost::filesystem::path expectedPrefix = "/" / tempDir.path().relative_path(); soltestAssert(expectedPrefix.is_absolute() || expectedPrefix.root_path() == "/", ""); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("contract.sol"), expectedWorkDir / "contract.sol"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol"), expectedPrefix / "sym/contract.sol"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol"), expectedPrefix / "abc/contract.sol"); + for (SymlinkResolution resolveSymlinks: {SymlinkResolution::Enabled, SymlinkResolution::Disabled}) + { + BOOST_CHECK_EQUAL( + FileReader::normalizeCLIPathForVFS("contract.sol", resolveSymlinks), + expectedWorkDir / "contract.sol" + ); + } + + BOOST_CHECK_EQUAL( + FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol", SymlinkResolution::Disabled), + expectedPrefix / "sym/contract.sol" + ); + BOOST_CHECK_EQUAL( + FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol", SymlinkResolution::Disabled), + expectedPrefix / "abc/contract.sol" + ); + + BOOST_CHECK_EQUAL( + FileReader::normalizeCLIPathForVFS(tempDir.path() / "sym/contract.sol", SymlinkResolution::Enabled), + expectedWorkDir / "contract.sol" + ); + BOOST_CHECK_EQUAL( + FileReader::normalizeCLIPathForVFS(tempDir.path() / "abc/contract.sol", SymlinkResolution::Enabled), + expectedWorkDir / "contract.sol" + ); } BOOST_AUTO_TEST_CASE(isPathPrefix_file_prefix) From 52dd39212d9f48cb7367b9c9bb0c8008d9837bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 21 Jul 2021 19:00:30 +0200 Subject: [PATCH 172/232] Normalize allowed paths before comparing them with imports --- libsolidity/interface/FileReader.cpp | 14 +- solc/CommandLineParser.cpp | 13 +- test/solc/CommandLineInterfaceAllowPaths.cpp | 158 +++++++++---------- 3 files changed, 86 insertions(+), 99 deletions(-) diff --git a/libsolidity/interface/FileReader.cpp b/libsolidity/interface/FileReader.cpp index 28f52d834..7ed84c579 100644 --- a/libsolidity/interface/FileReader.cpp +++ b/libsolidity/interface/FileReader.cpp @@ -69,20 +69,16 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so if (strippedSourceUnitName.find("file://") == 0) strippedSourceUnitName.erase(0, 7); - auto canonicalPath = boost::filesystem::weakly_canonical(m_basePath / strippedSourceUnitName); + auto canonicalPath = normalizeCLIPathForVFS(m_basePath / strippedSourceUnitName, SymlinkResolution::Enabled); + bool isAllowed = false; - for (auto const& allowedDir: m_allowedDirectories) - { - // If dir is a prefix of boostPath, we are fine. - if ( - std::distance(allowedDir.begin(), allowedDir.end()) <= std::distance(canonicalPath.begin(), canonicalPath.end()) && - std::equal(allowedDir.begin(), allowedDir.end(), canonicalPath.begin()) - ) + for (boost::filesystem::path const& allowedDir: m_allowedDirectories) + if (isPathPrefix(normalizeCLIPathForVFS(allowedDir, SymlinkResolution::Enabled), canonicalPath)) { isAllowed = true; break; } - } + if (!isAllowed) return ReadCallback::Result{false, "File outside of allowed directories."}; diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index d62745ec9..64fc5e630 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -978,17 +978,8 @@ bool CommandLineParser::processArgs() if (m_args.count(g_strAllowPaths)) { vector paths; - for (string const& path: boost::split(paths, m_args[g_strAllowPaths].as(), boost::is_any_of(","))) - { - auto filesystem_path = boost::filesystem::path(path); - // If the given path had a trailing slash, the Boost filesystem - // path will have it's last component set to '.'. This breaks - // path comparison in later parts of the code, so we need to strip - // it. - if (filesystem_path.filename() == ".") - filesystem_path.remove_filename(); - m_options.input.allowedDirectories.insert(filesystem_path); - } + for (string const& allowedPath: boost::split(paths, m_args[g_strAllowPaths].as(), boost::is_any_of(","))) + m_options.input.allowedDirectories.insert(allowedPath); } if (m_args.count(g_strStopAfter)) diff --git a/test/solc/CommandLineInterfaceAllowPaths.cpp b/test/solc/CommandLineInterfaceAllowPaths.cpp index ba71188ef..ac5b2ca62 100644 --- a/test/solc/CommandLineInterfaceAllowPaths.cpp +++ b/test/solc/CommandLineInterfaceAllowPaths.cpp @@ -243,22 +243,22 @@ BOOST_FIXTURE_TEST_CASE(allow_path_should_work_with_various_path_forms, AllowPat BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a/b/c.sol"})); // Relative paths allowed - BOOST_TEST(checkImport(import, {"--allow-paths=../code/a"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport(import, {"--allow-paths=../code/a/"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport(import, {"--allow-paths=../code/a/b"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport(import, {"--allow-paths=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths=../code/a"})); + BOOST_TEST(checkImport(import, {"--allow-paths=../code/a/"})); + BOOST_TEST(checkImport(import, {"--allow-paths=../code/a/b"})); + BOOST_TEST(checkImport(import, {"--allow-paths=../code/a/b/c.sol"})); // Non-normalized paths allowed - BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/."}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/./"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/.."}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/../"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/b"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/./b"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/../a/b"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a///b"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/b//"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/b///"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/."})); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/./"})); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/.."})); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/../"})); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/b"})); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/./b"})); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/../a/b"})); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a///b"})); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/b//"})); + BOOST_TEST(checkImport(import, {"--allow-paths", "./../code/a/b///"})); // Root path allowed BOOST_TEST(checkImport(import, {"--allow-paths=/"})); @@ -270,10 +270,10 @@ BOOST_FIXTURE_TEST_CASE(allow_path_should_work_with_various_path_forms, AllowPat BOOST_TEST(checkImport(import, {"--allow-paths=/" + m_portablePrefix}) == ImportCheck::PathDisallowed()); // Paths going beyond root allowed - BOOST_TEST(checkImport(import, {"--allow-paths=/../../"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport(import, {"--allow-paths=/../.."}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport(import, {"--allow-paths=/../../a/../"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport(import, {"--allow-paths=/../../" + m_portablePrefix}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport(import, {"--allow-paths=/../../"})); + BOOST_TEST(checkImport(import, {"--allow-paths=/../.."})); + BOOST_TEST(checkImport(import, {"--allow-paths=/../../a/../"})); + BOOST_TEST(checkImport(import, {"--allow-paths=/../../" + m_portablePrefix})); // File named like a directory BOOST_TEST(checkImport(import, {"--allow-paths", m_codeDir.string() + "/a/b/c.sol/"})); @@ -284,14 +284,14 @@ BOOST_FIXTURE_TEST_CASE(allow_path_should_handle_empty_paths, AllowPathsFixture) // Work dir is base path BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", ""})); BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "x,,y"})); - BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", ""})); - BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "x,,y"})); + BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", ""}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "x,,y"}) == ImportCheck::PathDisallowed()); // Work dir is not base path BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "", "--base-path=../code/"})); BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "x,,y", "--base-path=../code/"})); - BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "", "--base-path=../code/"})); - BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "x,,y", "--base-path=../code/"})); + BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "", "--base-path=../code/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "x,,y", "--base-path=../code/"}) == ImportCheck::PathDisallowed()); } BOOST_FIXTURE_TEST_CASE(allow_path_case_sensitive, AllowPathsFixture) @@ -306,38 +306,38 @@ BOOST_FIXTURE_TEST_CASE(allow_path_case_sensitive, AllowPathsFixture) BOOST_FIXTURE_TEST_CASE(allow_path_should_work_with_various_import_forms, AllowPathsFixture) { // Absolute import paths - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a/b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a/b/"})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", "../code/a/b/"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a/b/"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a/b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a/b/"})); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a/b"})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a/b"})); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths", "../code/a"})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"--allow-paths", "../code/a"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"--allow-paths", "../code/a"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"--allow-paths", "../code/a"})); // Relative import paths // NOTE: Base path is whitelisted by default so we need the 'a/../../code/' part to get // outside of it. And it can't be just '../code/' because that would not be a direct import. - BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "../code/a/b"})); BOOST_TEST(checkImport("import 'a/../../code/X/b/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import 'a/../../code/a/X/c.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'a/../../code/a/b/X.sol'", {"--allow-paths", "../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/../../code/a/b/X.sol'", {"--allow-paths", "../code/a/b"})); // Non-normalized relative import paths - BOOST_TEST(checkImport("import 'a/../../code/a/./b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'a/../../code/a/../a/b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'a/../../code/a///b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/../../code/a/./b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"})); + BOOST_TEST(checkImport("import 'a/../../code/a/../a/b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"})); + BOOST_TEST(checkImport("import 'a/../../code/a///b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"})); // UNC paths in imports string uncImportPath = "/" + m_portablePrefix + "/a/b/c.sol"; @@ -372,9 +372,9 @@ BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_input_files, AllowPath BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_remappings, AllowPathsFixture) { // Adding a remapping whitelists target's parent directory and subdirectories - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/c.sol"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {"x=../code/a/b/c.sol"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"x=../code/a/b/c.sol"})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); @@ -382,17 +382,17 @@ BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_remappings, AllowPaths BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=/contract.sol"})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=/contract.sol/"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b=../code/X/b"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b/=../code/X/b/"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {m_portablePrefix + "/a/b=../code/X/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b=../code/X/b"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b/=../code/X/b/"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {m_portablePrefix + "/a/b=../code/X/b"})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {m_portablePrefix + "/a/b/=../code/X/b/"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b:y/z=x/w"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "/a/b:y/z=x/w"}) == ImportCheck::PathDisallowed()); // Adding a remapping whitelists the target and subdirectories when the target is a directory - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {"x=../code/a/b/"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"x=../code/a/b/"})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/b/"}) == ImportCheck::PathDisallowed()); @@ -400,59 +400,59 @@ BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_remappings, AllowPaths // Adding a remapping whitelists target's parent directory and subdirectories when the target // is a directory but does not have a trailing slash - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {"x=../code/a/b"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"x=../code/a/b"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c/d.sol'", {"x=../code/a/b"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/X.sol'", {"x=../code/a/b"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b"})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/b"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/c"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/b"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/bc/d.sol'", {"x=../code/a/c"})); // Adding a remapping to a relative target at VFS root whitelists the work dir - BOOST_TEST(checkImport("import '/../../x/y/z.sol'", {"x=contract.sol", "--base-path=../code/a/b/"})); + BOOST_TEST(checkImport("import '/../../x/y/z.sol'", {"x=contract.sol", "--base-path=../code/a/b/"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '/../../../work/a/b/c.sol'", {"x=contract.sol", "--base-path=../code/a/b/"})); BOOST_TEST(checkImport("import '/../../x/y/z.sol'", {"x=contract.sol/", "--base-path=../code/a/b/"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '/../../../work/a/b/c.sol'", {"x=contract.sol/", "--base-path=../code/a/b/"}) == ImportCheck::PathDisallowed()); // Adding a remapping with an empty target does not whitelist anything - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "="}) == ImportCheck::FileNotFound()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"../code/="})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "="}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"../code/="}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '/../work/a/b/c.sol'", {"../code/=", "--base-path", m_portablePrefix})); // Adding a remapping that includes .. or . segments whitelists the parent dir and subdirectories // of the resolved target - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=."})); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=."})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=."}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=."}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=./"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=./"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=.."})); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=.."})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=.."}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=.."}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../"})); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./.."}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./.."})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./.."}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./.."}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./../"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./../"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./../"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./../"})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./../"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./../b"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./../b"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./../b"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./../b"})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./../b"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./../b/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./../b/"})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./../b/"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./../b/"}) == ImportCheck::PathDisallowed()); // If the target is just a file name, its parent dir path is empty. This should be equivalent to // whitelisting the work dir. - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/contract.sol'", {"x=contract.sol"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/contract.sol'", {"x=contract.sol"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import 'contract.sol'", {"x=contract.sol"})); } @@ -507,28 +507,28 @@ BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_work_dir, AllowPathsFi BOOST_FIXTURE_TEST_CASE(allow_path_symlinks_within_whitelisted_dir, AllowPathsFixture) { - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b/"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths=../code/a/b_sym/"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b_sym/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b/"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths=../code/a/b_sym/"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b_sym/"})); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths=../code/a/b_sym"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b_sym"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths=../code/a/b_sym"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b_sym"})); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c_sym.sol'", {"--allow-paths=../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths=../code/a/b/c_sym.sol"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c_sym.sol'", {"--allow-paths=../code/a/b/c_sym.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c_sym.sol'", {"--allow-paths=../code/a/b/c.sol"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"--allow-paths=../code/a/b/c_sym.sol"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c_sym.sol'", {"--allow-paths=../code/a/b/c_sym.sol"})); } BOOST_FIXTURE_TEST_CASE(allow_path_symlinks_outside_whitelisted_dir, AllowPathsFixture) { BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/y_sym/z.sol'", {"--allow-paths=../code/a/"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/y_sym/z.sol'", {"--allow-paths=../code/x/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/y_sym/z.sol'", {"--allow-paths=../code/x/"})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/a/"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/x/"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/a/b/z_sym.sol"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/x/y/z.sol"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/x/"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/a/b/z_sym.sol"})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/z_sym.sol'", {"--allow-paths=../code/x/y/z.sol"})); } BOOST_AUTO_TEST_SUITE_END() From 3ac36127674fc823e18bbf2c4c4947acb5141e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 24 Jul 2021 03:54:46 +0200 Subject: [PATCH 173/232] Whitelist base path --- libsolidity/interface/FileReader.cpp | 3 +- test/cmdlineTests/stdin_allowed_paths/args | 1 - test/cmdlineTests/stdin_allowed_paths/err | 11 ---- test/cmdlineTests/stdin_allowed_paths/exit | 1 - .../stdin_allowed_paths/input.sol | 4 -- test/cmdlineTests/stdin_allowed_paths/stdin | 4 -- test/solc/CommandLineInterfaceAllowPaths.cpp | 52 +++++++++---------- 7 files changed, 28 insertions(+), 48 deletions(-) delete mode 100644 test/cmdlineTests/stdin_allowed_paths/args delete mode 100644 test/cmdlineTests/stdin_allowed_paths/err delete mode 100644 test/cmdlineTests/stdin_allowed_paths/exit delete mode 100644 test/cmdlineTests/stdin_allowed_paths/input.sol delete mode 100644 test/cmdlineTests/stdin_allowed_paths/stdin diff --git a/libsolidity/interface/FileReader.cpp b/libsolidity/interface/FileReader.cpp index 7ed84c579..b7ff2ce58 100644 --- a/libsolidity/interface/FileReader.cpp +++ b/libsolidity/interface/FileReader.cpp @@ -70,9 +70,10 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so strippedSourceUnitName.erase(0, 7); auto canonicalPath = normalizeCLIPathForVFS(m_basePath / strippedSourceUnitName, SymlinkResolution::Enabled); + FileSystemPathSet extraAllowedPaths = {m_basePath.empty() ? "." : m_basePath}; bool isAllowed = false; - for (boost::filesystem::path const& allowedDir: m_allowedDirectories) + for (boost::filesystem::path const& allowedDir: m_allowedDirectories + extraAllowedPaths) if (isPathPrefix(normalizeCLIPathForVFS(allowedDir, SymlinkResolution::Enabled), canonicalPath)) { isAllowed = true; diff --git a/test/cmdlineTests/stdin_allowed_paths/args b/test/cmdlineTests/stdin_allowed_paths/args deleted file mode 100644 index 39cdd0ded..000000000 --- a/test/cmdlineTests/stdin_allowed_paths/args +++ /dev/null @@ -1 +0,0 @@ -- diff --git a/test/cmdlineTests/stdin_allowed_paths/err b/test/cmdlineTests/stdin_allowed_paths/err deleted file mode 100644 index e25a6567c..000000000 --- a/test/cmdlineTests/stdin_allowed_paths/err +++ /dev/null @@ -1,11 +0,0 @@ -Error: Source "too_long_line/input.sol" not found: File outside of allowed directories. - --> :4:1: - | -4 | import "../too_long_line/input.sol"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Error: Source "error_codes/input.sol" not found: File outside of allowed directories. - --> stdin_allowed_paths/input.sol:4:1: - | -4 | import "../error_codes/input.sol"; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/test/cmdlineTests/stdin_allowed_paths/exit b/test/cmdlineTests/stdin_allowed_paths/exit deleted file mode 100644 index d00491fd7..000000000 --- a/test/cmdlineTests/stdin_allowed_paths/exit +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/test/cmdlineTests/stdin_allowed_paths/input.sol b/test/cmdlineTests/stdin_allowed_paths/input.sol deleted file mode 100644 index dfe1f7070..000000000 --- a/test/cmdlineTests/stdin_allowed_paths/input.sol +++ /dev/null @@ -1,4 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity >=0.0; - -import "../error_codes/input.sol"; diff --git a/test/cmdlineTests/stdin_allowed_paths/stdin b/test/cmdlineTests/stdin_allowed_paths/stdin deleted file mode 100644 index 776d152d7..000000000 --- a/test/cmdlineTests/stdin_allowed_paths/stdin +++ /dev/null @@ -1,4 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity >=0.0; - -import "../too_long_line/input.sol"; diff --git a/test/solc/CommandLineInterfaceAllowPaths.cpp b/test/solc/CommandLineInterfaceAllowPaths.cpp index ac5b2ca62..ae6e1912b 100644 --- a/test/solc/CommandLineInterfaceAllowPaths.cpp +++ b/test/solc/CommandLineInterfaceAllowPaths.cpp @@ -290,8 +290,8 @@ BOOST_FIXTURE_TEST_CASE(allow_path_should_handle_empty_paths, AllowPathsFixture) // Work dir is not base path BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "", "--base-path=../code/"})); BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "x,,y", "--base-path=../code/"})); - BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "", "--base-path=../code/"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "x,,y", "--base-path=../code/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "", "--base-path=../code/"})); + BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "x,,y", "--base-path=../code/"})); } BOOST_FIXTURE_TEST_CASE(allow_path_case_sensitive, AllowPathsFixture) @@ -459,26 +459,26 @@ BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_remappings, AllowPaths BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_base_path, AllowPathsFixture) { // Relative base path whitelists its content - BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path=../code/a"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path=../code/a"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path=../code/a"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path=../code/a"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path=../code/a"})); + BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path=../code/a"})); + BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path=../code/a"})); + BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path=../code/a"})); - BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path=../code/a/"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path=../code/a/"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path=../code/a/"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path=../code/a/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path=../code/a/"})); + BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path=../code/a/"})); + BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path=../code/a/"})); + BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path=../code/a/"})); - BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path=../code/."}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path=../code/./"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'code/a/b/c.sol'", {"--base-path=.."}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'code/a/b/c.sol'", {"--base-path=../"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path=../code/."})); + BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path=../code/./"})); + BOOST_TEST(checkImport("import 'code/a/b/c.sol'", {"--base-path=.."})); + BOOST_TEST(checkImport("import 'code/a/b/c.sol'", {"--base-path=../"})); // Absolute base path whitelists its content - BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path", m_codeDir.string() + "/a"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path", m_codeDir.string() + "/a"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path", m_codeDir.string() + "/a"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path", m_codeDir.string() + "/a"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path", m_codeDir.string() + "/a"})); + BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path", m_codeDir.string() + "/a"})); + BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path", m_codeDir.string() + "/a"})); + BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path", m_codeDir.string() + "/a"})); } BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_work_dir, AllowPathsFixture) @@ -493,16 +493,16 @@ BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_work_dir, AllowPathsFi BOOST_TEST(checkImport("import 'b/../../../work/a/b/c.sol'", {"--base-path", "../code/a/", "--allow-paths=."})); // Not setting base path whitelists the working directory - BOOST_TEST(checkImport("import 'a/b/c.sol'", {}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'a/b/c/d.sol'", {}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'a/b/X.sol'", {}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'a/X/c.sol'", {}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/b/c.sol'", {})); + BOOST_TEST(checkImport("import 'a/b/c/d.sol'", {})); + BOOST_TEST(checkImport("import 'a/b/X.sol'", {})); + BOOST_TEST(checkImport("import 'a/X/c.sol'", {})); // Setting base path to an empty value whitelists the working directory - BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path", ""}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'a/b/c/d.sol'", {"--base-path", ""}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'a/b/X.sol'", {"--base-path", ""}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import 'a/X/c.sol'", {"--base-path", ""}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path", ""})); + BOOST_TEST(checkImport("import 'a/b/c/d.sol'", {"--base-path", ""})); + BOOST_TEST(checkImport("import 'a/b/X.sol'", {"--base-path", ""})); + BOOST_TEST(checkImport("import 'a/X/c.sol'", {"--base-path", ""})); } BOOST_FIXTURE_TEST_CASE(allow_path_symlinks_within_whitelisted_dir, AllowPathsFixture) From 479ba7c52314acf69883afe29c32f6f6014699ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Sat, 24 Jul 2021 01:30:17 +0200 Subject: [PATCH 174/232] Handle allowing empty paths correctly --- libsolidity/interface/FileReader.cpp | 18 ++++++++++++++++++ libsolidity/interface/FileReader.h | 12 ++---------- solc/CommandLineParser.cpp | 5 +++-- test/solc/CommandLineInterfaceAllowPaths.cpp | 4 ++-- test/solc/CommandLineParser.cpp | 4 ++-- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/libsolidity/interface/FileReader.cpp b/libsolidity/interface/FileReader.cpp index b7ff2ce58..06a0381cf 100644 --- a/libsolidity/interface/FileReader.cpp +++ b/libsolidity/interface/FileReader.cpp @@ -33,11 +33,29 @@ using std::string; namespace solidity::frontend { +FileReader::FileReader( + boost::filesystem::path _basePath, + FileSystemPathSet _allowedDirectories +): + m_allowedDirectories(std::move(_allowedDirectories)), + m_sourceCodes() +{ + setBasePath(_basePath); + for (boost::filesystem::path const& allowedDir: m_allowedDirectories) + solAssert(!allowedDir.empty(), ""); +} + void FileReader::setBasePath(boost::filesystem::path const& _path) { m_basePath = (_path.empty() ? "" : normalizeCLIPathForVFS(_path)); } +void FileReader::allowDirectory(boost::filesystem::path _path) +{ + solAssert(!_path.empty(), ""); + m_allowedDirectories.insert(std::move(_path)); +} + void FileReader::setSource(boost::filesystem::path const& _path, SourceCode _source) { boost::filesystem::path normalizedPath = normalizeCLIPathForVFS(_path); diff --git a/libsolidity/interface/FileReader.h b/libsolidity/interface/FileReader.h index 53d4ef9b8..fe59464ad 100644 --- a/libsolidity/interface/FileReader.h +++ b/libsolidity/interface/FileReader.h @@ -46,20 +46,12 @@ public: /// Constructs a FileReader with a base path and a set of allowed directories that /// will be used when requesting files from this file reader instance. - explicit FileReader( - boost::filesystem::path _basePath = {}, - FileSystemPathSet _allowedDirectories = {} - ): - m_allowedDirectories(std::move(_allowedDirectories)), - m_sourceCodes() - { - setBasePath(_basePath); - } + explicit FileReader(boost::filesystem::path _basePath = {}, FileSystemPathSet _allowedDirectories = {}); void setBasePath(boost::filesystem::path const& _path); boost::filesystem::path const& basePath() const noexcept { return m_basePath; } - void allowDirectory(boost::filesystem::path _path) { m_allowedDirectories.insert(std::move(_path)); } + void allowDirectory(boost::filesystem::path _path); FileSystemPathSet const& allowedDirectories() const noexcept { return m_allowedDirectories; } StringMap const& sourceCodes() const noexcept { return m_sourceCodes; } diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 64fc5e630..af67c7360 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -358,7 +358,7 @@ bool CommandLineParser::parseInputPathsAndRemappings() boost::filesystem::path remappingDir = remapping->target; remappingDir.remove_filename(); - m_options.input.allowedDirectories.insert(remappingDir); + m_options.input.allowedDirectories.insert(remappingDir.empty() ? "." : remappingDir); m_options.input.remappings.emplace_back(move(remapping.value())); } @@ -979,7 +979,8 @@ bool CommandLineParser::processArgs() { vector paths; for (string const& allowedPath: boost::split(paths, m_args[g_strAllowPaths].as(), boost::is_any_of(","))) - m_options.input.allowedDirectories.insert(allowedPath); + if (!allowedPath.empty()) + m_options.input.allowedDirectories.insert(allowedPath); } if (m_args.count(g_strStopAfter)) diff --git a/test/solc/CommandLineInterfaceAllowPaths.cpp b/test/solc/CommandLineInterfaceAllowPaths.cpp index ae6e1912b..f09873d7b 100644 --- a/test/solc/CommandLineInterfaceAllowPaths.cpp +++ b/test/solc/CommandLineInterfaceAllowPaths.cpp @@ -288,8 +288,8 @@ BOOST_FIXTURE_TEST_CASE(allow_path_should_handle_empty_paths, AllowPathsFixture) BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "x,,y"}) == ImportCheck::PathDisallowed()); // Work dir is not base path - BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "", "--base-path=../code/"})); - BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "x,,y", "--base-path=../code/"})); + BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "", "--base-path=../code/"}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import 'a/../../work/a/b/c.sol'", {"--allow-paths", "x,,y", "--base-path=../code/"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "", "--base-path=../code/"})); BOOST_TEST(checkImport("import 'a/../../code/a/b/c.sol'", {"--allow-paths", "x,,y", "--base-path=../code/"})); } diff --git a/test/solc/CommandLineParser.cpp b/test/solc/CommandLineParser.cpp index 26c620f03..142ba31af 100644 --- a/test/solc/CommandLineParser.cpp +++ b/test/solc/CommandLineParser.cpp @@ -168,7 +168,7 @@ BOOST_AUTO_TEST_CASE(cli_mode_options) expectedOptions.input.addStdin = true; expectedOptions.input.basePath = "/home/user/"; - expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", "", "c", "/usr/lib"}; + expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", ".", "c", "/usr/lib"}; expectedOptions.input.ignoreMissingFiles = true; expectedOptions.input.errorRecovery = (inputMode == InputMode::Compiler); expectedOptions.output.dir = "/tmp/out"; @@ -307,7 +307,7 @@ BOOST_AUTO_TEST_CASE(assembly_mode_options) }; expectedOptions.input.addStdin = true; expectedOptions.input.basePath = "/home/user/"; - expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", "", "c", "/usr/lib"}; + expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", ".", "c", "/usr/lib"}; expectedOptions.input.ignoreMissingFiles = true; expectedOptions.output.overwriteFiles = true; expectedOptions.output.evmVersion = EVMVersion::spuriousDragon(); From 8a8471d9cc05167ca6ec0c943ff7a898dc56b9bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 21 Jul 2021 18:59:08 +0200 Subject: [PATCH 175/232] Interpret remapping targets ending with /.. as directories --- solc/CommandLineParser.cpp | 7 ++++++- test/solc/CommandLineInterfaceAllowPaths.cpp | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index af67c7360..62611eac1 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -356,8 +356,13 @@ bool CommandLineParser::parseInputPathsAndRemappings() return false; } + // If the target is a directory, whitelist it. Otherwise whitelist containing dir. + // NOTE: /a/b/c/ is a directory while /a/b/c is not. boost::filesystem::path remappingDir = remapping->target; - remappingDir.remove_filename(); + if (remappingDir.filename() != "..") + // As an exception we'll treat /a/b/c/.. as a directory too. It would be + // unintuitive to whitelist /a/b/c when the target is equivalent to /a/b/. + remappingDir.remove_filename(); m_options.input.allowedDirectories.insert(remappingDir.empty() ? "." : remappingDir); m_options.input.remappings.emplace_back(move(remapping.value())); diff --git a/test/solc/CommandLineInterfaceAllowPaths.cpp b/test/solc/CommandLineInterfaceAllowPaths.cpp index f09873d7b..b69639d3c 100644 --- a/test/solc/CommandLineInterfaceAllowPaths.cpp +++ b/test/solc/CommandLineInterfaceAllowPaths.cpp @@ -428,14 +428,14 @@ BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_remappings, AllowPaths BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=./"}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=./"}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=.."}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=.."}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=.."})); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=.."})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../"})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../"})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./.."})); - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./.."}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/X/c.sol'", {"x=../code/a/b/./.."})); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/X/b/c.sol'", {"x=../code/a/b/./.."}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"x=../code/a/b/./../"})); From c0b83787821e0e2f609a0b92884e3b8c071e6afb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 23 Jul 2021 20:27:50 +0200 Subject: [PATCH 176/232] Do not whitelist any paths if remapping target is empty --- solc/CommandLineParser.cpp | 19 +++++++++++-------- test/solc/CommandLineInterfaceAllowPaths.cpp | 2 +- test/solc/CommandLineParser.cpp | 4 ++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 62611eac1..d74bcbf04 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -356,14 +356,17 @@ bool CommandLineParser::parseInputPathsAndRemappings() return false; } - // If the target is a directory, whitelist it. Otherwise whitelist containing dir. - // NOTE: /a/b/c/ is a directory while /a/b/c is not. - boost::filesystem::path remappingDir = remapping->target; - if (remappingDir.filename() != "..") - // As an exception we'll treat /a/b/c/.. as a directory too. It would be - // unintuitive to whitelist /a/b/c when the target is equivalent to /a/b/. - remappingDir.remove_filename(); - m_options.input.allowedDirectories.insert(remappingDir.empty() ? "." : remappingDir); + if (!remapping->target.empty()) + { + // If the target is a directory, whitelist it. Otherwise whitelist containing dir. + // NOTE: /a/b/c/ is a directory while /a/b/c is not. + boost::filesystem::path remappingDir = remapping->target; + if (remappingDir.filename() != "..") + // As an exception we'll treat /a/b/c/.. as a directory too. It would be + // unintuitive to whitelist /a/b/c when the target is equivalent to /a/b/. + remappingDir.remove_filename(); + m_options.input.allowedDirectories.insert(remappingDir.empty() ? "." : remappingDir); + } m_options.input.remappings.emplace_back(move(remapping.value())); } diff --git a/test/solc/CommandLineInterfaceAllowPaths.cpp b/test/solc/CommandLineInterfaceAllowPaths.cpp index b69639d3c..bf6cf81bc 100644 --- a/test/solc/CommandLineInterfaceAllowPaths.cpp +++ b/test/solc/CommandLineInterfaceAllowPaths.cpp @@ -418,7 +418,7 @@ BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_remappings, AllowPaths // Adding a remapping with an empty target does not whitelist anything BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "="}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"../code/="}) == ImportCheck::PathDisallowed()); - BOOST_TEST(checkImport("import '/../work/a/b/c.sol'", {"../code/=", "--base-path", m_portablePrefix})); + BOOST_TEST(checkImport("import '/../work/a/b/c.sol'", {"../code/=", "--base-path", m_portablePrefix}) == ImportCheck::PathDisallowed()); // Adding a remapping that includes .. or . segments whitelists the parent dir and subdirectories // of the resolved target diff --git a/test/solc/CommandLineParser.cpp b/test/solc/CommandLineParser.cpp index 142ba31af..5644aaadd 100644 --- a/test/solc/CommandLineParser.cpp +++ b/test/solc/CommandLineParser.cpp @@ -168,7 +168,7 @@ BOOST_AUTO_TEST_CASE(cli_mode_options) expectedOptions.input.addStdin = true; expectedOptions.input.basePath = "/home/user/"; - expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", ".", "c", "/usr/lib"}; + expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", "c", "/usr/lib"}; expectedOptions.input.ignoreMissingFiles = true; expectedOptions.input.errorRecovery = (inputMode == InputMode::Compiler); expectedOptions.output.dir = "/tmp/out"; @@ -307,7 +307,7 @@ BOOST_AUTO_TEST_CASE(assembly_mode_options) }; expectedOptions.input.addStdin = true; expectedOptions.input.basePath = "/home/user/"; - expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", ".", "c", "/usr/lib"}; + expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", "c", "/usr/lib"}; expectedOptions.input.ignoreMissingFiles = true; expectedOptions.output.overwriteFiles = true; expectedOptions.output.evmVersion = EVMVersion::spuriousDragon(); From 60b2f2b9138ad8a1b39e2ea7f1c294905d4f23ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 21 Jul 2021 20:19:28 +0200 Subject: [PATCH 177/232] Documentation for --allow-paths and changelog entry for fixes --- Changelog.md | 1 + docs/path-resolution.rst | 68 ++++++++++++++++++++++++++++++++++++- docs/using-the-compiler.rst | 7 ++-- 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/Changelog.md b/Changelog.md index 7d07627f2..d301ef522 100644 --- a/Changelog.md +++ b/Changelog.md @@ -21,6 +21,7 @@ Bugfixes: * Code Generator: Fix ICE on assigning to calldata structs and statically-sized calldata arrays in inline assembly. * Code Generator: Use stable source order for ABI functions. * Commandline Interface: Disallow the ``--experimental-via-ir`` option in Standard JSON, Assembler and Linker modes. + * Commandline Interface: Fix resolution of paths whitelisted with ``--allowed-paths`` or implicitly due to base path, remappings and files being compiled. Correctly handle paths that do not match imports exactly due to being relative, non-normalized or empty. * Commandline Interface: Report optimizer options as invalid in Standard JSON and linker modes instead of ignoring them. * Name Resolver: Fix that when importing an aliased symbol using ``import {AliasedName} from "a.sol"`` it would use the original name of the symbol and not the aliased one. * Opcode Optimizer: Prevent the optimizer from running multiple times to avoid potential bytecode differences for referenced code. diff --git a/docs/path-resolution.rst b/docs/path-resolution.rst index 470bfbf31..0ace3a461 100644 --- a/docs/path-resolution.rst +++ b/docs/path-resolution.rst @@ -297,7 +297,7 @@ Here are some examples of what you can expect if they are not: The same effect can be achieved in a more reliable way by using direct imports with :ref:`base path ` and :ref:`import remapping `. -.. index:: ! base path, --base-path +.. index:: ! base path, ! --base-path .. _base-path: Base Path @@ -373,6 +373,72 @@ The resulting file path becomes the source unit name. When working with older versions of the compiler it is recommended to invoke the compiler from the base path and to only use relative paths on the command line. +.. index:: ! allowed paths, ! --allow-paths, remapping; target +.. _allowed-paths: + +Allowed Paths +============= + +As a security measure, the Host Filesystem Loader will refuse to load files from outside of a few +locations that are considered safe by default: + +- Outside of Standard JSON mode: + + - The directories containing input files listed on the command line. + - The directories used as :ref:`remapping ` targets. + If the target is not a directory (i.e does not end with ``/``, ``/.`` or ``/..``) the directory + containing the target is used instead. + - Base path. + +- In Standard JSON mode: + + - Base path. + +Additional directories can be whitelisted using the ``--allow-paths`` option. +The option accepts a comma-separated list of paths: + +.. code-block:: bash + + cd /home/user/project/ + solc token/contract.sol \ + lib/util.sol=libs/util.sol \ + --base-path=token/ \ + --allow-paths=../utils/,/tmp/libraries + +When the compiler is invoked with the command shown above, the Host Filesystem Loader will allow +importing files from the following directories: + +- ``/home/user/project/token/`` (because ``token/`` contains the input file and also because it is + the base path), +- ``/home/user/project/libs/`` (because ``libs/`` is a directory containing a remapping target), +- ``/home/user/utils/`` (because of ``../utils/`` passed to ``--allow-paths``), +- ``/tmp/libraries/`` (because of ``/tmp/libraries`` passed to ``--allow-paths``), + +.. note:: + + The working directory of the compiler is one of the paths allowed by default only if it + happens to be the base path (or the base path is not specified or has an empty value). + +.. note:: + + The compiler does not check if allowed paths actually exist and whether they are directories. + Non-existent or empty paths are simply ignored. + If an allowed path matches a file rather than a directory, the file is considered whitelisted, too. + +.. note:: + + Allowed paths are case-sensitive even if the filesystem is not. + The case must exactly match the one used in your imports. + For example ``--allow-paths tokens`` will not match ``import "Tokens/IERC20.sol"``. + +.. warning:: + + Files and directories only reachable through symbolic links from allowed directories are not + automatically whitelisted. + For example if ``token/contract.sol`` in the example above was actually a symlink pointing at + ``/etc/passwd`` the compiler would refuse to load it unless ``/etc/`` was one of the allowed + paths too. + .. index:: ! remapping; import, ! import; remapping, ! remapping; context, ! remapping; prefix, ! remapping; target .. _import-remapping: diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 5245991fd..406af7c9b 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -47,16 +47,13 @@ it is also possible to provide :ref:`path redirects ` using `` This essentially instructs the compiler to search for anything starting with ``github.com/ethereum/dapp-bin/`` under ``/usr/local/lib/dapp-bin``. -``solc`` will not read files from the filesystem that lie outside of -the remapping targets and outside of the directories where explicitly specified source -files reside, so things like ``import "/etc/passwd";`` only work if you add ``/=/`` as a remapping. When accessing the filesystem to search for imports, :ref:`paths that do not start with ./ -or ../ ` are treated as relative to the directory specified using +or ../ ` are treated as relative to the directory specified using ``--base-path`` option (or the current working directory if base path is not specified). Furthermore, the part added via ``--base-path`` will not appear in the contract metadata. -For security reasons the compiler has restrictions on what directories it can access. +For security reasons the compiler has :ref:`restrictions on what directories it can access `. Directories of source files specified on the command line and target paths of remappings are automatically allowed to be accessed by the file reader, but everything else is rejected by default. From d4d778de771e19774eb60f9060f52d75fa3952d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Wed, 4 Aug 2021 16:57:19 +0200 Subject: [PATCH 178/232] Disable tests that fail on Windows due to a bug in Boost <= 1.76 --- test/libsolidity/interface/FileReader.cpp | 26 ++++++++++++++------ test/solc/CommandLineInterfaceAllowPaths.cpp | 3 +++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/test/libsolidity/interface/FileReader.cpp b/test/libsolidity/interface/FileReader.cpp index 866a4435a..64886903c 100644 --- a/test/libsolidity/interface/FileReader.cpp +++ b/test/libsolidity/interface/FileReader.cpp @@ -58,13 +58,16 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_absolute_path) BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b", resolveSymlinks), "/a/b"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/", resolveSymlinks), "/a/b/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/./b/", resolveSymlinks), "/a/b/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../a/b/", resolveSymlinks), "/a/b/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/..", resolveSymlinks), "/a/b"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../", resolveSymlinks), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/./b/", resolveSymlinks), "/a/b/"); +#if !defined(_WIN32) || BOOST_VERSION > 107600 + // This throws on Windows due to a bug in Boost: https://github.com/boostorg/filesystem/issues/201 + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../a/b/", resolveSymlinks), "/a/b/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../../", resolveSymlinks), "/"); +#endif } } @@ -108,16 +111,20 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_relative_path) BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/b", resolveSymlinks), expectedPrefix / "x/y/z/a/b"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("././a/b", resolveSymlinks), expectedPrefix / "x/y/z/a/b"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/./b/", resolveSymlinks), expectedPrefix / "x/y/z/a/b/"); + +#if !defined(_WIN32) || BOOST_VERSION > 107600 + // This throws on Windows due to a bug in Boost: https://github.com/boostorg/filesystem/issues/201 + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/.././../p/../q/../a/b", resolveSymlinks), expectedPrefix / "a/b"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../a/b/", resolveSymlinks), expectedPrefix / "x/y/z/a/b/"); +#endif + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/./b/", resolveSymlinks), expectedPrefix / "x/y/z/a/b/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/..", resolveSymlinks), expectedPrefix / "x/y/z/a/b"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../", resolveSymlinks), expectedPrefix / "x/y/z/a/b/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/..//", resolveSymlinks), expectedPrefix / "x/y/z/a/b/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../..", resolveSymlinks), expectedPrefix / "x/y/z/a"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../../", resolveSymlinks), expectedPrefix / "x/y/z/a/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../..//", resolveSymlinks), expectedPrefix / "x/y/z/a/"); - - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/.././../p/../q/../a/b", resolveSymlinks), expectedPrefix / "a/b"); } } @@ -233,26 +240,31 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_beyond_root) BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../.", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a", resolveSymlinks), "/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a", resolveSymlinks), "/a"); +#if !defined(_WIN32) || BOOST_VERSION > 107600 + // This throws on Windows due to a bug in Boost: https://github.com/boostorg/filesystem/issues/201 BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/../..", resolveSymlinks), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a", resolveSymlinks), "/a"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/../..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../../b/../..", resolveSymlinks), "/"); +#endif BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../.", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a", resolveSymlinks), "/a"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a", resolveSymlinks), "/a"); +#if !defined(_WIN32) || BOOST_VERSION > 107600 BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/../..", resolveSymlinks), "/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a", resolveSymlinks), "/a"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/../..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../../b/../..", resolveSymlinks), "/"); +#endif } } diff --git a/test/solc/CommandLineInterfaceAllowPaths.cpp b/test/solc/CommandLineInterfaceAllowPaths.cpp index bf6cf81bc..f3401f967 100644 --- a/test/solc/CommandLineInterfaceAllowPaths.cpp +++ b/test/solc/CommandLineInterfaceAllowPaths.cpp @@ -272,7 +272,10 @@ BOOST_FIXTURE_TEST_CASE(allow_path_should_work_with_various_path_forms, AllowPat // Paths going beyond root allowed BOOST_TEST(checkImport(import, {"--allow-paths=/../../"})); BOOST_TEST(checkImport(import, {"--allow-paths=/../.."})); +#if !defined(_WIN32) || BOOST_VERSION > 107600 + // This throws on Windows due to a bug in Boost: https://github.com/boostorg/filesystem/issues/201 BOOST_TEST(checkImport(import, {"--allow-paths=/../../a/../"})); +#endif BOOST_TEST(checkImport(import, {"--allow-paths=/../../" + m_portablePrefix})); // File named like a directory From a61a950861012943083444cbe595e83d5601e0ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Mon, 30 Aug 2021 20:17:19 +0200 Subject: [PATCH 179/232] createFilesWithParentDirs(): Use binary mode to preserve original newlines on Windows --- test/FilesystemUtils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/FilesystemUtils.cpp b/test/FilesystemUtils.cpp index 159568c62..0235b1147 100644 --- a/test/FilesystemUtils.cpp +++ b/test/FilesystemUtils.cpp @@ -31,7 +31,8 @@ void solidity::test::createFilesWithParentDirs(set cons if (!path.parent_path().empty()) boost::filesystem::create_directories(path.parent_path()); - ofstream newFile(path.string()); + // Use binary mode to avoid line ending conversion on Windows. + ofstream newFile(path.string(), std::ofstream::binary); newFile << _content; if (newFile.fail() || !boost::filesystem::exists(path)) From c8a7a1da7ce507885e37377fc431e61f17216577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 20 Aug 2021 19:17:44 +0200 Subject: [PATCH 180/232] Add --include-path option --- Changelog.md | 3 +- docs/path-resolution.rst | 67 ++++- docs/using-the-compiler.rst | 8 +- libsolidity/interface/FileReader.cpp | 62 +++- libsolidity/interface/FileReader.h | 20 +- solc/CommandLineInterface.cpp | 3 + solc/CommandLineParser.cpp | 30 ++ solc/CommandLineParser.h | 1 + test/solc/CommandLineInterface.cpp | 290 +++++++++++++++++++ test/solc/CommandLineInterfaceAllowPaths.cpp | 35 ++- test/solc/CommandLineParser.cpp | 10 + 11 files changed, 498 insertions(+), 31 deletions(-) diff --git a/Changelog.md b/Changelog.md index d301ef522..0d5822e13 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,8 +7,9 @@ Language Features: Compiler Features: + * Commandline Interface: Add ``--include-path`` option for specifying extra directories that may contain importable code (e.g. packaged third-party libraries). * Commandline Interface: Do not implicitly run evm bytecode generation unless needed for the requested output. - * Commandline Interface: Normalize paths specified on the command line and make them relative for files located inside base path. + * Commandline Interface: Normalize paths specified on the command line and make them relative for files located inside base path and/or include paths. * Immutable variables can be read at construction time once they are initialized. * SMTChecker: Support low level ``call`` as external calls to unknown code. * SMTChecker: Add constraints to better correlate ``address(this).balance`` and ``msg.value``. diff --git a/docs/path-resolution.rst b/docs/path-resolution.rst index 0ace3a461..6dff6985e 100644 --- a/docs/path-resolution.rst +++ b/docs/path-resolution.rst @@ -72,8 +72,9 @@ The initial content of the VFS depends on how you invoke the compiler: solc contract.sol /usr/local/dapp-bin/token.sol The source unit name of a file loaded this way is constructed by converting its path to a - canonical form and making it relative to the base path if it is located inside. - See :ref:`Base Path Normalization and Stripping ` for + canonical form and, if possible, making it relative to either the base path or one of the + include paths. + See :ref:`CLI Path Normalization and Stripping ` for a detailed description of this process. .. index:: standard JSON @@ -295,16 +296,36 @@ Here are some examples of what you can expect if they are not: The use of relative imports containing leading ``..`` segments is not recommended. The same effect can be achieved in a more reliable way by using direct imports with - :ref:`base path ` and :ref:`import remapping `. + :ref:`base path and include paths `. -.. index:: ! base path, ! --base-path -.. _base-path: +.. index:: ! base path, ! --base-path, ! include paths, ! --include-path +.. _base-and-include-paths: -Base Path -========= +Base Path and Include Paths +=========================== -The base path specifies the directory that the Host Filesystem Loader will load files from. -It is simply prepended to a source unit name before the filesystem lookup is performed. +The base path and include paths represent directories that the Host Filesystem Loader will load files from. +When a source unit name is passed to the loader, it prepends the base path to it and performs a +filesystem lookup. +If the lookup does not succeed, the same is done with all directories on the include path list. + +It is recommended to set the base path to the root directory of your project and use include paths to +specify additional locations that may contain libraries your project depends on. +This lets you import from these libraries in a uniform way, no matter where they are located in the +filesystem relative to your project. +For example, if you use npm to install packages and your contract imports +``@openzeppelin/contracts/utils/Strings.sol``, you can use these options to tell the compiler that +the library can be found in one of the npm package directories: + +.. code-block:: bash + + solc contract.sol \ + --base-path . \ + --include-path node_modules/ \ + --include-path /usr/local/lib/node_modules/ + +Your contract will compile (with the same exact metadata) no matter whether you install the library +in the local or global package directory or even directly under your project root. By default the base path is empty, which leaves the source unit name unchanged. When the source unit name is a relative path, this results in the file being looked up in the @@ -314,10 +335,14 @@ interpreted as absolute paths on disk. If the base path itself is relative, it is interpreted as relative to the current working directory of the compiler. -.. _base-path-normalization-and-stripping: +.. note:: -Base Path Normalization and Stripping -------------------------------------- + Include paths cannot have empty values and must be used together with a non-empty base path. + +.. _cli-path-normalization-and-stripping: + +CLI Path Normalization and Stripping +------------------------------------ On the command line the compiler behaves just as you would expect from any other program: it accepts paths in a format native to the platform and relative paths are relative to the current @@ -326,7 +351,7 @@ The source unit names assigned to files whose paths are specified on the command should not change just because the project is being compiled on a different platform or because the compiler happens to have been invoked from a different directory. To achieve this, paths to source files coming from the command line must be converted to a canonical -form, and, if possible, made relative to the base path. +form, and, if possible, made relative to the base path or one of the include paths. The normalization rules are as follows: @@ -357,7 +382,8 @@ The normalization rules are as follows: You can avoid such situations by ensuring that all the files are available within a single directory tree on the same drive. -Once canonicalized, the base path is stripped from all source file paths that start with it. +After normalization the compiler attempts to make the source file path relative. +It tries the base path first and then the include paths in the order they were given. If the base path is empty or not specified, it is treated as if it was equal to the path to the current working directory (with all symbolic links resolved). The result is accepted only if the normalized directory path is the exact prefix of the normalized @@ -388,11 +414,11 @@ locations that are considered safe by default: - The directories used as :ref:`remapping ` targets. If the target is not a directory (i.e does not end with ``/``, ``/.`` or ``/..``) the directory containing the target is used instead. - - Base path. + - Base path and include paths. - In Standard JSON mode: - - Base path. + - Base path and include paths. Additional directories can be whitelisted using the ``--allow-paths`` option. The option accepts a comma-separated list of paths: @@ -403,6 +429,7 @@ The option accepts a comma-separated list of paths: solc token/contract.sol \ lib/util.sol=libs/util.sol \ --base-path=token/ \ + --include-path=/lib/ \ --allow-paths=../utils/,/tmp/libraries When the compiler is invoked with the command shown above, the Host Filesystem Loader will allow @@ -410,6 +437,7 @@ importing files from the following directories: - ``/home/user/project/token/`` (because ``token/`` contains the input file and also because it is the base path), +- ``/lib/`` (because ``/lib/`` is one of the include paths), - ``/home/user/project/libs/`` (because ``libs/`` is a directory containing a remapping target), - ``/home/user/utils/`` (because of ``../utils/`` passed to ``--allow-paths``), - ``/tmp/libraries/`` (because of ``/tmp/libraries`` passed to ``--allow-paths``), @@ -492,6 +520,13 @@ Loader, which will then look in ``/project/dapp-bin/library/iterable_mapping.sol would need to recreate parts of your local directory structure in the VFS and (if you rely on Host Filesystem Loader) also in the host filesystem. + To avoid having your local directory structure embedded in the metadata, it is recommended to + designate the directories containing libraries as *include paths* instead. + For example, in the example above ``--include-path /home/user/packages/`` would let you use + imports starting with ``mymath/``. + Unlike remapping, the option on its own will not make ``mymath`` appear as ``@math`` but this + can be achieved by creating a symbolic link or renaming the package subdirectory. + As a more complex example, suppose you rely on a module that uses an old version of dapp-bin that you checked out to ``/project/dapp-bin_old``, then you can run: diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 406af7c9b..1b14187ca 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -33,7 +33,7 @@ This parameter has effects on the following (this might change in the future): - the size of the binary search in the function dispatch routine - the way constants like large numbers or strings are stored -.. index:: allowed paths, --allow-paths, base path, --base-path +.. index:: allowed paths, --allow-paths, base path, --base-path, include paths, --include-path Base Path and Import Remapping ------------------------------ @@ -49,9 +49,9 @@ This essentially instructs the compiler to search for anything starting with ``github.com/ethereum/dapp-bin/`` under ``/usr/local/lib/dapp-bin``. When accessing the filesystem to search for imports, :ref:`paths that do not start with ./ -or ../ ` are treated as relative to the directory specified using -``--base-path`` option (or the current working directory if base path is not specified). -Furthermore, the part added via ``--base-path`` will not appear in the contract metadata. +or ../ ` are treated as relative to the directories specified using +``--base-path`` and ``--include-path`` options (or the current working directory if base path is not specified). +Furthermore, the part of the path added via these options will not appear in the contract metadata. For security reasons the compiler has :ref:`restrictions on what directories it can access `. Directories of source files specified on the command line and target paths of diff --git a/libsolidity/interface/FileReader.cpp b/libsolidity/interface/FileReader.cpp index 06a0381cf..0588b9a02 100644 --- a/libsolidity/interface/FileReader.cpp +++ b/libsolidity/interface/FileReader.cpp @@ -24,30 +24,54 @@ #include +#include + +#include + using solidity::frontend::ReadCallback; using solidity::langutil::InternalCompilerError; using solidity::util::errinfo_comment; using solidity::util::readFileAsString; +using std::reference_wrapper; using std::string; +using std::vector; namespace solidity::frontend { FileReader::FileReader( boost::filesystem::path _basePath, + vector const& _includePaths, FileSystemPathSet _allowedDirectories ): m_allowedDirectories(std::move(_allowedDirectories)), m_sourceCodes() { setBasePath(_basePath); + for (boost::filesystem::path const& includePath: _includePaths) + addIncludePath(includePath); + for (boost::filesystem::path const& allowedDir: m_allowedDirectories) solAssert(!allowedDir.empty(), ""); } void FileReader::setBasePath(boost::filesystem::path const& _path) { - m_basePath = (_path.empty() ? "" : normalizeCLIPathForVFS(_path)); + if (_path.empty()) + { + // Empty base path is a special case that does not make sense when include paths are used. + solAssert(m_includePaths.empty(), ""); + m_basePath = ""; + } + else + m_basePath = normalizeCLIPathForVFS(_path); +} + +void FileReader::addIncludePath(boost::filesystem::path const& _path) +{ + solAssert(!m_basePath.empty(), ""); + solAssert(!_path.empty(), ""); + m_includePaths.push_back(normalizeCLIPathForVFS(_path)); } void FileReader::allowDirectory(boost::filesystem::path _path) @@ -58,10 +82,7 @@ void FileReader::allowDirectory(boost::filesystem::path _path) void FileReader::setSource(boost::filesystem::path const& _path, SourceCode _source) { - boost::filesystem::path normalizedPath = normalizeCLIPathForVFS(_path); - boost::filesystem::path prefix = (m_basePath.empty() ? normalizeCLIPathForVFS(".") : m_basePath); - - m_sourceCodes[stripPrefixIfPresent(prefix, normalizedPath).generic_string()] = std::move(_source); + m_sourceCodes[cliPathToSourceUnitName(_path)] = std::move(_source); } void FileReader::setStdin(SourceCode _source) @@ -87,8 +108,20 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so if (strippedSourceUnitName.find("file://") == 0) strippedSourceUnitName.erase(0, 7); - auto canonicalPath = normalizeCLIPathForVFS(m_basePath / strippedSourceUnitName, SymlinkResolution::Enabled); + vector> prefixes = {m_basePath}; + prefixes += (m_includePaths | ranges::to>>); + + boost::filesystem::path canonicalPath; + for (auto const& prefix: prefixes) + { + canonicalPath = normalizeCLIPathForVFS(prefix / strippedSourceUnitName, SymlinkResolution::Enabled); + + if (boost::filesystem::exists(canonicalPath)) + break; + } + FileSystemPathSet extraAllowedPaths = {m_basePath.empty() ? "." : m_basePath}; + extraAllowedPaths += m_includePaths; bool isAllowed = false; for (boost::filesystem::path const& allowedDir: m_allowedDirectories + extraAllowedPaths) @@ -126,6 +159,23 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so } } +string FileReader::cliPathToSourceUnitName(boost::filesystem::path const& _cliPath) +{ + vector prefixes = {m_basePath.empty() ? normalizeCLIPathForVFS(".") : m_basePath}; + prefixes += m_includePaths; + + boost::filesystem::path normalizedPath = normalizeCLIPathForVFS(_cliPath); + for (boost::filesystem::path const& prefix: prefixes) + if (isPathPrefix(prefix, normalizedPath)) + { + // Multiple prefixes can potentially match the path. We take the first one. + normalizedPath = stripPrefixIfPresent(prefix, normalizedPath); + break; + } + + return normalizedPath.generic_string(); +} + boost::filesystem::path FileReader::normalizeCLIPathForVFS( boost::filesystem::path const& _path, SymlinkResolution _symlinkResolution diff --git a/libsolidity/interface/FileReader.h b/libsolidity/interface/FileReader.h index fe59464ad..50f30c9df 100644 --- a/libsolidity/interface/FileReader.h +++ b/libsolidity/interface/FileReader.h @@ -44,13 +44,20 @@ public: Enabled, ///< Follow symbolic links. The path should contain no symlinks. }; - /// Constructs a FileReader with a base path and a set of allowed directories that - /// will be used when requesting files from this file reader instance. - explicit FileReader(boost::filesystem::path _basePath = {}, FileSystemPathSet _allowedDirectories = {}); + /// Constructs a FileReader with a base path and sets of include paths and allowed directories + /// that will be used when requesting files from this file reader instance. + explicit FileReader( + boost::filesystem::path _basePath = {}, + std::vector const& _includePaths = {}, + FileSystemPathSet _allowedDirectories = {} + ); void setBasePath(boost::filesystem::path const& _path); boost::filesystem::path const& basePath() const noexcept { return m_basePath; } + void addIncludePath(boost::filesystem::path const& _path); + std::vector const& includePaths() const noexcept { return m_includePaths; } + void allowDirectory(boost::filesystem::path _path); FileSystemPathSet const& allowedDirectories() const noexcept { return m_allowedDirectories; } @@ -85,6 +92,10 @@ public: return [this](std::string const& _kind, std::string const& _path) { return readFile(_kind, _path); }; } + /// Creates a source unit name by normalizing a path given on the command line and, if possible, + /// making it relative to base path or one of the include directories. + std::string cliPathToSourceUnitName(boost::filesystem::path const& _cliPath); + /// Normalizes a filesystem path to make it include all components up to the filesystem root, /// remove small, inconsequential differences that do not affect the meaning and make it look /// the same on all platforms (if possible). @@ -130,6 +141,9 @@ private: /// Base path, used for resolving relative paths in imports. boost::filesystem::path m_basePath; + /// Additional directories used for resolving relative paths in imports. + std::vector m_includePaths; + /// list of allowed directories to read files from FileSystemPathSet m_allowedDirectories; diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 3399a86fb..6af1b11fb 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -422,6 +422,9 @@ bool CommandLineInterface::readInputFiles() } } + for (boost::filesystem::path const& includePath: m_options.input.includePaths) + m_fileReader.addIncludePath(includePath); + for (boost::filesystem::path const& allowedDirectory: m_options.input.allowedDirectories) m_fileReader.allowDirectory(allowedDirectory); diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index d74bcbf04..059a15a5f 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -54,6 +54,7 @@ ostream& CommandLineParser::serr() static string const g_strAbi = "abi"; static string const g_strAllowPaths = "allow-paths"; static string const g_strBasePath = "base-path"; +static string const g_strIncludePath = "include-path"; static string const g_strAsm = "asm"; static string const g_strAsmJson = "asm-json"; static string const g_strAssemble = "assemble"; @@ -273,6 +274,7 @@ bool CommandLineOptions::operator==(CommandLineOptions const& _other) const noex input.remappings == _other.input.remappings && input.addStdin == _other.input.addStdin && input.basePath == _other.input.basePath && + input.includePaths == _other.input.includePaths && input.allowedDirectories == _other.input.allowedDirectories && input.ignoreMissingFiles == _other.input.ignoreMissingFiles && input.errorRecovery == _other.input.errorRecovery && @@ -532,6 +534,15 @@ General Information)").c_str(), po::value()->value_name("path"), "Use the given path as the root of the source tree instead of the root of the filesystem." ) + ( + g_strIncludePath.c_str(), + po::value>()->value_name("path"), + "Make an additional source directory available to the default import callback. " + "Use this option if you want to import contracts whose location is not fixed in relation " + "to your main source tree, e.g. third-party libraries installed using a package manager. " + "Can be used multiple times. " + "Can only be used if base path has a non-empty value." + ) ( g_strAllowPaths.c_str(), po::value()->value_name("path(s)"), @@ -983,6 +994,25 @@ bool CommandLineParser::processArgs() if (m_args.count(g_strBasePath)) m_options.input.basePath = m_args[g_strBasePath].as(); + if (m_args.count(g_strIncludePath) > 0) + { + if (m_options.input.basePath.empty()) + { + serr() << "--" << g_strIncludePath << " option requires a non-empty base path." << endl; + return false; + } + + for (string const& includePath: m_args[g_strIncludePath].as>()) + { + if (includePath.empty()) + { + serr() << "Empty values are not allowed in --" << g_strIncludePath << "." << endl; + return false; + } + m_options.input.includePaths.push_back(includePath); + } + } + if (m_args.count(g_strAllowPaths)) { vector paths; diff --git a/solc/CommandLineParser.h b/solc/CommandLineParser.h index 41aaab71b..4159e2ac2 100644 --- a/solc/CommandLineParser.h +++ b/solc/CommandLineParser.h @@ -111,6 +111,7 @@ struct CommandLineOptions std::vector remappings; bool addStdin = false; boost::filesystem::path basePath = ""; + std::vector includePaths; FileReader::FileSystemPathSet allowedDirectories; bool ignoreMissingFiles = false; bool errorRecovery = false; diff --git a/test/solc/CommandLineInterface.cpp b/test/solc/CommandLineInterface.cpp index b76d86ee8..dff834242 100644 --- a/test/solc/CommandLineInterface.cpp +++ b/test/solc/CommandLineInterface.cpp @@ -27,6 +27,8 @@ #include #include +#include + #include #include @@ -868,6 +870,294 @@ BOOST_AUTO_TEST_CASE(cli_paths_to_source_unit_names_base_path_and_stdin) BOOST_TEST(result.reader.basePath() == expectedWorkDir / "base"); } +BOOST_AUTO_TEST_CASE(cli_include_paths) +{ + TemporaryDirectory tempDir({"base/", "include/", "lib/nested/"}, TEST_CASE_NAME); + TemporaryWorkingDirectory tempWorkDir(tempDir); + + string const preamble = + "// SPDX-License-Identifier: GPL-3.0\n" + "pragma solidity >=0.0;\n"; + string const mainContractSource = preamble + + "import \"contract.sol\";\n" + "import \"contract_via_callback.sol\";\n" + "import \"include.sol\";\n" + "import \"include_via_callback.sol\";\n" + "import \"nested.sol\";\n" + "import \"nested_via_callback.sol\";\n" + "import \"lib.sol\";\n" + "import \"lib_via_callback.sol\";\n"; + + createFilesWithParentDirs( + { + tempDir.path() / "base/contract.sol", + tempDir.path() / "base/contract_via_callback.sol", + tempDir.path() / "include/include.sol", + tempDir.path() / "include/include_via_callback.sol", + tempDir.path() / "lib/nested/nested.sol", + tempDir.path() / "lib/nested/nested_via_callback.sol", + tempDir.path() / "lib/lib.sol", + tempDir.path() / "lib/lib_via_callback.sol", + }, + preamble + ); + createFilesWithParentDirs({tempDir.path() / "base/main.sol"}, mainContractSource); + + boost::filesystem::path canonicalWorkDir = boost::filesystem::canonical(tempDir); + boost::filesystem::path expectedWorkDir = "/" / canonicalWorkDir.relative_path(); + + vector commandLine = { + "solc", + "--no-color", + "--base-path=base/", + "--include-path=include/", + "--include-path=lib/nested", + "--include-path=lib/", + "base/main.sol", + "base/contract.sol", + "include/include.sol", + "lib/nested/nested.sol", + "lib/lib.sol", + }; + + CommandLineOptions expectedOptions; + expectedOptions.input.paths = { + "base/main.sol", + "base/contract.sol", + "include/include.sol", + "lib/nested/nested.sol", + "lib/lib.sol", + }; + expectedOptions.input.basePath = "base/"; + expectedOptions.input.includePaths = { + "include/", + "lib/nested", + "lib/", + }; + expectedOptions.formatting.coloredOutput = false; + expectedOptions.modelChecker.initialize = true; + + map expectedSources = { + {"main.sol", mainContractSource}, + {"contract.sol", preamble}, + {"contract_via_callback.sol", preamble}, + {"include.sol", preamble}, + {"include_via_callback.sol", preamble}, + {"nested.sol", preamble}, + {"nested_via_callback.sol", preamble}, + {"lib.sol", preamble}, + {"lib_via_callback.sol", preamble}, + }; + + vector expectedIncludePaths = { + expectedWorkDir / "include/", + expectedWorkDir / "lib/nested", + expectedWorkDir / "lib/", + }; + + FileReader::FileSystemPathSet expectedAllowedDirectories = { + canonicalWorkDir / "base", + canonicalWorkDir / "include", + canonicalWorkDir / "lib/nested", + canonicalWorkDir / "lib", + }; + + OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles( + commandLine, + "", + true /* _processInput */ + ); + + BOOST_TEST(result.stderrContent == ""); + BOOST_TEST(result.stdoutContent == ""); + BOOST_REQUIRE(result.success); + BOOST_TEST(result.options == expectedOptions); + BOOST_TEST(result.reader.sourceCodes() == expectedSources); + BOOST_TEST(result.reader.includePaths() == expectedIncludePaths); + BOOST_TEST(result.reader.allowedDirectories() == expectedAllowedDirectories); + BOOST_TEST(result.reader.basePath() == expectedWorkDir / "base/"); +} + +BOOST_AUTO_TEST_CASE(standard_json_include_paths) +{ + TemporaryDirectory tempDir({"base/", "include/", "lib/nested/"}, TEST_CASE_NAME); + TemporaryWorkingDirectory tempWorkDir(tempDir); + + string const preamble = + "// SPDX-License-Identifier: GPL-3.0\n" + "pragma solidity >=0.0;\n"; + string const mainContractSource = preamble + + "import 'contract_via_callback.sol';\n" + "import 'include_via_callback.sol';\n" + "import 'nested_via_callback.sol';\n" + "import 'lib_via_callback.sol';\n"; + + string const standardJsonInput = R"( + { + "language": "Solidity", + "sources": { + "main.sol": {"content": ")" + mainContractSource + R"("} + } + } + )"; + + createFilesWithParentDirs( + { + tempDir.path() / "base/contract_via_callback.sol", + tempDir.path() / "include/include_via_callback.sol", + tempDir.path() / "lib/nested/nested_via_callback.sol", + tempDir.path() / "lib/lib_via_callback.sol", + }, + preamble + ); + + boost::filesystem::path expectedWorkDir = "/" / boost::filesystem::canonical(tempDir).relative_path(); + + vector commandLine = { + "solc", + "--base-path=base/", + "--include-path=include/", + "--include-path=lib/nested", + "--include-path=lib/", + "--standard-json", + }; + + CommandLineOptions expectedOptions; + expectedOptions.input.mode = InputMode::StandardJson; + expectedOptions.input.paths = {}; + expectedOptions.input.addStdin = true; + expectedOptions.input.basePath = "base/"; + expectedOptions.input.includePaths = { + "include/", + "lib/nested", + "lib/", + }; + expectedOptions.modelChecker.initialize = false; + + // NOTE: Source code from Standard JSON does not end up in FileReader. This is not a problem + // because FileReader is only used once to initialize the compiler stack and after that + // its sources are irrelevant (even though the callback still stores everything it loads). + map expectedSources = { + {"contract_via_callback.sol", preamble}, + {"include_via_callback.sol", preamble}, + {"nested_via_callback.sol", preamble}, + {"lib_via_callback.sol", preamble}, + }; + + vector expectedIncludePaths = { + expectedWorkDir / "include/", + expectedWorkDir / "lib/nested", + expectedWorkDir / "lib/", + }; + + FileReader::FileSystemPathSet expectedAllowedDirectories = {}; + + OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles( + commandLine, + standardJsonInput, + true /* _processInput */ + ); + + Json::Value parsedStdout; + string jsonParsingErrors; + BOOST_TEST(util::jsonParseStrict(result.stdoutContent, parsedStdout, &jsonParsingErrors)); + BOOST_TEST(jsonParsingErrors == ""); + for (Json::Value const& errorDict: parsedStdout["errors"]) + // The error list might contain pre-release compiler warning + BOOST_TEST(errorDict["severity"] != "error"); + BOOST_TEST( + (parsedStdout["sources"].getMemberNames() | ranges::to) == + (expectedSources | ranges::views::keys | ranges::to) + set{"main.sol"} + ); + + BOOST_REQUIRE(result.success); + BOOST_TEST(result.options == expectedOptions); + BOOST_TEST(result.reader.sourceCodes() == expectedSources); + BOOST_TEST(result.reader.includePaths() == expectedIncludePaths); + BOOST_TEST(result.reader.allowedDirectories() == expectedAllowedDirectories); + BOOST_TEST(result.reader.basePath() == expectedWorkDir / "base/"); +} + +BOOST_AUTO_TEST_CASE(cli_include_paths_empty_path) +{ + TemporaryDirectory tempDir({"base/", "include/"}, TEST_CASE_NAME); + TemporaryWorkingDirectory tempWorkDir(tempDir); + createFilesWithParentDirs({tempDir.path() / "base/main.sol"}); + + string expectedMessage = "Empty values are not allowed in --include-path.\n"; + + vector commandLine = { + "solc", + "--base-path=base/", + "--include-path", "include/", + "--include-path", "", + "base/main.sol", + }; + OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(commandLine); + BOOST_TEST(!result.success); + BOOST_TEST(result.stderrContent == expectedMessage); +} + +BOOST_AUTO_TEST_CASE(cli_include_paths_without_base_path) +{ + TemporaryDirectory tempDir(TEST_CASE_NAME); + TemporaryWorkingDirectory tempWorkDir(tempDir); + createFilesWithParentDirs({tempDir.path() / "contract.sol"}); + + string expectedMessage = "--include-path option requires a non-empty base path.\n"; + + vector commandLine = {"solc", "--include-path", "include/", "contract.sol"}; + OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(commandLine); + BOOST_TEST(!result.success); + BOOST_TEST(result.stderrContent == expectedMessage); +} + +BOOST_AUTO_TEST_CASE(cli_include_paths_should_allow_duplicate_paths) +{ + TemporaryDirectory tempDir({"dir1/", "dir2/"}, TEST_CASE_NAME); + TemporaryWorkingDirectory tempWorkDir(tempDir); + createFilesWithParentDirs({"dir1/contract.sol"}); + + boost::filesystem::path expectedWorkDir = "/" / boost::filesystem::canonical(tempDir).relative_path(); + boost::filesystem::path expectedTempDir = "/" / tempDir.path().relative_path(); + + vector commandLine = { + "solc", + "--base-path=dir1/", + "--include-path", "dir1", + "--include-path", "dir1", + "--include-path", "dir1/", + "--include-path", "dir1/", + "--include-path", "./dir1/", + "--include-path", "dir2/../dir1/", + "--include-path", (tempDir.path() / "dir1/").string(), + "--include-path", (expectedWorkDir / "dir1/").string(), + "--include-path", "dir1/", + "dir1/contract.sol", + }; + + // Duplicates do not affect the result but are not removed from the include path list. + vector expectedIncludePaths = { + expectedWorkDir / "dir1", + expectedWorkDir / "dir1", + expectedWorkDir / "dir1/", + expectedWorkDir / "dir1/", + expectedWorkDir / "dir1/", + expectedWorkDir / "dir1/", + // NOTE: On macOS expectedTempDir usually contains a symlink and therefore for us it's + // different from expectedWorkDir. + expectedTempDir / "dir1/", + expectedWorkDir / "dir1/", + expectedWorkDir / "dir1/", + }; + + OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(commandLine); + BOOST_TEST(result.stderrContent == ""); + BOOST_REQUIRE(result.success); + BOOST_TEST(result.reader.includePaths() == expectedIncludePaths); + BOOST_TEST(result.reader.basePath() == expectedWorkDir / "dir1/"); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace solidity::frontend::test diff --git a/test/solc/CommandLineInterfaceAllowPaths.cpp b/test/solc/CommandLineInterfaceAllowPaths.cpp index f3401f967..d48471acf 100644 --- a/test/solc/CommandLineInterfaceAllowPaths.cpp +++ b/test/solc/CommandLineInterfaceAllowPaths.cpp @@ -76,6 +76,7 @@ ImportCheck checkImport( for (string const& option: _cliOptions) soltestAssert( boost::starts_with(option, "--base-path") || + boost::starts_with(option, "--include-path") || boost::starts_with(option, "--allow-paths") || !boost::starts_with(option, "--"), "" @@ -146,6 +147,7 @@ protected: m_codeDir / "X/bc/d.sol", m_codeDir / "x/y/z.sol", + m_codeDir / "1/2/3.sol", m_codeDir / "contract.sol", m_workDir / "a/b/c/d.sol", @@ -419,7 +421,7 @@ BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_remappings, AllowPaths BOOST_TEST(checkImport("import '/../../../work/a/b/c.sol'", {"x=contract.sol/", "--base-path=../code/a/b/"}) == ImportCheck::PathDisallowed()); // Adding a remapping with an empty target does not whitelist anything - BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "="}) == ImportCheck::PathDisallowed()); + BOOST_TEST(checkImport("import '" + m_portablePrefix + m_portablePrefix + "/a/b/c.sol'", {m_portablePrefix + "="}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b/c.sol'", {"../code/="}) == ImportCheck::PathDisallowed()); BOOST_TEST(checkImport("import '/../work/a/b/c.sol'", {"../code/=", "--base-path", m_portablePrefix}) == ImportCheck::PathDisallowed()); @@ -508,6 +510,37 @@ BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_work_dir, AllowPathsFi BOOST_TEST(checkImport("import 'a/X/c.sol'", {"--base-path", ""})); } +BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_include_paths, AllowPathsFixture) +{ + // Relative include path whitelists its content + BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path=a/b/c", "--include-path=../code/a"})); + BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path=a/b/c", "--include-path=../code/a"})); + BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path=a/b/c", "--include-path=../code/a"})); + BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path=a/b/c", "--include-path=../code/a"})); + + BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path=a/b/c", "--include-path=../code/a/"})); + BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path=a/b/c", "--include-path=../code/a/"})); + BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path=a/b/c", "--include-path=../code/a/"})); + BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path=a/b/c", "--include-path=../code/a/"})); + + BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path=a/b/c", "--include-path=../code/."})); + BOOST_TEST(checkImport("import 'a/b/c.sol'", {"--base-path=a/b/c", "--include-path=../code/./"})); + BOOST_TEST(checkImport("import 'code/a/b/c.sol'", {"--base-path=a/b/c", "--include-path=.."})); + BOOST_TEST(checkImport("import 'code/a/b/c.sol'", {"--base-path=a/b/c", "--include-path=../"})); + + // Absolute include path whitelists its content + BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path=a/b/c", "--include-path", m_codeDir.string() + "/a"})); + BOOST_TEST(checkImport("import 'b/c/d.sol'", {"--base-path=a/b/c", "--include-path", m_codeDir.string() + "/a"})); + BOOST_TEST(checkImport("import 'b/X.sol'", {"--base-path=a/b/c", "--include-path", m_codeDir.string() + "/a"})); + BOOST_TEST(checkImport("import 'X/c.sol'", {"--base-path=a/b/c", "--include-path", m_codeDir.string() + "/a"})); + + // If there are multiple include paths, all of them get whitelisted + BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path=a/b/c", "--include-path=../code/a", "--include-path=../code/1"})); + BOOST_TEST(checkImport("import '2/3.sol'", {"--base-path=a/b/c", "--include-path=../code/a", "--include-path=../code/1"})); + BOOST_TEST(checkImport("import 'b/c.sol'", {"--base-path=a/b/c", "--include-path=../code/1", "--include-path=../code/a"})); + BOOST_TEST(checkImport("import '2/3.sol'", {"--base-path=a/b/c", "--include-path=../code/1", "--include-path=../code/a"})); +} + BOOST_FIXTURE_TEST_CASE(allow_path_symlinks_within_whitelisted_dir, AllowPathsFixture) { BOOST_TEST(checkImport("import '" + m_portablePrefix + "/a/b_sym/c.sol'", {"--allow-paths=../code/a/b/"})); diff --git a/test/solc/CommandLineParser.cpp b/test/solc/CommandLineParser.cpp index 5644aaadd..7b1dd375b 100644 --- a/test/solc/CommandLineParser.cpp +++ b/test/solc/CommandLineParser.cpp @@ -117,6 +117,8 @@ BOOST_AUTO_TEST_CASE(cli_mode_options) "a:b=c/d", ":contract.sol=", "--base-path=/home/user/", + "--include-path=/usr/lib/include/", + "--include-path=/home/user/include", "--allow-paths=/tmp,/home,project,../contracts", "--ignore-missing", "--error-recovery", @@ -168,6 +170,8 @@ BOOST_AUTO_TEST_CASE(cli_mode_options) expectedOptions.input.addStdin = true; expectedOptions.input.basePath = "/home/user/"; + expectedOptions.input.includePaths = {"/usr/lib/include/", "/home/user/include"}; + expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", "c", "/usr/lib"}; expectedOptions.input.ignoreMissingFiles = true; expectedOptions.input.errorRecovery = (inputMode == InputMode::Compiler); @@ -257,6 +261,8 @@ BOOST_AUTO_TEST_CASE(assembly_mode_options) "a:b=c/d", ":contract.yul=", "--base-path=/home/user/", + "--include-path=/usr/lib/include/", + "--include-path=/home/user/include", "--allow-paths=/tmp,/home,project,../contracts", "--ignore-missing", "--error-recovery", // Ignored in assembly mode @@ -307,6 +313,7 @@ BOOST_AUTO_TEST_CASE(assembly_mode_options) }; expectedOptions.input.addStdin = true; expectedOptions.input.basePath = "/home/user/"; + expectedOptions.input.includePaths = {"/usr/lib/include/", "/home/user/include"}; expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", "c", "/usr/lib"}; expectedOptions.input.ignoreMissingFiles = true; expectedOptions.output.overwriteFiles = true; @@ -350,6 +357,8 @@ BOOST_AUTO_TEST_CASE(standard_json_mode_options) "input.json", "--standard-json", "--base-path=/home/user/", + "--include-path=/usr/lib/include/", + "--include-path=/home/user/include", "--allow-paths=/tmp,/home,project,../contracts", "--ignore-missing", "--error-recovery", // Ignored in Standard JSON mode @@ -390,6 +399,7 @@ BOOST_AUTO_TEST_CASE(standard_json_mode_options) expectedOptions.input.mode = InputMode::StandardJson; expectedOptions.input.paths = {"input.json"}; expectedOptions.input.basePath = "/home/user/"; + expectedOptions.input.includePaths = {"/usr/lib/include/", "/home/user/include"}; expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts"}; expectedOptions.input.ignoreMissingFiles = true; expectedOptions.output.dir = "/tmp/out"; From 9975b5e26b5a17ac648e4bedf1d4796eb08ca45e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 26 Aug 2021 18:34:34 +0200 Subject: [PATCH 181/232] Detect source unit name collisions between paths specified on the command line --- docs/path-resolution.rst | 10 ++++ libsolidity/interface/FileReader.cpp | 19 ++++++ libsolidity/interface/FileReader.h | 7 +++ solc/CommandLineInterface.cpp | 18 ++++++ test/solc/CommandLineInterface.cpp | 89 ++++++++++++++++++++++++++++ 5 files changed, 143 insertions(+) diff --git a/docs/path-resolution.rst b/docs/path-resolution.rst index 6dff6985e..f1a246788 100644 --- a/docs/path-resolution.rst +++ b/docs/path-resolution.rst @@ -392,6 +392,16 @@ Otherwise the file path remains absolute. This makes the conversion unambiguous and ensures that the relative path does not start with ``../``. The resulting file path becomes the source unit name. +.. note:: + + The relative path produced by stripping must remain unique within the base path and include paths. + For example the compiler will issue an error for the following command if both + ``/project/contract.sol`` and ``/lib/contract.sol`` exist: + + .. code-block:: bash + + solc /project/contract.sol --base-path /project --include-path /lib + .. note:: Prior to version 0.8.8, CLI path stripping was not performed and the only normalization applied diff --git a/libsolidity/interface/FileReader.cpp b/libsolidity/interface/FileReader.cpp index 0588b9a02..4d60b8083 100644 --- a/libsolidity/interface/FileReader.cpp +++ b/libsolidity/interface/FileReader.cpp @@ -32,6 +32,7 @@ using solidity::frontend::ReadCallback; using solidity::langutil::InternalCompilerError; using solidity::util::errinfo_comment; using solidity::util::readFileAsString; +using std::map; using std::reference_wrapper; using std::string; using std::vector; @@ -176,6 +177,24 @@ string FileReader::cliPathToSourceUnitName(boost::filesystem::path const& _cliPa return normalizedPath.generic_string(); } +map FileReader::detectSourceUnitNameCollisions(FileSystemPathSet const& _cliPaths) +{ + map nameToPaths; + for (boost::filesystem::path const& cliPath: _cliPaths) + { + string sourceUnitName = cliPathToSourceUnitName(cliPath); + boost::filesystem::path normalizedPath = normalizeCLIPathForVFS(cliPath); + nameToPaths[sourceUnitName].insert(normalizedPath); + } + + map collisions; + for (auto&& [sourceUnitName, cliPaths]: nameToPaths) + if (cliPaths.size() >= 2) + collisions[sourceUnitName] = std::move(cliPaths); + + return collisions; +} + boost::filesystem::path FileReader::normalizeCLIPathForVFS( boost::filesystem::path const& _path, SymlinkResolution _symlinkResolution diff --git a/libsolidity/interface/FileReader.h b/libsolidity/interface/FileReader.h index 50f30c9df..71f5819df 100644 --- a/libsolidity/interface/FileReader.h +++ b/libsolidity/interface/FileReader.h @@ -96,6 +96,13 @@ public: /// making it relative to base path or one of the include directories. std::string cliPathToSourceUnitName(boost::filesystem::path const& _cliPath); + /// Checks if a set contains any paths that lead to different files but would receive identical + /// source unit names. Files are considered the same if their paths are exactly the same after + /// normalization (without following symlinks). + /// @returns a map containing all the conflicting source unit names and the paths that would + /// receive them. The returned paths are normalized. + std::map detectSourceUnitNameCollisions(FileSystemPathSet const& _cliPaths); + /// Normalizes a filesystem path to make it include all components up to the filesystem root, /// remove small, inconsequential differences that do not affect the meaning and make it look /// the same on all platforms (if possible). diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 6af1b11fb..dfe5cfc5c 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -428,6 +428,24 @@ bool CommandLineInterface::readInputFiles() for (boost::filesystem::path const& allowedDirectory: m_options.input.allowedDirectories) m_fileReader.allowDirectory(allowedDirectory); + map> collisions = + m_fileReader.detectSourceUnitNameCollisions(m_options.input.paths); + if (!collisions.empty()) + { + auto pathToQuotedString = [](boost::filesystem::path const& _path){ return "\"" + _path.string() + "\""; }; + + serr() << "Source unit name collision detected. "; + serr() << "The specified values of base path and/or include paths would result in multiple "; + serr() << "input files being assigned the same source unit name:" << endl; + for (auto const& [sourceUnitName, normalizedInputPaths]: collisions) + { + serr() << sourceUnitName << " matches: "; + serr() << joinHumanReadable(normalizedInputPaths | ranges::views::transform(pathToQuotedString)) << endl; + } + + return false; + } + for (boost::filesystem::path const& infile: m_options.input.paths) { if (!boost::filesystem::exists(infile)) diff --git a/test/solc/CommandLineInterface.cpp b/test/solc/CommandLineInterface.cpp index dff834242..7d7470db5 100644 --- a/test/solc/CommandLineInterface.cpp +++ b/test/solc/CommandLineInterface.cpp @@ -1112,6 +1112,95 @@ BOOST_AUTO_TEST_CASE(cli_include_paths_without_base_path) BOOST_TEST(result.stderrContent == expectedMessage); } +BOOST_AUTO_TEST_CASE(cli_include_paths_should_detect_source_unit_name_collisions) +{ + TemporaryDirectory tempDir({"dir1/", "dir2/", "dir3/"}, TEST_CASE_NAME); + TemporaryWorkingDirectory tempWorkDir(tempDir); + createFilesWithParentDirs({ + "dir1/contract1.sol", + "dir1/contract2.sol", + "dir2/contract1.sol", + "dir2/contract2.sol", + }); + + boost::filesystem::path expectedWorkDir = "/" / boost::filesystem::canonical(tempDir).relative_path(); + + string expectedMessage = + "Source unit name collision detected. " + "The specified values of base path and/or include paths would result in multiple " + "input files being assigned the same source unit name:\n" + "contract1.sol matches: " + "\"" + (expectedWorkDir / "dir1/contract1.sol").generic_string() + "\", " + "\"" + (expectedWorkDir / "dir2/contract1.sol").generic_string() + "\"\n" + "contract2.sol matches: " + "\"" + (expectedWorkDir / "dir1/contract2.sol").generic_string() + "\", " + "\"" + (expectedWorkDir / "dir2/contract2.sol").generic_string() + "\"\n"; + + { + // import "contract1.sol" and import "contract2.sol" would be ambiguous: + vector commandLine = { + "solc", + "--base-path=dir1/", + "--include-path=dir2/", + "dir1/contract1.sol", + "dir2/contract1.sol", + "dir1/contract2.sol", + "dir2/contract2.sol", + }; + OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(commandLine); + BOOST_TEST(result.stderrContent == expectedMessage); + BOOST_REQUIRE(!result.success); + } + + { + // import "contract1.sol" and import "contract2.sol" would be ambiguous: + vector commandLine = { + "solc", + "--base-path=dir3/", + "--include-path=dir1/", + "--include-path=dir2/", + "dir1/contract1.sol", + "dir2/contract1.sol", + "dir1/contract2.sol", + "dir2/contract2.sol", + }; + OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(commandLine); + BOOST_TEST(result.stderrContent == expectedMessage); + BOOST_REQUIRE(!result.success); + } + + { + // No conflict if files with the same name exist but only one is given to the compiler. + vector commandLine = { + "solc", + "--base-path=dir3/", + "--include-path=dir1/", + "--include-path=dir2/", + "dir1/contract1.sol", + "dir1/contract2.sol", + }; + OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(commandLine); + BOOST_TEST(result.stderrContent == ""); + BOOST_REQUIRE(result.success); + } + + { + // The same file specified multiple times is not a conflict. + vector commandLine = { + "solc", + "--base-path=dir3/", + "--include-path=dir1/", + "--include-path=dir2/", + "dir1/contract1.sol", + "dir1/contract1.sol", + "./dir1/contract1.sol", + }; + OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(commandLine); + BOOST_TEST(result.stderrContent == ""); + BOOST_REQUIRE(result.success); + } +} + BOOST_AUTO_TEST_CASE(cli_include_paths_should_allow_duplicate_paths) { TemporaryDirectory tempDir({"dir1/", "dir2/"}, TEST_CASE_NAME); From f909555022152188338e70a1409fd4f87bea6237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 26 Aug 2021 18:35:25 +0200 Subject: [PATCH 182/232] Treat ambiguous imports as errors --- docs/path-resolution.rst | 9 ++++ libsolidity/interface/FileReader.cpp | 33 +++++++++++---- test/solc/CommandLineInterface.cpp | 44 ++++++++++++++++++++ test/solc/CommandLineInterfaceAllowPaths.cpp | 6 ++- 4 files changed, 82 insertions(+), 10 deletions(-) diff --git a/docs/path-resolution.rst b/docs/path-resolution.rst index f1a246788..40a727068 100644 --- a/docs/path-resolution.rst +++ b/docs/path-resolution.rst @@ -339,6 +339,15 @@ of the compiler. Include paths cannot have empty values and must be used together with a non-empty base path. +.. note:: + + Include paths and base path can overlap as long as it does not make import resolution ambiguous. + For example, you can specify a directory inside base path as an include directory or have an + include directory that is a subdirectory of another include directory. + The compiler will only issue an error if the source unit name passed to the Host Filesystem + Loader represents an existing path when combined with multiple include paths or an include path + and base path. + .. _cli-path-normalization-and-stripping: CLI Path Normalization and Stripping diff --git a/libsolidity/interface/FileReader.cpp b/libsolidity/interface/FileReader.cpp index 4d60b8083..2a1859d21 100644 --- a/libsolidity/interface/FileReader.cpp +++ b/libsolidity/interface/FileReader.cpp @@ -21,8 +21,10 @@ #include #include +#include #include +#include #include @@ -32,6 +34,7 @@ using solidity::frontend::ReadCallback; using solidity::langutil::InternalCompilerError; using solidity::util::errinfo_comment; using solidity::util::readFileAsString; +using solidity::util::joinHumanReadable; using std::map; using std::reference_wrapper; using std::string; @@ -109,24 +112,38 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so if (strippedSourceUnitName.find("file://") == 0) strippedSourceUnitName.erase(0, 7); + vector candidates; vector> prefixes = {m_basePath}; prefixes += (m_includePaths | ranges::to>>); - boost::filesystem::path canonicalPath; for (auto const& prefix: prefixes) { - canonicalPath = normalizeCLIPathForVFS(prefix / strippedSourceUnitName, SymlinkResolution::Enabled); + boost::filesystem::path canonicalPath = normalizeCLIPathForVFS(prefix / strippedSourceUnitName, SymlinkResolution::Enabled); if (boost::filesystem::exists(canonicalPath)) - break; + candidates.push_back(std::move(canonicalPath)); } + auto pathToQuotedString = [](boost::filesystem::path const& _path){ return "\"" + _path.string() + "\""; }; + + if (candidates.empty()) + return ReadCallback::Result{false, "File not found."}; + + if (candidates.size() >= 2) + return ReadCallback::Result{ + false, + "Ambiguous import. " + "Multiple matching files found inside base path and/or include paths: " + + joinHumanReadable(candidates | ranges::views::transform(pathToQuotedString), ", ") + + "." + }; + FileSystemPathSet extraAllowedPaths = {m_basePath.empty() ? "." : m_basePath}; extraAllowedPaths += m_includePaths; bool isAllowed = false; for (boost::filesystem::path const& allowedDir: m_allowedDirectories + extraAllowedPaths) - if (isPathPrefix(normalizeCLIPathForVFS(allowedDir, SymlinkResolution::Enabled), canonicalPath)) + if (isPathPrefix(normalizeCLIPathForVFS(allowedDir, SymlinkResolution::Enabled), candidates[0])) { isAllowed = true; break; @@ -135,14 +152,12 @@ ReadCallback::Result FileReader::readFile(string const& _kind, string const& _so if (!isAllowed) return ReadCallback::Result{false, "File outside of allowed directories."}; - if (!boost::filesystem::exists(canonicalPath)) - return ReadCallback::Result{false, "File not found."}; - - if (!boost::filesystem::is_regular_file(canonicalPath)) + if (!boost::filesystem::is_regular_file(candidates[0])) return ReadCallback::Result{false, "Not a valid file."}; // NOTE: we ignore the FileNotFound exception as we manually check above - auto contents = readFileAsString(canonicalPath); + auto contents = readFileAsString(candidates[0]); + solAssert(m_sourceCodes.count(_sourceUnitName) == 0, ""); m_sourceCodes[_sourceUnitName] = contents; return ReadCallback::Result{true, contents}; } diff --git a/test/solc/CommandLineInterface.cpp b/test/solc/CommandLineInterface.cpp index 7d7470db5..126a1cd09 100644 --- a/test/solc/CommandLineInterface.cpp +++ b/test/solc/CommandLineInterface.cpp @@ -1247,6 +1247,50 @@ BOOST_AUTO_TEST_CASE(cli_include_paths_should_allow_duplicate_paths) BOOST_TEST(result.reader.basePath() == expectedWorkDir / "dir1/"); } +BOOST_AUTO_TEST_CASE(cli_include_paths_ambiguous_import) +{ + TemporaryDirectory tempDir({"base/", "include/"}, TEST_CASE_NAME); + TemporaryWorkingDirectory tempWorkDir(tempDir); + + string const preamble = + "// SPDX-License-Identifier: GPL-3.0\n" + "pragma solidity >=0.0;\n"; + string const mainContractSource = preamble + + // Ambiguous: both base/contract.sol and include/contract.sol match the import. + "import \"contract.sol\";"; + + createFilesWithParentDirs({"base/contract.sol", "include/contract.sol"}, preamble); + + boost::filesystem::path expectedWorkDir = "/" / boost::filesystem::canonical(tempDir).relative_path(); + + vector commandLine = { + "solc", + "--no-color", + "--base-path=base/", + "--include-path=include/", + "-", + }; + + string expectedMessage = + "Error: Source \"contract.sol\" not found: Ambiguous import. " + "Multiple matching files found inside base path and/or include paths: \"" + + (expectedWorkDir / "base/contract.sol").generic_string() + "\", \"" + + (expectedWorkDir / "include/contract.sol").generic_string() + "\".\n" + " --> :3:1:\n" + " |\n" + "3 | import \"contract.sol\";\n" + " | ^^^^^^^^^^^^^^^^^^^^^^\n\n"; + + OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles( + commandLine, + mainContractSource, + true /* _processInput */ + ); + + BOOST_TEST(result.stderrContent == expectedMessage); + BOOST_REQUIRE(!result.success); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace solidity::frontend::test diff --git a/test/solc/CommandLineInterfaceAllowPaths.cpp b/test/solc/CommandLineInterfaceAllowPaths.cpp index d48471acf..215085699 100644 --- a/test/solc/CommandLineInterfaceAllowPaths.cpp +++ b/test/solc/CommandLineInterfaceAllowPaths.cpp @@ -344,10 +344,14 @@ BOOST_FIXTURE_TEST_CASE(allow_path_should_work_with_various_import_forms, AllowP BOOST_TEST(checkImport("import 'a/../../code/a/../a/b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"})); BOOST_TEST(checkImport("import 'a/../../code/a///b/c.sol'", {"--allow-paths", "../code/a/b/c.sol"})); - // UNC paths in imports +#if !defined(_WIN32) + // UNC paths in imports. + // Unfortunately can't test it on Windows without having an existing UNC path. On Linux we can + // at least rely on the fact that `//` works like `/`. string uncImportPath = "/" + m_portablePrefix + "/a/b/c.sol"; soltestAssert(FileReader::isUNCPath(uncImportPath), ""); BOOST_TEST(checkImport("import '" + uncImportPath + "'", {"--allow-paths", "../code/a/b/c.sol"}) == ImportCheck::PathDisallowed()); +#endif } BOOST_FIXTURE_TEST_CASE(allow_path_automatic_whitelisting_input_files, AllowPathsFixture) From e3a3829f97da0699615bf4ba6b30ef173cb69049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 24 Sep 2021 14:17:13 +0200 Subject: [PATCH 183/232] Increase minimum Boost version to 1.77 on Windows --- cmake/EthDependencies.cmake | 13 ++++++++++--- docs/installing-solidity.rst | 5 ++++- scripts/install_deps.ps1 | 6 +++--- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index 04cb876be..7a84a01d9 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -25,13 +25,20 @@ set(ETH_SCRIPTS_DIR ${ETH_CMAKE_DIR}/scripts) ## use multithreaded boost libraries, with -mt suffix set(Boost_USE_MULTITHREADED ON) option(Boost_USE_STATIC_LIBS "Link Boost statically" ON) -if(WIN32) +if (WIN32) option(Boost_USE_STATIC_RUNTIME "Link Boost against static C++ runtime libraries" ON) endif() set(BOOST_COMPONENTS "filesystem;unit_test_framework;program_options;system") -find_package(Boost 1.65.0 QUIET REQUIRED COMPONENTS ${BOOST_COMPONENTS}) +if (WIN32) + # Boost 1.77 fixes a bug that causes crashes on Windows for some relative paths in --allow-paths. + # See https://github.com/boostorg/filesystem/issues/201 + find_package(Boost 1.77.0 QUIET REQUIRED COMPONENTS ${BOOST_COMPONENTS}) +else() + # Boost 1.65 is the first to also provide boost::get for rvalue-references (#5787). + find_package(Boost 1.65.0 QUIET REQUIRED COMPONENTS ${BOOST_COMPONENTS}) +endif() # If cmake is older than boost and boost is older than 1.70, # find_package does not define imported targets, so we have to @@ -51,7 +58,7 @@ foreach (BOOST_COMPONENT IN LISTS BOOST_COMPONENTS) set_property(TARGET Boost::${BOOST_COMPONENT} PROPERTY IMPORTED_LOCATION ${Boost_${BOOST_COMPONENT_UPPER}_LIBRARY}) set_property(TARGET Boost::${BOOST_COMPONENT} PROPERTY INTERFACE_LINK_LIBRARIES ${Boost_${BOOST_COMPONENT_UPPER}_LIBRARIES}) set_property(TARGET Boost::${BOOST_COMPONENT} PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIRS}) - endif() + endif() get_property(LOCATION TARGET Boost::${BOOST_COMPONENT} PROPERTY IMPORTED_LOCATION) message(STATUS "Found Boost::${BOOST_COMPONENT} at ${LOCATION}") endforeach() diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst index a0857e038..dbd0954c9 100644 --- a/docs/installing-solidity.rst +++ b/docs/installing-solidity.rst @@ -313,7 +313,8 @@ The following are dependencies for all builds of Solidity: +===================================+=======================================================+ | `CMake`_ (version 3.13+) | Cross-platform build file generator. | +-----------------------------------+-------------------------------------------------------+ -| `Boost`_ (version 1.65+) | C++ libraries. | +| `Boost`_ (version 1.77+ on | C++ libraries. | +| Windows, 1.65+ otherwise) | | +-----------------------------------+-------------------------------------------------------+ | `Git`_ | Command-line tool for retrieving source code. | +-----------------------------------+-------------------------------------------------------+ @@ -378,6 +379,8 @@ You need to install the following dependencies for Windows builds of Solidity: +-----------------------------------+-------------------------------------------------------+ | `Visual Studio 2019`_ (Optional) | C++ compiler and dev environment. | +-----------------------------------+-------------------------------------------------------+ +| `Boost`_ (version 1.77+) | C++ libraries. | ++-----------------------------------+-------------------------------------------------------+ If you already have one IDE and only need the compiler and libraries, you could install Visual Studio 2019 Build Tools. diff --git a/scripts/install_deps.ps1 b/scripts/install_deps.ps1 index 00c439e3a..e7726993c 100644 --- a/scripts/install_deps.ps1 +++ b/scripts/install_deps.ps1 @@ -15,12 +15,12 @@ if ( -not (Test-Path "$PSScriptRoot\..\deps\boost") ) { # FIXME: The default user agent results in Artifactory treating Invoke-WebRequest as a browser # and serving it a page that requires JavaScript. - Invoke-WebRequest -URI "https://boostorg.jfrog.io/artifactory/main/release/1.74.0/source/boost_1_74_0.zip" -OutFile boost.zip -UserAgent "" - if ((Get-FileHash boost.zip).Hash -ne "a0e7ce67c52d816708fdeccdd8c9725626ba61254c13c18770498cacd514710a") { + Invoke-WebRequest -URI "https://boostorg.jfrog.io/artifactory/main/release/1.77.0/source/boost_1_77_0.zip" -OutFile boost.zip -UserAgent "" + if ((Get-FileHash boost.zip).Hash -ne "d2886ceff60c35fc6dc9120e8faa960c1e9535f2d7ce447469eae9836110ea77") { throw 'Downloaded Boost source package has wrong checksum.' } tar -xf boost.zip - cd boost_1_74_0 + cd boost_1_77_0 .\bootstrap.bat .\b2 -j4 -d0 link=static runtime-link=static variant=release threading=multi address-model=64 --with-filesystem --with-system --with-program_options --with-test --prefix="$PSScriptRoot\..\deps\boost" install if ( -not $? ) { throw "Error building boost." } From 77aa1707e13a8cb1a60f7a83d5b27a3af4daa76e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 24 Sep 2021 15:28:48 +0200 Subject: [PATCH 184/232] Revert "Disable tests that fail on Windows due to a bug in Boost <= 1.76" This reverts commit a801c12a8b89a7353a4339510aedc94739e9c46f. --- test/libsolidity/interface/FileReader.cpp | 26 ++++++-------------- test/solc/CommandLineInterfaceAllowPaths.cpp | 3 --- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/test/libsolidity/interface/FileReader.cpp b/test/libsolidity/interface/FileReader.cpp index 64886903c..866a4435a 100644 --- a/test/libsolidity/interface/FileReader.cpp +++ b/test/libsolidity/interface/FileReader.cpp @@ -58,16 +58,13 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_absolute_path) BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b", resolveSymlinks), "/a/b"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/", resolveSymlinks), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/./b/", resolveSymlinks), "/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../a/b/", resolveSymlinks), "/a/b/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/..", resolveSymlinks), "/a/b"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../", resolveSymlinks), "/a/b/"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/./b/", resolveSymlinks), "/a/b/"); -#if !defined(_WIN32) || BOOST_VERSION > 107600 - // This throws on Windows due to a bug in Boost: https://github.com/boostorg/filesystem/issues/201 - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../a/b/", resolveSymlinks), "/a/b/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/b/c/../../../", resolveSymlinks), "/"); -#endif } } @@ -111,20 +108,16 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_relative_path) BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("./a/b", resolveSymlinks), expectedPrefix / "x/y/z/a/b"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("././a/b", resolveSymlinks), expectedPrefix / "x/y/z/a/b"); - -#if !defined(_WIN32) || BOOST_VERSION > 107600 - // This throws on Windows due to a bug in Boost: https://github.com/boostorg/filesystem/issues/201 - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/.././../p/../q/../a/b", resolveSymlinks), expectedPrefix / "a/b"); - - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../a/b/", resolveSymlinks), expectedPrefix / "x/y/z/a/b/"); -#endif BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/./b/", resolveSymlinks), expectedPrefix / "x/y/z/a/b/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../a/b/", resolveSymlinks), expectedPrefix / "x/y/z/a/b/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/..", resolveSymlinks), expectedPrefix / "x/y/z/a/b"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../", resolveSymlinks), expectedPrefix / "x/y/z/a/b/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/..//", resolveSymlinks), expectedPrefix / "x/y/z/a/b/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../..", resolveSymlinks), expectedPrefix / "x/y/z/a"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../../", resolveSymlinks), expectedPrefix / "x/y/z/a/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/b/c/../..//", resolveSymlinks), expectedPrefix / "x/y/z/a/"); + + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/.././../p/../q/../a/b", resolveSymlinks), expectedPrefix / "a/b"); } } @@ -240,31 +233,26 @@ BOOST_AUTO_TEST_CASE(normalizeCLIPathForVFS_path_beyond_root) BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../.", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a", resolveSymlinks), "/a"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a", resolveSymlinks), "/a"); -#if !defined(_WIN32) || BOOST_VERSION > 107600 - // This throws on Windows due to a bug in Boost: https://github.com/boostorg/filesystem/issues/201 BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../a/../..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a", resolveSymlinks), "/a"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/../../a/../..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("/a/../../b/../..", resolveSymlinks), "/"); -#endif BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../.", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a", resolveSymlinks), "/a"); - BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a", resolveSymlinks), "/a"); -#if !defined(_WIN32) || BOOST_VERSION > 107600 BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../a/../..", resolveSymlinks), "/"); + BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a", resolveSymlinks), "/a"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("../../a/../..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../..", resolveSymlinks), "/"); BOOST_CHECK_EQUAL(FileReader::normalizeCLIPathForVFS("a/../../b/../..", resolveSymlinks), "/"); -#endif } } diff --git a/test/solc/CommandLineInterfaceAllowPaths.cpp b/test/solc/CommandLineInterfaceAllowPaths.cpp index f3401f967..bf6cf81bc 100644 --- a/test/solc/CommandLineInterfaceAllowPaths.cpp +++ b/test/solc/CommandLineInterfaceAllowPaths.cpp @@ -272,10 +272,7 @@ BOOST_FIXTURE_TEST_CASE(allow_path_should_work_with_various_path_forms, AllowPat // Paths going beyond root allowed BOOST_TEST(checkImport(import, {"--allow-paths=/../../"})); BOOST_TEST(checkImport(import, {"--allow-paths=/../.."})); -#if !defined(_WIN32) || BOOST_VERSION > 107600 - // This throws on Windows due to a bug in Boost: https://github.com/boostorg/filesystem/issues/201 BOOST_TEST(checkImport(import, {"--allow-paths=/../../a/../"})); -#endif BOOST_TEST(checkImport(import, {"--allow-paths=/../../" + m_portablePrefix})); // File named like a directory From 970381cb1d96f8cc0e7443ff11bdebd35a187525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 17 Sep 2021 20:08:49 +0200 Subject: [PATCH 185/232] splitSources.py: Support the case where the input file is empty --- scripts/splitSources.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/splitSources.py b/scripts/splitSources.py index bdd53bf0a..3d1c8ef45 100755 --- a/scripts/splitSources.py +++ b/scripts/splitSources.py @@ -65,7 +65,7 @@ if __name__ == '__main__': # decide if file has multiple sources with open(filePath, mode='r', encoding='utf8', newline='') as f: lines = f.read().splitlines() - if lines[0][:12] == "==== Source:": + if len(lines) >= 1 and lines[0][:12] == "==== Source:": hasMultipleSources = True writeSourceToFile(lines) From 23f7b7781f47672267741922af77c0610abf495a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 17 Sep 2021 20:54:01 +0200 Subject: [PATCH 186/232] cmdlineTests.sh: Skip empty test directories --- test/cmdlineTests.sh | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index d6c335067..ab0037bd9 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -56,7 +56,8 @@ do *) matching_tests=$(find . -mindepth 1 -maxdepth 1 -type d -name "$1" | cut --characters 3- | sort) - if [[ $matching_tests == "" ]]; then + if [[ $matching_tests == "" ]] + then patterns_with_no_matches+=("$1") printWarning "No tests matching pattern '$1' found." else @@ -69,7 +70,8 @@ do esac done -if (( ${#selected_tests[@]} == 0 && ${#patterns_with_no_matches[@]} == 0 )); then +if (( ${#selected_tests[@]} == 0 && ${#patterns_with_no_matches[@]} == 0 )) +then selected_tests=(*) fi popd > /dev/null @@ -94,7 +96,8 @@ then fi # extend stack size in case we run via ASAN -if [[ -n "${CIRCLECI}" ]] || [[ -n "$CI" ]]; then +if [[ -n "${CIRCLECI}" ]] || [[ -n "$CI" ]] +then ulimit -s 16384 ulimit -a fi @@ -169,7 +172,10 @@ function test_solc_behaviour() # shellcheck disable=SC2064 trap "rm -f $stdout_path $stderr_path" EXIT - if [[ "$exit_code_expected" = "" ]]; then exit_code_expected="0"; fi + if [[ "$exit_code_expected" = "" ]] + then + exit_code_expected="0" + fi [[ $filename == "" ]] || solc_args+=("$filename") @@ -338,19 +344,27 @@ printTask "Running general commandline tests..." cd "$REPO_ROOT"/test/cmdlineTests/ for tdir in "${selected_tests[@]}" do - if ! [[ -d $tdir ]]; then + if ! [[ -d $tdir ]] + then printError "Test directory not found: $tdir" exit 1 fi printTask " - ${tdir}" + if [[ $(ls -A "$tdir") == "" ]] + then + printWarning " ---> skipped (test dir empty)" + continue + fi + # Strip trailing slash from $tdir. tdir=$(basename "${tdir}") if [[ $no_smt == true ]] then - if [[ $tdir =~ .*model_checker_.* ]]; then - printWarning " --- > skipped" + if [[ $tdir =~ .*model_checker_.* ]] + then + printWarning " ---> skipped (SMT test)" continue fi fi From 4e28020ff5cb40bafffcaf4168bae8925f2b2c9d Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 27 Sep 2021 15:43:59 +0200 Subject: [PATCH 187/232] Set release date. --- Changelog.md | 2 +- docs/bugs_by_version.json | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index ee2b6ec97..db242be05 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,4 +1,4 @@ -### 0.8.8 (unreleased) +### 0.8.8 (2021-09-27) Language Features: * Inheritance: A function that overrides only a single interface function does not require the ``override`` specifier. diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index 0c1dbbc18..d5c49bdb9 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1555,5 +1555,9 @@ "0.8.7": { "bugs": [], "released": "2021-08-11" + }, + "0.8.8": { + "bugs": [], + "released": "2021-09-27" } } \ No newline at end of file From 3dc41914414cff4a32d5a9da2fdb526e8b25ed05 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 27 Sep 2021 19:43:47 +0200 Subject: [PATCH 188/232] Update version number. --- Changelog.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Changelog.md b/Changelog.md index db242be05..7ee71b924 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,16 @@ +### 0.8.9 (unreleased) + +Language Features: + + +Compiler Features: + + + +Bugfixes: + + + ### 0.8.8 (2021-09-27) Language Features: From 4d49008901febd7ca641ac746c2ef9e8aca3b48a Mon Sep 17 00:00:00 2001 From: Leo Arias Date: Tue, 28 Sep 2021 04:10:02 +0000 Subject: [PATCH 189/232] Update the snap to build on Ubuntu 20.04 --- snap/snapcraft.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index d732b9077..45a5844b1 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -13,6 +13,7 @@ description: | It is possible to create contracts for voting, crowdfunding, blind auctions, multi-signature wallets and more. +base: core20 grade: stable confinement: strict @@ -27,7 +28,7 @@ parts: source-type: git plugin: cmake build-packages: [build-essential, libboost-all-dev] - stage-packages: [libicu60] + stage-packages: [libicu66] override-build: | if git describe --exact-match --tags 2> /dev/null then @@ -41,7 +42,6 @@ parts: plugin: make build-packages: [python] stage-packages: [libstdc++6] - makefile: build/Makefile override-build: | python scripts/mk_make.py cd build From e24083a298cf1801e15f457f816a490dec890dfd Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Tue, 28 Sep 2021 11:15:43 +0200 Subject: [PATCH 190/232] UserDefinedValueType: test for reading from dirty storage slots --- .../userDefinedValueType/dirty_slot.sol | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/dirty_slot.sol diff --git a/test/libsolidity/semanticTests/userDefinedValueType/dirty_slot.sol b/test/libsolidity/semanticTests/userDefinedValueType/dirty_slot.sol new file mode 100644 index 000000000..4e500f53a --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/dirty_slot.sol @@ -0,0 +1,37 @@ +type MyUInt16 is uint16; +type MyBytes2 is bytes2; +contract C { + MyUInt16 public a = MyUInt16.wrap(13); + MyBytes2 public b = MyBytes2.wrap(bytes2(uint16(1025))); + bytes2 public x; + function write_a() external { + uint max = 0xf00e0bbc0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0c0ba098076054032001; + assembly { + sstore(a.slot, max) + } + } + function write_b() external { + uint max = 0xf00e0bbc0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0e0c0ba098076054032001; + assembly { + sstore(b.slot, max) + } + } + function get_b(uint index) public returns (bytes1) { + return MyBytes2.unwrap(b)[index]; + } +} +// ==== +// compileViaYul: also +// ---- +// a() -> 13 +// b() -> 0x0401000000000000000000000000000000000000000000000000000000000000 +// get_b(uint256): 0 -> 0x0400000000000000000000000000000000000000000000000000000000000000 +// get_b(uint256): 1 -> 0x0100000000000000000000000000000000000000000000000000000000000000 +// get_b(uint256): 2 -> FAILURE, hex"4e487b71", 0x32 +// write_a() -> +// a() -> 0x2001 +// write_b() -> +// b() -> 0xf00e000000000000000000000000000000000000000000000000000000000000 +// get_b(uint256): 0 -> 0xf000000000000000000000000000000000000000000000000000000000000000 +// get_b(uint256): 1 -> 0x0e00000000000000000000000000000000000000000000000000000000000000 +// get_b(uint256): 2 -> FAILURE, hex"4e487b71", 0x32 From b6e62d61ec7482e64fba600f2988e1555db97c60 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 28 Sep 2021 11:05:52 +0200 Subject: [PATCH 191/232] Export canonicalName --- Changelog.md | 1 + libsolidity/ast/ASTJsonConverter.cpp | 2 ++ test/cmdlineTests/ast_compact_json_with_base_path/output | 1 + test/cmdlineTests/combined_json_with_base_path/output | 2 +- test/cmdlineTests/recovery_ast_constructor/output | 1 + test/cmdlineTests/recovery_standard_json/output.json | 2 +- test/cmdlineTests/standard_only_ast_requested/output.json | 2 +- test/libsolidity/ASTJSON/abstract_contract.json | 1 + test/libsolidity/ASTJSON/address_payable.json | 1 + test/libsolidity/ASTJSON/array_type_name.json | 1 + test/libsolidity/ASTJSON/assembly/call.json | 1 + test/libsolidity/ASTJSON/assembly/empty_block.json | 1 + test/libsolidity/ASTJSON/assembly/function.json | 1 + test/libsolidity/ASTJSON/assembly/leave.json | 1 + test/libsolidity/ASTJSON/assembly/loop.json | 1 + test/libsolidity/ASTJSON/assembly/nested_functions.json | 1 + test/libsolidity/ASTJSON/assembly/slot_offset.json | 1 + test/libsolidity/ASTJSON/assembly/stringlit.json | 1 + test/libsolidity/ASTJSON/assembly/switch.json | 1 + test/libsolidity/ASTJSON/assembly/switch_default.json | 1 + test/libsolidity/ASTJSON/assembly/var_access.json | 1 + test/libsolidity/ASTJSON/base_constructor_call.json | 2 ++ test/libsolidity/ASTJSON/constructor.json | 1 + test/libsolidity/ASTJSON/contract_dep_order.json | 5 +++++ test/libsolidity/ASTJSON/documentation.json | 3 +++ test/libsolidity/ASTJSON/documentation_local_variable.json | 1 + test/libsolidity/ASTJSON/documentation_on_statements.json | 1 + test/libsolidity/ASTJSON/documentation_triple.json | 1 + test/libsolidity/ASTJSON/enum_value.json | 1 + test/libsolidity/ASTJSON/event_definition.json | 1 + test/libsolidity/ASTJSON/fallback.json | 1 + test/libsolidity/ASTJSON/fallback_and_reveice_ether.json | 1 + test/libsolidity/ASTJSON/fallback_payable.json | 1 + test/libsolidity/ASTJSON/function_type.json | 1 + test/libsolidity/ASTJSON/inheritance_specifier.json | 2 ++ test/libsolidity/ASTJSON/license.json | 1 + .../libsolidity/ASTJSON/long_type_name_binary_operation.json | 1 + test/libsolidity/ASTJSON/long_type_name_identifier.json | 1 + test/libsolidity/ASTJSON/mappings.json | 1 + test/libsolidity/ASTJSON/modifier_definition.json | 1 + test/libsolidity/ASTJSON/modifier_invocation.json | 1 + test/libsolidity/ASTJSON/mutability.json | 1 + test/libsolidity/ASTJSON/non_utf8.json | 1 + test/libsolidity/ASTJSON/override.json | 3 +++ test/libsolidity/ASTJSON/placeholder_statement.json | 1 + test/libsolidity/ASTJSON/receive_ether.json | 1 + test/libsolidity/ASTJSON/short_type_name.json | 1 + test/libsolidity/ASTJSON/short_type_name_ref.json | 1 + test/libsolidity/ASTJSON/smoke.json | 1 + test/libsolidity/ASTJSON/source_location.json | 1 + test/libsolidity/ASTJSON/string.json | 1 + test/libsolidity/ASTJSON/two_base_functions.json | 3 +++ test/libsolidity/ASTJSON/unicode.json | 1 + test/libsolidity/ASTJSON/used_errors.json | 1 + test/libsolidity/ASTJSON/userDefinedValueType.json | 5 +++++ test/libsolidity/ASTJSON/using_for_directive.json | 2 ++ test/libsolidity/ASTJSON/yul_hex_literal.json | 1 + test/libsolidity/StandardCompiler.cpp | 2 +- 58 files changed, 76 insertions(+), 4 deletions(-) diff --git a/Changelog.md b/Changelog.md index 7ee71b924..995abc949 100644 --- a/Changelog.md +++ b/Changelog.md @@ -8,6 +8,7 @@ Compiler Features: Bugfixes: + * AST: Export ``canonicalName`` for ``UserDefinedValueTypeDefinition`` and ``ContractDefinition``. diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index c624e56ae..fd79a6f62 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -275,6 +275,7 @@ bool ASTJsonConverter::visit(ContractDefinition const& _node) make_pair("nodes", toJson(_node.subNodes())), make_pair("scope", idOrNull(_node.scope())) }; + addIfSet(attributes, "canonicalName", _node.annotation().canonicalName); if (_node.annotation().unimplementedDeclarations.has_value()) attributes.emplace_back("fullyImplemented", _node.annotation().unimplementedDeclarations->empty()); @@ -361,6 +362,7 @@ bool ASTJsonConverter::visit(UserDefinedValueTypeDefinition const& _node) make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), make_pair("underlyingType", toJson(*_node.underlyingType())) }; + addIfSet(attributes, "canonicalName", _node.annotation().canonicalName); setJsonNode(_node, "UserDefinedValueTypeDefinition", std::move(attributes)); diff --git a/test/cmdlineTests/ast_compact_json_with_base_path/output b/test/cmdlineTests/ast_compact_json_with_base_path/output index ce8c4d274..6404ef3bd 100644 --- a/test/cmdlineTests/ast_compact_json_with_base_path/output +++ b/test/cmdlineTests/ast_compact_json_with_base_path/output @@ -30,6 +30,7 @@ JSON AST (compact format): { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/cmdlineTests/combined_json_with_base_path/output b/test/cmdlineTests/combined_json_with_base_path/output index 206bfc639..fe00b71a0 100644 --- a/test/cmdlineTests/combined_json_with_base_path/output +++ b/test/cmdlineTests/combined_json_with_base_path/output @@ -1 +1 @@ -{"contracts":{"combined_json_with_base_path/c.sol:C":{}},"sourceList":["combined_json_with_base_path/c.sol","combined_json_with_base_path/input.sol"],"sources":{"combined_json_with_base_path/c.sol":{"AST":{"absolutePath":"combined_json_with_base_path/c.sol","exportedSymbols":{"C":[5]},"id":6,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":4,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":5,"linearizedBaseContracts":[5],"name":"C","nameLocation":"69:1:0","nodeType":"ContractDefinition","nodes":[],"scope":6,"src":"60:13:0","usedErrors":[]}],"src":"36:38:0"}},"combined_json_with_base_path/input.sol":{"AST":{"absolutePath":"combined_json_with_base_path/input.sol","exportedSymbols":{"C":[5]},"id":3,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:1"},{"absolutePath":"combined_json_with_base_path/c.sol","file":"./c.sol","id":2,"nameLocation":"-1:-1:-1","nodeType":"ImportDirective","scope":3,"sourceUnit":6,"src":"60:17:1","symbolAliases":[],"unitAlias":""}],"src":"36:42:1"}}},"version": ""} +{"contracts":{"combined_json_with_base_path/c.sol:C":{}},"sourceList":["combined_json_with_base_path/c.sol","combined_json_with_base_path/input.sol"],"sources":{"combined_json_with_base_path/c.sol":{"AST":{"absolutePath":"combined_json_with_base_path/c.sol","exportedSymbols":{"C":[5]},"id":6,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":4,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":5,"linearizedBaseContracts":[5],"name":"C","nameLocation":"69:1:0","nodeType":"ContractDefinition","nodes":[],"scope":6,"src":"60:13:0","usedErrors":[]}],"src":"36:38:0"}},"combined_json_with_base_path/input.sol":{"AST":{"absolutePath":"combined_json_with_base_path/input.sol","exportedSymbols":{"C":[5]},"id":3,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:1"},{"absolutePath":"combined_json_with_base_path/c.sol","file":"./c.sol","id":2,"nameLocation":"-1:-1:-1","nodeType":"ImportDirective","scope":3,"sourceUnit":6,"src":"60:17:1","symbolAliases":[],"unitAlias":""}],"src":"36:42:1"}}},"version": ""} diff --git a/test/cmdlineTests/recovery_ast_constructor/output b/test/cmdlineTests/recovery_ast_constructor/output index 4a2f711c1..33c07b4c1 100644 --- a/test/cmdlineTests/recovery_ast_constructor/output +++ b/test/cmdlineTests/recovery_ast_constructor/output @@ -31,6 +31,7 @@ JSON AST (compact format): { "abstract": false, "baseContracts": [], + "canonicalName": "Error1", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/cmdlineTests/recovery_standard_json/output.json b/test/cmdlineTests/recovery_standard_json/output.json index 3868e93cb..2378a2084 100644 --- a/test/cmdlineTests/recovery_standard_json/output.json +++ b/test/cmdlineTests/recovery_standard_json/output.json @@ -10,4 +10,4 @@ 2 | pragma solidity >=0.0; contract Errort6 { using foo for ; /* missing type name */ } | ^ -","message":"Recovered in ContractDefinition at '}'.","severity":"warning","sourceLocation":{"end":120,"file":"A","start":119},"type":"Warning"}],"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"Errort6":[3]},"id":4,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":3,"linearizedBaseContracts":[3],"name":"Errort6","nameLocation":"68:7:0","nodeType":"ContractDefinition","nodes":[],"scope":4,"src":"59:35:0","usedErrors":[]}],"src":"36:84:0"},"id":0}}} +","message":"Recovered in ContractDefinition at '}'.","severity":"warning","sourceLocation":{"end":120,"file":"A","start":119},"type":"Warning"}],"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"Errort6":[3]},"id":4,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"canonicalName":"Errort6","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":3,"linearizedBaseContracts":[3],"name":"Errort6","nameLocation":"68:7:0","nodeType":"ContractDefinition","nodes":[],"scope":4,"src":"59:35:0","usedErrors":[]}],"src":"36:84:0"},"id":0}}} diff --git a/test/cmdlineTests/standard_only_ast_requested/output.json b/test/cmdlineTests/standard_only_ast_requested/output.json index 31e349c4d..0177dd7fc 100644 --- a/test/cmdlineTests/standard_only_ast_requested/output.json +++ b/test/cmdlineTests/standard_only_ast_requested/output.json @@ -1 +1 @@ -{"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"C":[6]},"id":7,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":6,"linearizedBaseContracts":[6],"name":"C","nameLocation":"68:1:0","nodeType":"ContractDefinition","nodes":[{"body":{"id":4,"nodeType":"Block","src":"97:2:0","statements":[]},"functionSelector":"26121ff0","id":5,"implemented":true,"kind":"function","modifiers":[],"name":"f","nameLocation":"81:1:0","nodeType":"FunctionDefinition","parameters":{"id":2,"nodeType":"ParameterList","parameters":[],"src":"82:2:0"},"returnParameters":{"id":3,"nodeType":"ParameterList","parameters":[],"src":"97:0:0"},"scope":6,"src":"72:27:0","stateMutability":"pure","virtual":false,"visibility":"public"}],"scope":7,"src":"59:42:0","usedErrors":[]}],"src":"36:65:0"},"id":0}}} +{"sources":{"A":{"ast":{"absolutePath":"A","exportedSymbols":{"C":[6]},"id":7,"license":"GPL-3.0","nodeType":"SourceUnit","nodes":[{"id":1,"literals":["solidity",">=","0.0"],"nodeType":"PragmaDirective","src":"36:22:0"},{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":6,"linearizedBaseContracts":[6],"name":"C","nameLocation":"68:1:0","nodeType":"ContractDefinition","nodes":[{"body":{"id":4,"nodeType":"Block","src":"97:2:0","statements":[]},"functionSelector":"26121ff0","id":5,"implemented":true,"kind":"function","modifiers":[],"name":"f","nameLocation":"81:1:0","nodeType":"FunctionDefinition","parameters":{"id":2,"nodeType":"ParameterList","parameters":[],"src":"82:2:0"},"returnParameters":{"id":3,"nodeType":"ParameterList","parameters":[],"src":"97:0:0"},"scope":6,"src":"72:27:0","stateMutability":"pure","virtual":false,"visibility":"public"}],"scope":7,"src":"59:42:0","usedErrors":[]}],"src":"36:65:0"},"id":0}}} diff --git a/test/libsolidity/ASTJSON/abstract_contract.json b/test/libsolidity/ASTJSON/abstract_contract.json index ab0764cd8..168433eb9 100644 --- a/test/libsolidity/ASTJSON/abstract_contract.json +++ b/test/libsolidity/ASTJSON/abstract_contract.json @@ -14,6 +14,7 @@ { "abstract": true, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/address_payable.json b/test/libsolidity/ASTJSON/address_payable.json index 37692508b..22090ee29 100644 --- a/test/libsolidity/ASTJSON/address_payable.json +++ b/test/libsolidity/ASTJSON/address_payable.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/array_type_name.json b/test/libsolidity/ASTJSON/array_type_name.json index 25a54712d..c1bcaa985 100644 --- a/test/libsolidity/ASTJSON/array_type_name.json +++ b/test/libsolidity/ASTJSON/array_type_name.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/assembly/call.json b/test/libsolidity/ASTJSON/assembly/call.json index 43a401558..c6e0561ed 100644 --- a/test/libsolidity/ASTJSON/assembly/call.json +++ b/test/libsolidity/ASTJSON/assembly/call.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/assembly/empty_block.json b/test/libsolidity/ASTJSON/assembly/empty_block.json index 9e0867656..19779b076 100644 --- a/test/libsolidity/ASTJSON/assembly/empty_block.json +++ b/test/libsolidity/ASTJSON/assembly/empty_block.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/assembly/function.json b/test/libsolidity/ASTJSON/assembly/function.json index f78550fd1..e528baa4c 100644 --- a/test/libsolidity/ASTJSON/assembly/function.json +++ b/test/libsolidity/ASTJSON/assembly/function.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/assembly/leave.json b/test/libsolidity/ASTJSON/assembly/leave.json index 12b042b51..eefc5105f 100644 --- a/test/libsolidity/ASTJSON/assembly/leave.json +++ b/test/libsolidity/ASTJSON/assembly/leave.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/assembly/loop.json b/test/libsolidity/ASTJSON/assembly/loop.json index a0c475ae1..8a887a80f 100644 --- a/test/libsolidity/ASTJSON/assembly/loop.json +++ b/test/libsolidity/ASTJSON/assembly/loop.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/assembly/nested_functions.json b/test/libsolidity/ASTJSON/assembly/nested_functions.json index f4cef95e0..aea5e54d0 100644 --- a/test/libsolidity/ASTJSON/assembly/nested_functions.json +++ b/test/libsolidity/ASTJSON/assembly/nested_functions.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "id": 8, diff --git a/test/libsolidity/ASTJSON/assembly/slot_offset.json b/test/libsolidity/ASTJSON/assembly/slot_offset.json index 8b8fb1a25..cc22c76e8 100644 --- a/test/libsolidity/ASTJSON/assembly/slot_offset.json +++ b/test/libsolidity/ASTJSON/assembly/slot_offset.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/assembly/stringlit.json b/test/libsolidity/ASTJSON/assembly/stringlit.json index 9ca0ad8e5..64777e947 100644 --- a/test/libsolidity/ASTJSON/assembly/stringlit.json +++ b/test/libsolidity/ASTJSON/assembly/stringlit.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/assembly/switch.json b/test/libsolidity/ASTJSON/assembly/switch.json index af02d3423..85dcb313f 100644 --- a/test/libsolidity/ASTJSON/assembly/switch.json +++ b/test/libsolidity/ASTJSON/assembly/switch.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "id": 6, diff --git a/test/libsolidity/ASTJSON/assembly/switch_default.json b/test/libsolidity/ASTJSON/assembly/switch_default.json index 63f105679..16e1f1bf4 100644 --- a/test/libsolidity/ASTJSON/assembly/switch_default.json +++ b/test/libsolidity/ASTJSON/assembly/switch_default.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/assembly/var_access.json b/test/libsolidity/ASTJSON/assembly/var_access.json index 0ae3bf008..9cddf4460 100644 --- a/test/libsolidity/ASTJSON/assembly/var_access.json +++ b/test/libsolidity/ASTJSON/assembly/var_access.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/base_constructor_call.json b/test/libsolidity/ASTJSON/base_constructor_call.json index e2b9686cb..bfbd716da 100644 --- a/test/libsolidity/ASTJSON/base_constructor_call.json +++ b/test/libsolidity/ASTJSON/base_constructor_call.json @@ -18,6 +18,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "A", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, @@ -121,6 +122,7 @@ "src": "50:1:1" } ], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/constructor.json b/test/libsolidity/ASTJSON/constructor.json index b1ca1503c..9ac4ac9c8 100644 --- a/test/libsolidity/ASTJSON/constructor.json +++ b/test/libsolidity/ASTJSON/constructor.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/contract_dep_order.json b/test/libsolidity/ASTJSON/contract_dep_order.json index fda09e177..754e14f4d 100644 --- a/test/libsolidity/ASTJSON/contract_dep_order.json +++ b/test/libsolidity/ASTJSON/contract_dep_order.json @@ -30,6 +30,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "A", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, @@ -64,6 +65,7 @@ "src": "29:1:1" } ], + "canonicalName": "B", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, @@ -99,6 +101,7 @@ "src": "49:1:1" } ], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, @@ -135,6 +138,7 @@ "src": "69:1:1" } ], + "canonicalName": "D", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, @@ -172,6 +176,7 @@ "src": "89:1:1" } ], + "canonicalName": "E", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/documentation.json b/test/libsolidity/ASTJSON/documentation.json index 751b6bcca..de512181f 100644 --- a/test/libsolidity/ASTJSON/documentation.json +++ b/test/libsolidity/ASTJSON/documentation.json @@ -15,6 +15,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "documentation": @@ -57,6 +58,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "documentation": @@ -99,6 +101,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/documentation_local_variable.json b/test/libsolidity/ASTJSON/documentation_local_variable.json index b21f719bf..24e38eb1a 100644 --- a/test/libsolidity/ASTJSON/documentation_local_variable.json +++ b/test/libsolidity/ASTJSON/documentation_local_variable.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/documentation_on_statements.json b/test/libsolidity/ASTJSON/documentation_on_statements.json index 5253c1115..bb3ee28d1 100644 --- a/test/libsolidity/ASTJSON/documentation_on_statements.json +++ b/test/libsolidity/ASTJSON/documentation_on_statements.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/documentation_triple.json b/test/libsolidity/ASTJSON/documentation_triple.json index 977006c3a..9124e68b1 100644 --- a/test/libsolidity/ASTJSON/documentation_triple.json +++ b/test/libsolidity/ASTJSON/documentation_triple.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/enum_value.json b/test/libsolidity/ASTJSON/enum_value.json index 90d5e498c..2cca00902 100644 --- a/test/libsolidity/ASTJSON/enum_value.json +++ b/test/libsolidity/ASTJSON/enum_value.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/event_definition.json b/test/libsolidity/ASTJSON/event_definition.json index e2187bbe3..627fd13ba 100644 --- a/test/libsolidity/ASTJSON/event_definition.json +++ b/test/libsolidity/ASTJSON/event_definition.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/fallback.json b/test/libsolidity/ASTJSON/fallback.json index 4b9e22e44..25a9b8588 100644 --- a/test/libsolidity/ASTJSON/fallback.json +++ b/test/libsolidity/ASTJSON/fallback.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/fallback_and_reveice_ether.json b/test/libsolidity/ASTJSON/fallback_and_reveice_ether.json index 0f3b1b69e..26b4ada77 100644 --- a/test/libsolidity/ASTJSON/fallback_and_reveice_ether.json +++ b/test/libsolidity/ASTJSON/fallback_and_reveice_ether.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/fallback_payable.json b/test/libsolidity/ASTJSON/fallback_payable.json index 1d0f3e627..4331b5edf 100644 --- a/test/libsolidity/ASTJSON/fallback_payable.json +++ b/test/libsolidity/ASTJSON/fallback_payable.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/function_type.json b/test/libsolidity/ASTJSON/function_type.json index 304812905..cef79e70b 100644 --- a/test/libsolidity/ASTJSON/function_type.json +++ b/test/libsolidity/ASTJSON/function_type.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/inheritance_specifier.json b/test/libsolidity/ASTJSON/inheritance_specifier.json index debcfdb10..b74604265 100644 --- a/test/libsolidity/ASTJSON/inheritance_specifier.json +++ b/test/libsolidity/ASTJSON/inheritance_specifier.json @@ -18,6 +18,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C1", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, @@ -52,6 +53,7 @@ "src": "30:2:1" } ], + "canonicalName": "C2", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/license.json b/test/libsolidity/ASTJSON/license.json index 2afd9a017..9f996e051 100644 --- a/test/libsolidity/ASTJSON/license.json +++ b/test/libsolidity/ASTJSON/license.json @@ -15,6 +15,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/long_type_name_binary_operation.json b/test/libsolidity/ASTJSON/long_type_name_binary_operation.json index a2dbdc41c..8340eaf40 100644 --- a/test/libsolidity/ASTJSON/long_type_name_binary_operation.json +++ b/test/libsolidity/ASTJSON/long_type_name_binary_operation.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "c", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/long_type_name_identifier.json b/test/libsolidity/ASTJSON/long_type_name_identifier.json index 8263dcda2..c810283d2 100644 --- a/test/libsolidity/ASTJSON/long_type_name_identifier.json +++ b/test/libsolidity/ASTJSON/long_type_name_identifier.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "c", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/mappings.json b/test/libsolidity/ASTJSON/mappings.json index f3951853e..16904ec8a 100644 --- a/test/libsolidity/ASTJSON/mappings.json +++ b/test/libsolidity/ASTJSON/mappings.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/modifier_definition.json b/test/libsolidity/ASTJSON/modifier_definition.json index cddfdd273..67aa3e1ea 100644 --- a/test/libsolidity/ASTJSON/modifier_definition.json +++ b/test/libsolidity/ASTJSON/modifier_definition.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/modifier_invocation.json b/test/libsolidity/ASTJSON/modifier_invocation.json index cddfdd273..67aa3e1ea 100644 --- a/test/libsolidity/ASTJSON/modifier_invocation.json +++ b/test/libsolidity/ASTJSON/modifier_invocation.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/mutability.json b/test/libsolidity/ASTJSON/mutability.json index 0adce73a7..90bbf05d5 100644 --- a/test/libsolidity/ASTJSON/mutability.json +++ b/test/libsolidity/ASTJSON/mutability.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/non_utf8.json b/test/libsolidity/ASTJSON/non_utf8.json index 5c433531a..2f7145fda 100644 --- a/test/libsolidity/ASTJSON/non_utf8.json +++ b/test/libsolidity/ASTJSON/non_utf8.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/override.json b/test/libsolidity/ASTJSON/override.json index 1eda7ba09..639572c54 100644 --- a/test/libsolidity/ASTJSON/override.json +++ b/test/libsolidity/ASTJSON/override.json @@ -22,6 +22,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "A", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, @@ -94,6 +95,7 @@ "src": "72:1:1" } ], + "canonicalName": "B", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": false, @@ -207,6 +209,7 @@ "src": "167:1:1" } ], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/placeholder_statement.json b/test/libsolidity/ASTJSON/placeholder_statement.json index 62631f003..5a6d51b21 100644 --- a/test/libsolidity/ASTJSON/placeholder_statement.json +++ b/test/libsolidity/ASTJSON/placeholder_statement.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/receive_ether.json b/test/libsolidity/ASTJSON/receive_ether.json index b36dcd338..bfcb33f6c 100644 --- a/test/libsolidity/ASTJSON/receive_ether.json +++ b/test/libsolidity/ASTJSON/receive_ether.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/short_type_name.json b/test/libsolidity/ASTJSON/short_type_name.json index a4d25b46f..b7409fbbc 100644 --- a/test/libsolidity/ASTJSON/short_type_name.json +++ b/test/libsolidity/ASTJSON/short_type_name.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "c", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/short_type_name_ref.json b/test/libsolidity/ASTJSON/short_type_name_ref.json index eba4ae96d..6a0f249f8 100644 --- a/test/libsolidity/ASTJSON/short_type_name_ref.json +++ b/test/libsolidity/ASTJSON/short_type_name_ref.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "c", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/smoke.json b/test/libsolidity/ASTJSON/smoke.json index b32ff7673..4d4a02e24 100644 --- a/test/libsolidity/ASTJSON/smoke.json +++ b/test/libsolidity/ASTJSON/smoke.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/source_location.json b/test/libsolidity/ASTJSON/source_location.json index 0518c8a1b..0591a30cc 100644 --- a/test/libsolidity/ASTJSON/source_location.json +++ b/test/libsolidity/ASTJSON/source_location.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/string.json b/test/libsolidity/ASTJSON/string.json index 67f5c16f7..438f760c4 100644 --- a/test/libsolidity/ASTJSON/string.json +++ b/test/libsolidity/ASTJSON/string.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/two_base_functions.json b/test/libsolidity/ASTJSON/two_base_functions.json index dde1c5d61..2098b3cd5 100644 --- a/test/libsolidity/ASTJSON/two_base_functions.json +++ b/test/libsolidity/ASTJSON/two_base_functions.json @@ -22,6 +22,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "A", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, @@ -79,6 +80,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "B", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, @@ -164,6 +166,7 @@ "src": "117:1:1" } ], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/unicode.json b/test/libsolidity/ASTJSON/unicode.json index 937a40943..dcb267b3f 100644 --- a/test/libsolidity/ASTJSON/unicode.json +++ b/test/libsolidity/ASTJSON/unicode.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/used_errors.json b/test/libsolidity/ASTJSON/used_errors.json index 5e7d0bc3a..a8ca24a28 100644 --- a/test/libsolidity/ASTJSON/used_errors.json +++ b/test/libsolidity/ASTJSON/used_errors.json @@ -112,6 +112,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/userDefinedValueType.json b/test/libsolidity/ASTJSON/userDefinedValueType.json index 4cd72c4f8..df7aa69c8 100644 --- a/test/libsolidity/ASTJSON/userDefinedValueType.json +++ b/test/libsolidity/ASTJSON/userDefinedValueType.json @@ -24,6 +24,7 @@ "nodes": [ { + "canonicalName": "MyAddress", "id": 2, "name": "MyAddress", "nameLocation": "5:9:1", @@ -44,6 +45,7 @@ } }, { + "canonicalName": "MyUInt", "id": 4, "name": "MyUInt", "nameLocation": "32:6:1", @@ -202,6 +204,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, @@ -216,6 +219,7 @@ "nodes": [ { + "canonicalName": "C.MyAddress", "id": 18, "name": "MyAddress", "nameLocation": "118:9:1", @@ -236,6 +240,7 @@ } }, { + "canonicalName": "C.MyUInt", "id": 20, "name": "MyUInt", "nameLocation": "149:6:1", diff --git a/test/libsolidity/ASTJSON/using_for_directive.json b/test/libsolidity/ASTJSON/using_for_directive.json index b8a8fd3b7..b935b262b 100644 --- a/test/libsolidity/ASTJSON/using_for_directive.json +++ b/test/libsolidity/ASTJSON/using_for_directive.json @@ -18,6 +18,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "L", "contractDependencies": [], "contractKind": "library", "fullyImplemented": true, @@ -37,6 +38,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "C", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/ASTJSON/yul_hex_literal.json b/test/libsolidity/ASTJSON/yul_hex_literal.json index 54d37da00..fc1cc39db 100644 --- a/test/libsolidity/ASTJSON/yul_hex_literal.json +++ b/test/libsolidity/ASTJSON/yul_hex_literal.json @@ -14,6 +14,7 @@ { "abstract": false, "baseContracts": [], + "canonicalName": "Sample", "contractDependencies": [], "contractKind": "contract", "fullyImplemented": true, diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index ec5166cb1..8497fc0c0 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -485,7 +485,7 @@ BOOST_AUTO_TEST_CASE(basic_compilation) BOOST_CHECK_EQUAL( util::jsonCompactPrint(result["sources"]["fileA"]["ast"]), "{\"absolutePath\":\"fileA\",\"exportedSymbols\":{\"A\":[1]},\"id\":2,\"nodeType\":\"SourceUnit\",\"nodes\":[{\"abstract\":false," - "\"baseContracts\":[],\"contractDependencies\":[],\"contractKind\":\"contract\",\"fullyImplemented\":true,\"id\":1," + "\"baseContracts\":[],\"canonicalName\":\"A\",\"contractDependencies\":[],\"contractKind\":\"contract\",\"fullyImplemented\":true,\"id\":1," "\"linearizedBaseContracts\":[1],\"name\":\"A\",\"nameLocation\":\"9:1:0\",\"nodeType\":\"ContractDefinition\",\"nodes\":[],\"scope\":2," "\"src\":\"0:14:0\",\"usedErrors\":[]}],\"src\":\"0:14:0\"}" ); From 41f9aab219c3afab66f7e7ada7fe568e75f31853 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Tue, 28 Sep 2021 14:41:57 +0200 Subject: [PATCH 192/232] Tests for assembly access of user defined value types. --- .../assembly_access_bytes2_abicoder_v1.sol | 35 +++++++++++++++++++ .../assembly_access_bytes2_abicoder_v2.sol | 35 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/assembly_access_bytes2_abicoder_v1.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/assembly_access_bytes2_abicoder_v2.sol diff --git a/test/libsolidity/semanticTests/userDefinedValueType/assembly_access_bytes2_abicoder_v1.sol b/test/libsolidity/semanticTests/userDefinedValueType/assembly_access_bytes2_abicoder_v1.sol new file mode 100644 index 000000000..f41a9205d --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/assembly_access_bytes2_abicoder_v1.sol @@ -0,0 +1,35 @@ +pragma abicoder v1; + +type MyBytes2 is bytes2; + +contract C { + function f(MyBytes2 val) external returns (bytes2 ret) { + assembly { + ret := val + } + } + + function g(bytes2 val) external returns (bytes2 ret) { + assembly { + ret := val + } + } + + function h(uint256 val) external returns (MyBytes2) { + MyBytes2 ret; + assembly { + ret := val + } + return ret; + } + +} +// ==== +// compileViaYul: false +// ---- +// f(bytes2): "ab" -> 0x6162000000000000000000000000000000000000000000000000000000000000 +// g(bytes2): "ab" -> 0x6162000000000000000000000000000000000000000000000000000000000000 +// f(bytes2): "abcdef" -> 0x6162000000000000000000000000000000000000000000000000000000000000 +// g(bytes2): "abcdef" -> 0x6162000000000000000000000000000000000000000000000000000000000000 +// h(uint256): "ab" -> 0x6162000000000000000000000000000000000000000000000000000000000000 +// h(uint256): "abcdef" -> 0x6162000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/assembly_access_bytes2_abicoder_v2.sol b/test/libsolidity/semanticTests/userDefinedValueType/assembly_access_bytes2_abicoder_v2.sol new file mode 100644 index 000000000..6af03b847 --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/assembly_access_bytes2_abicoder_v2.sol @@ -0,0 +1,35 @@ +pragma abicoder v2; + +type MyBytes2 is bytes2; + +contract C { + function f(MyBytes2 val) external returns (bytes2 ret) { + assembly { + ret := val + } + } + + function g(bytes2 val) external returns (bytes2 ret) { + assembly { + ret := val + } + } + + function h(uint256 val) external returns (MyBytes2) { + MyBytes2 ret; + assembly { + ret := val + } + return ret; + } + +} +// ==== +// compileViaYul: also +// ---- +// f(bytes2): "ab" -> 0x6162000000000000000000000000000000000000000000000000000000000000 +// g(bytes2): "ab" -> 0x6162000000000000000000000000000000000000000000000000000000000000 +// f(bytes2): "abcdef" -> FAILURE +// g(bytes2): "abcdef" -> FAILURE +// h(uint256): "ab" -> 0x6162000000000000000000000000000000000000000000000000000000000000 +// h(uint256): "abcdef" -> 0x6162000000000000000000000000000000000000000000000000000000000000 From b96be377ad3531696fbc1342d23aeaba29f8e5d9 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 28 Sep 2021 17:41:23 +0200 Subject: [PATCH 193/232] Update version. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e835a66ff..3fcf42d2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ include(EthPolicy) eth_policy() # project name and version should be set after cmake_policy CMP0048 -set(PROJECT_VERSION "0.8.8") +set(PROJECT_VERSION "0.8.9") # OSX target needed in order to support std::visit set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX) From bb4e3e191dc8beb3e8696a5ec5adf6e7819305f8 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 28 Sep 2021 13:33:16 +0200 Subject: [PATCH 194/232] Fix array copying check. --- libsolidity/codegen/YulUtilFunctions.cpp | 2 +- .../calldata_to_storage.sol | 43 +++++++++++++++++++ .../memory_to_storage.sol | 43 +++++++++++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/memory_to_storage.sol diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index bb56c43df..891595503 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -2416,7 +2416,7 @@ string YulUtilFunctions::copyArrayFromStorageToMemoryFunction(ArrayType const& _ return m_functionCollector.createFunction(functionName, [&]() { if (_from.baseType()->isValueType()) { - solAssert(_from.baseType() == _to.baseType(), ""); + solAssert(*_from.baseType() == *_to.baseType(), ""); ABIFunctions abi(m_evmVersion, m_revertStrings, m_functionCollector); return Whiskers(R"( function (slot) -> memPtr { diff --git a/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol b/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol new file mode 100644 index 000000000..72c9db1bf --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol @@ -0,0 +1,43 @@ +pragma abicoder v2; + +type Small is uint16; +type Left is bytes2; +struct S { uint8 a; Small b; Left c; uint8 d; } + +contract C { + S public s; + Small[] public small; + Left[] public l; + function f(S calldata _s) external { + s = _s; + } + function g(Small[] calldata _small) external returns (Small[] memory) { + small = _small; + return small; + } + function h(Left[] calldata _left) external returns (Left[] memory) { + l = _left; + return l; + } +} +// ==== +// compileViaYul: also +// ---- +// s() -> 0, 0, 0x00, 0 +// f((uint8,uint16,bytes2,uint8)): 1, 0xff, "ab", 15 -> +// gas irOptimized: 110778 +// gas legacy: 112851 +// gas legacyOptimized: 110766 +// s() -> 1, 0xff, 0x6162000000000000000000000000000000000000000000000000000000000000, 15 +// g(uint16[]): 0x20, 3, 1, 2, 3 -> 0x20, 3, 1, 2, 3 +// gas irOptimized: 112669 +// gas legacy: 113715 +// gas legacyOptimized: 112488 +// small(uint256): 0 -> 1 +// small(uint256): 1 -> 2 +// h(bytes2[]): 0x20, 3, "ab", "cd", "ef" -> 0x20, 3, "ab", "cd", "ef" +// gas irOptimized: 112797 +// gas legacy: 113414 +// gas legacyOptimized: 112572 +// l(uint256): 0 -> 0x6162000000000000000000000000000000000000000000000000000000000000 +// l(uint256): 1 -> 0x6364000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/memory_to_storage.sol b/test/libsolidity/semanticTests/userDefinedValueType/memory_to_storage.sol new file mode 100644 index 000000000..2ed2b72db --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/memory_to_storage.sol @@ -0,0 +1,43 @@ +pragma abicoder v2; + +type Small is uint16; +type Left is bytes2; +struct S { uint8 a; Small b; Left c; uint8 d; } + +contract C { + S public s; + Small[] public small; + Left[] public l; + function f(S memory _s) public { + s = _s; + } + function g(Small[] memory _small) public returns (Small[] memory) { + small = _small; + return small; + } + function h(Left[] memory _left) public returns (Left[] memory) { + l = _left; + return l; + } +} +// ==== +// compileViaYul: also +// ---- +// s() -> 0, 0, 0x00, 0 +// f((uint8,uint16,bytes2,uint8)): 1, 0xff, "ab", 15 -> +// gas irOptimized: 110788 +// gas legacy: 111668 +// gas legacyOptimized: 110908 +// s() -> 1, 0xff, 0x6162000000000000000000000000000000000000000000000000000000000000, 15 +// g(uint16[]): 0x20, 3, 1, 2, 3 -> 0x20, 3, 1, 2, 3 +// gas irOptimized: 113144 +// gas legacy: 114806 +// gas legacyOptimized: 113085 +// small(uint256): 0 -> 1 +// small(uint256): 1 -> 2 +// h(bytes2[]): 0x20, 3, "ab", "cd", "ef" -> 0x20, 3, "ab", "cd", "ef" +// gas irOptimized: 113317 +// gas legacy: 114496 +// gas legacyOptimized: 113214 +// l(uint256): 0 -> 0x6162000000000000000000000000000000000000000000000000000000000000 +// l(uint256): 1 -> 0x6364000000000000000000000000000000000000000000000000000000000000 From 90f4ca1048884f2393b1b981611bf61c9d501cd2 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 28 Sep 2021 16:41:32 +0200 Subject: [PATCH 195/232] Do not store immutables packed. --- libsolidity/codegen/CompilerUtils.h | 6 +++--- libsolidity/codegen/ContractCompiler.cpp | 9 ++++++-- libsolidity/codegen/LValue.cpp | 6 ++++-- .../immutable/immutable_signed.sol | 15 +++++++++++++ .../immutable/small_types_in_reverse.sol | 21 +++++++++++++++++++ 5 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 test/libsolidity/semanticTests/immutable/immutable_signed.sol create mode 100644 test/libsolidity/semanticTests/immutable/small_types_in_reverse.sol diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h index 721f65614..f51f8c3cd 100644 --- a/libsolidity/codegen/CompilerUtils.h +++ b/libsolidity/codegen/CompilerUtils.h @@ -95,9 +95,9 @@ public: /// @returns the number of bytes consumed in memory. unsigned loadFromMemory( unsigned _offset, - Type const& _type = *TypeProvider::uint256(), - bool _fromCalldata = false, - bool _padToWords = false + Type const& _type, + bool _fromCalldata, + bool _padToWords ); /// Dynamic version of @see loadFromMemory, expects the memory offset on the stack. /// Stack pre: memory_offset diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 5df08e0cb..357cc8b2d 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -192,7 +192,12 @@ size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _cont auto const& immutables = contractType.immutableVariables(); // Push all immutable values on the stack. for (auto const& immutable: immutables) - CompilerUtils(m_context).loadFromMemory(static_cast(m_context.immutableMemoryOffset(*immutable)), *immutable->annotation().type); + CompilerUtils(m_context).loadFromMemory( + static_cast(m_context.immutableMemoryOffset(*immutable)), + *immutable->annotation().type, + false, + true + ); m_context.pushSubroutineSize(m_context.runtimeSub()); if (immutables.empty()) m_context << Instruction::DUP1; @@ -439,7 +444,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac // retrieve the function signature hash from the calldata if (!interfaceFunctions.empty()) { - CompilerUtils(m_context).loadFromMemory(0, IntegerType(CompilerUtils::dataStartOffset * 8), true); + CompilerUtils(m_context).loadFromMemory(0, IntegerType(CompilerUtils::dataStartOffset * 8), true, false); // stack now is: ? vector> sortedIDs; diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index 2622f2967..75a7f2749 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -159,7 +159,9 @@ void ImmutableItem::retrieveValue(SourceLocation const&, bool) const if (m_context.runtimeContext()) CompilerUtils(m_context).loadFromMemory( static_cast(m_context.immutableMemoryOffset(m_variable)), - *m_dataType + *m_dataType, + false, + true ); else for (auto&& slotName: m_context.immutableVariableSlotNames(m_variable)) @@ -178,7 +180,7 @@ void ImmutableItem::storeValue(Type const& _sourceType, SourceLocation const&, b utils.moveIntoStack(m_dataType->sizeOnStack()); else utils.copyToStackTop(m_dataType->sizeOnStack() + 1, m_dataType->sizeOnStack()); - utils.storeInMemoryDynamic(*m_dataType, false); + utils.storeInMemoryDynamic(*m_dataType); m_context << Instruction::POP; } diff --git a/test/libsolidity/semanticTests/immutable/immutable_signed.sol b/test/libsolidity/semanticTests/immutable/immutable_signed.sol new file mode 100644 index 000000000..752048739 --- /dev/null +++ b/test/libsolidity/semanticTests/immutable/immutable_signed.sol @@ -0,0 +1,15 @@ +contract C { + int8 immutable a = -2; + bytes2 immutable b = "ab"; + function() internal returns (uint) immutable f = g; + function viaasm() view external returns (bytes32 x, bytes32 y) { + int8 _a = a; + bytes2 _b = b; + assembly { x := _a y := _b } + } + function g() internal pure returns (uint) { return 2; } +} +// ==== +// compileViaYul: also +// ---- +// viaasm() -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 0x6162000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/immutable/small_types_in_reverse.sol b/test/libsolidity/semanticTests/immutable/small_types_in_reverse.sol new file mode 100644 index 000000000..677b87d32 --- /dev/null +++ b/test/libsolidity/semanticTests/immutable/small_types_in_reverse.sol @@ -0,0 +1,21 @@ +contract A { + uint16 public immutable a; + uint16 public immutable b; + uint16 public immutable c; + uint16[3] public x; + constructor() { + c = 0xffff; + b = 0x0f0f; + a = 0x1234; + x = [a, b, c]; + } +} +// ==== +// compileViaYul: also +// ---- +// a() -> 4660 +// b() -> 0x0f0f +// c() -> 0xffff +// x(uint256): 0 -> 4660 +// x(uint256): 1 -> 0x0f0f +// x(uint256): 2 -> 0xffff From ffe6e7dcf4be09902147ffcf9efa3412c4eab863 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 28 Sep 2021 17:36:54 +0200 Subject: [PATCH 196/232] Bug list entry about the signed immutables bug. --- docs/bugs.json | 10 ++++++++++ docs/bugs_by_version.json | 39 ++++++++++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/docs/bugs.json b/docs/bugs.json index 5f394aecc..f6ce8f6fe 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,14 @@ [ + { + "uid": "SOL-2021-3", + "name": "SignedImmutables", + "summary": "Immutable variables of signed integer type shorter than 256 bits can lead to values with invalid higher order bits if inline assembly is used.", + "description": "When immutable variables of signed integer type shorter than 256 bits are read, their higher order bits were unconditionally set to zero. The correct operation would be to sign-extend the value, i.e. set the higher order bits to one if the sign bit is one. This sign-extension is performed by Solidity just prior to when it matters, i.e. when a value is stored in memory, when it is compared or when a division is performed. Because of that, to our knowledge, the only way to access the value in its unclean state is by reading it through inline assembly.", + "link": "https://blog.soliditylang.org/2021/09/29/signed-immutables-bug/", + "introduced": "0.6.5", + "fixed": "0.8.9", + "severity": "very low" + }, { "uid": "SOL-2021-2", "name": "ABIDecodeTwoDimensionalArrayMemory", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index d5c49bdb9..c6af59bda 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1333,6 +1333,7 @@ }, "0.6.10": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1342,6 +1343,7 @@ }, "0.6.11": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1351,6 +1353,7 @@ }, "0.6.12": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1402,6 +1405,7 @@ }, "0.6.5": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1415,6 +1419,7 @@ }, "0.6.6": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1427,6 +1432,7 @@ }, "0.6.7": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1439,6 +1445,7 @@ }, "0.6.8": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1448,6 +1455,7 @@ }, "0.6.9": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1458,6 +1466,7 @@ }, "0.7.0": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1467,6 +1476,7 @@ }, "0.7.1": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1477,6 +1487,7 @@ }, "0.7.2": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy", @@ -1486,6 +1497,7 @@ }, "0.7.3": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching", "EmptyByteArrayCopy" @@ -1494,6 +1506,7 @@ }, "0.7.4": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" ], @@ -1501,6 +1514,7 @@ }, "0.7.5": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" ], @@ -1508,6 +1522,7 @@ }, "0.7.6": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" ], @@ -1515,6 +1530,7 @@ }, "0.8.0": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" ], @@ -1522,6 +1538,7 @@ }, "0.8.1": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" ], @@ -1529,6 +1546,7 @@ }, "0.8.2": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory", "KeccakCaching" ], @@ -1536,28 +1554,39 @@ }, "0.8.3": { "bugs": [ + "SignedImmutables", "ABIDecodeTwoDimensionalArrayMemory" ], "released": "2021-03-23" }, "0.8.4": { - "bugs": [], + "bugs": [ + "SignedImmutables" + ], "released": "2021-04-21" }, "0.8.5": { - "bugs": [], + "bugs": [ + "SignedImmutables" + ], "released": "2021-06-10" }, "0.8.6": { - "bugs": [], + "bugs": [ + "SignedImmutables" + ], "released": "2021-06-22" }, "0.8.7": { - "bugs": [], + "bugs": [ + "SignedImmutables" + ], "released": "2021-08-11" }, "0.8.8": { - "bugs": [], + "bugs": [ + "SignedImmutables" + ], "released": "2021-09-27" } } \ No newline at end of file From 7e7c68e5bf910b12ee9326dd34926c61261a4a71 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 28 Sep 2021 17:46:00 +0200 Subject: [PATCH 197/232] Changelog entry. --- Changelog.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Changelog.md b/Changelog.md index 995abc949..50cf3b0c6 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,10 +1,7 @@ ### 0.8.9 (unreleased) -Language Features: - - -Compiler Features: - +Important Bugfixes: + * Immutables: Properly perform sign extension on signed immutables. Bugfixes: From 6109b5c3a157115103cce045ecb30f005882e9e6 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Tue, 28 Sep 2021 10:52:09 +0200 Subject: [PATCH 198/232] UserDefinedValueType.storageBytes() is correctly set Previously it returned 32 bytes for all types, which was wasteful. This commit changes it to return the storage bytes of the underlying type. --- Changelog.md | 1 + libsolidity/ast/Types.h | 21 +++ .../storage_layout_user_defined/args | 1 + .../storage_layout_user_defined/err | 2 + .../storage_layout_user_defined/input.sol | 16 ++ .../storage_layout_user_defined/output | 4 + .../userDefinedValueType/storage_layout.sol | 74 ++++++++ .../storage_layout_struct.sol | 167 ++++++++++++++++++ 8 files changed, 286 insertions(+) create mode 100644 test/cmdlineTests/storage_layout_user_defined/args create mode 100644 test/cmdlineTests/storage_layout_user_defined/err create mode 100644 test/cmdlineTests/storage_layout_user_defined/input.sol create mode 100644 test/cmdlineTests/storage_layout_user_defined/output create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/storage_layout.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/storage_layout_struct.sol diff --git a/Changelog.md b/Changelog.md index 50cf3b0c6..8f8489d1d 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,7 @@ Important Bugfixes: * Immutables: Properly perform sign extension on signed immutables. + * User Defined Value Type: Fix storage layout of user defined value types for underlying types shorter than 32 bytes. Bugfixes: diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 3e6c52467..2220875b1 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -1108,6 +1108,8 @@ public: bool leftAligned() const override { return underlyingType().leftAligned(); } bool canBeStored() const override { return underlyingType().canBeStored(); } u256 storageSize() const override { return underlyingType().storageSize(); } + unsigned storageBytes() const override { return underlyingType().storageBytes(); } + bool isValueType() const override { solAssert(underlyingType().isValueType(), ""); @@ -1119,6 +1121,25 @@ public: return true; } + bool containsNestedMapping() const override + { + solAssert(nameable(), "Called for a non nameable type."); + solAssert(!underlyingType().containsNestedMapping(), ""); + return false; + } + + bool hasSimpleZeroValueInMemory() const override + { + solAssert(underlyingType().hasSimpleZeroValueInMemory(), ""); + return true; + } + + bool dataStoredIn(DataLocation _loc) const override + { + solAssert(!underlyingType().dataStoredIn(_loc), ""); + return false; + } + std::string toString(bool _short) const override; std::string canonicalName() const override { solAssert(false, ""); } std::string signatureInExternalFunction(bool) const override { solAssert(false, ""); } diff --git a/test/cmdlineTests/storage_layout_user_defined/args b/test/cmdlineTests/storage_layout_user_defined/args new file mode 100644 index 000000000..f69ac4e39 --- /dev/null +++ b/test/cmdlineTests/storage_layout_user_defined/args @@ -0,0 +1 @@ +--storage-layout diff --git a/test/cmdlineTests/storage_layout_user_defined/err b/test/cmdlineTests/storage_layout_user_defined/err new file mode 100644 index 000000000..a9b5f07b1 --- /dev/null +++ b/test/cmdlineTests/storage_layout_user_defined/err @@ -0,0 +1,2 @@ +Warning: Source file does not specify required compiler version! +--> storage_layout_user_defined/input.sol diff --git a/test/cmdlineTests/storage_layout_user_defined/input.sol b/test/cmdlineTests/storage_layout_user_defined/input.sol new file mode 100644 index 000000000..f07020081 --- /dev/null +++ b/test/cmdlineTests/storage_layout_user_defined/input.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL v3 +type MyInt128 is int128; +type MyInt8 is int8; +contract C { + // slot 0 + MyInt128 a; + MyInt128 b; + // slot 1 + MyInt128 c; + MyInt8 d; + MyInt8 e; + MyInt8 f; + MyInt8 g; + // slot 2 + MyInt8 h; +} diff --git a/test/cmdlineTests/storage_layout_user_defined/output b/test/cmdlineTests/storage_layout_user_defined/output new file mode 100644 index 000000000..0f6890dae --- /dev/null +++ b/test/cmdlineTests/storage_layout_user_defined/output @@ -0,0 +1,4 @@ + +======= storage_layout_user_defined/input.sol:C ======= +Contract Storage Layout: +{"storage":[{"astId":7,"contract":"storage_layout_user_defined/input.sol:C","label":"a","offset":0,"slot":"0","type":"t_userDefinedValueType(MyInt128)2"},{"astId":10,"contract":"storage_layout_user_defined/input.sol:C","label":"b","offset":16,"slot":"0","type":"t_userDefinedValueType(MyInt128)2"},{"astId":13,"contract":"storage_layout_user_defined/input.sol:C","label":"c","offset":0,"slot":"1","type":"t_userDefinedValueType(MyInt128)2"},{"astId":16,"contract":"storage_layout_user_defined/input.sol:C","label":"d","offset":16,"slot":"1","type":"t_userDefinedValueType(MyInt8)4"},{"astId":19,"contract":"storage_layout_user_defined/input.sol:C","label":"e","offset":17,"slot":"1","type":"t_userDefinedValueType(MyInt8)4"},{"astId":22,"contract":"storage_layout_user_defined/input.sol:C","label":"f","offset":18,"slot":"1","type":"t_userDefinedValueType(MyInt8)4"},{"astId":25,"contract":"storage_layout_user_defined/input.sol:C","label":"g","offset":19,"slot":"1","type":"t_userDefinedValueType(MyInt8)4"},{"astId":28,"contract":"storage_layout_user_defined/input.sol:C","label":"h","offset":20,"slot":"1","type":"t_userDefinedValueType(MyInt8)4"}],"types":{"t_userDefinedValueType(MyInt128)2":{"encoding":"inplace","label":"MyInt128","numberOfBytes":"16"},"t_userDefinedValueType(MyInt8)4":{"encoding":"inplace","label":"MyInt8","numberOfBytes":"1"}}} diff --git a/test/libsolidity/semanticTests/userDefinedValueType/storage_layout.sol b/test/libsolidity/semanticTests/userDefinedValueType/storage_layout.sol new file mode 100644 index 000000000..aab0b86d8 --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/storage_layout.sol @@ -0,0 +1,74 @@ +type MyInt8 is int8; +type MyAddress is address; +type MyInt96 is int96; + +contract C { + MyInt8 a; + MyInt8 b; + MyInt8 c; + MyAddress d; + + MyAddress e; + + MyAddress f; + MyInt96 g; + + function storage_a() pure external returns(uint slot, uint offset) { + assembly { + slot := a.slot + offset := a.offset + } + } + + function storage_b() pure external returns(uint slot, uint offset) { + assembly { + slot := b.slot + offset := b.offset + } + } + + function storage_c() pure external returns(uint slot, uint offset) { + assembly { + slot := d.slot + offset := c.offset + } + } + function storage_d() pure external returns(uint slot, uint offset) { + assembly { + slot := d.slot + offset := d.offset + } + } + + function storage_e() pure external returns(uint slot, uint offset) { + assembly { + slot := e.slot + offset := e.offset + } + } + + function storage_f() pure external returns(uint slot, uint offset) { + assembly { + slot := f.slot + offset := f.offset + } + } + + function storage_g() pure external returns(uint slot, uint offset) { + assembly { + slot := g.slot + offset := g.offset + } + } + +} +// ==== +// compileViaYul: also +// ---- +// storage_a() -> 0, 0 +// storage_b() -> 0, 1 +// storage_c() -> 0, 2 +// storage_d() -> 0, 3 +// storage_e() -> 1, 0 +// storage_f() -> 2, 0 +// storage_g() -> 2, 0x14 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/storage_layout_struct.sol b/test/libsolidity/semanticTests/userDefinedValueType/storage_layout_struct.sol new file mode 100644 index 000000000..445cd3d00 --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/storage_layout_struct.sol @@ -0,0 +1,167 @@ +type MyInt64 is int64; +struct HalfSlot { + MyInt64 a; + MyInt64 b; +} + +struct RegularHalfSlot { + int64 a; + int64 b; +} + +type MyAddress is address; +type MyInt96 is int96; +struct FullSlot { + MyInt96 a; + MyAddress b; +} +struct RegularFullSlot { + int96 a; + address b; +} + +contract C { + HalfSlot public a; + RegularHalfSlot public ra; + + HalfSlot public b; + RegularHalfSlot public rb; + + HalfSlot public c; + RegularHalfSlot public rc; + + FullSlot public d; + RegularFullSlot public rd; + + function storage_a() pure external returns(uint slot, uint offset) { + assembly { + slot := a.slot + offset := a.offset + } + } + + function storage_ra() pure external returns(uint slot, uint offset) { + assembly { + slot := ra.slot + offset := ra.offset + } + } + + function storage_b() pure external returns(uint slot, uint offset) { + assembly { + slot := b.slot + offset := b.offset + } + } + + function storage_rb() pure external returns(uint slot, uint offset) { + assembly { + slot := rb.slot + offset := rb.offset + } + } + + function storage_c() pure external returns(uint slot, uint offset) { + assembly { + slot := c.slot + offset := c.offset + } + } + + function storage_rc() pure external returns(uint slot, uint offset) { + assembly { + slot := rc.slot + offset := rc.offset + } + } + + function storage_d() pure external returns(uint slot, uint offset) { + assembly { + slot := d.slot + offset := d.offset + } + } + + function storage_rd() pure external returns(uint slot, uint offset) { + assembly { + slot := rd.slot + offset := rd.offset + } + } + + + function set_a(MyInt64 _a, MyInt64 _b) external { + a.a = _a; + a.b = _b; + } + + function set_ra(int64 _a, int64 _b) external { + ra.a = _a; + ra.b = _b; + } + + function set_b(MyInt64 _a, MyInt64 _b) external { + b.a = _a; + b.b = _b; + } + + function set_rb(int64 _a, int64 _b) external { + rb.a = _a; + rb.b = _b; + } + + function set_c(MyInt64 _a, MyInt64 _b) external { + c.a = _a; + c.b = _b; + } + + function set_rc(int64 _a, int64 _b) external { + rc.a = _a; + rc.b = _b; + } + + function set_d(MyInt96 _a, MyAddress _b) external { + d.a = _a; + d.b = _b; + } + + function set_rd(int96 _a, address _b) external { + rd.a = _a; + rd.b = _b; + } + + function read_slot(uint slot) view external returns (uint value) { + assembly { + value := sload(slot) + } + } + +} + +// ==== +// compileViaYul: also +// ---- +// storage_a() -> 0, 0 +// set_a(int64,int64): 100, 200 -> +// read_slot(uint256): 0 -> 0xc80000000000000064 +// storage_ra() -> 1, 0 +// set_ra(int64,int64): 100, 200 -> +// read_slot(uint256): 1 -> 0xc80000000000000064 +// storage_b() -> 2, 0 +// set_b(int64,int64): 0, 200 -> +// read_slot(uint256): 2 -> 3689348814741910323200 +// storage_rb() -> 3, 0 +// set_rb(int64,int64): 0, 200 -> +// read_slot(uint256): 3 -> 3689348814741910323200 +// storage_c() -> 4, 0 +// set_c(int64,int64): 100, 0 -> +// read_slot(uint256): 4 -> 0x64 +// storage_rc() -> 5, 0 +// set_rc(int64,int64): 100, 0 -> +// read_slot(uint256): 5 -> 0x64 +// storage_d() -> 6, 0 +// set_d(int96,address): 39614081257132168796771975167, 1461501637330902918203684832716283019655932542975 -> +// read_slot(uint256): 6 -> -39614081257132168796771975169 +// storage_rd() -> 7, 0 +// set_rd(int96,address): 39614081257132168796771975167, 1461501637330902918203684832716283019655932542975 -> +// read_slot(uint256): 7 -> -39614081257132168796771975169 From da5c5928fe403ebad08f7ec6e1d9e54999a19ec4 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 28 Sep 2021 14:21:39 +0200 Subject: [PATCH 199/232] Properly handle fixed-byte-like types. --- libsolidity/ast/Types.cpp | 1 + libsolidity/codegen/CompilerUtils.cpp | 18 +++++++++--------- libsolidity/codegen/LValue.cpp | 12 ++++++++---- libsolidity/codegen/YulUtilFunctions.cpp | 3 ++- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 3173d2763..5d624c26d 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2537,6 +2537,7 @@ Type const& UserDefinedValueType::underlyingType() const { Type const* type = m_definition.underlyingType()->annotation().type; solAssert(type, ""); + solAssert(type->category() != Category::UserDefinedValueType, ""); return *type; } diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index b27bd7930..5e49868a3 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1552,10 +1552,13 @@ void CompilerUtils::storeStringData(bytesConstRef _data) unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWords) { solAssert(_type.isValueType(), ""); + Type const* type = &_type; + if (auto const* userDefined = dynamic_cast(type)) + type = &userDefined->underlyingType(); - unsigned numBytes = _type.calldataEncodedSize(_padToWords); + unsigned numBytes = type->calldataEncodedSize(_padToWords); bool isExternalFunctionType = false; - if (auto const* funType = dynamic_cast(&_type)) + if (auto const* funType = dynamic_cast(type)) if (funType->kind() == FunctionType::Kind::External) isExternalFunctionType = true; if (numBytes == 0) @@ -1570,21 +1573,20 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda splitExternalFunctionType(true); else if (numBytes != 32) { - bool leftAligned = _type.category() == Type::Category::FixedBytes; // add leading or trailing zeros by dividing/multiplying depending on alignment unsigned shiftFactor = (32 - numBytes) * 8; rightShiftNumberOnStack(shiftFactor); - if (leftAligned) + if (type->leftAligned()) { leftShiftNumberOnStack(shiftFactor); cleanupNeeded = false; } - else if (IntegerType const* intType = dynamic_cast(&_type)) + else if (IntegerType const* intType = dynamic_cast(type)) if (!intType->isSigned()) cleanupNeeded = false; } if (_fromCalldata) - convertType(_type, _type, cleanupNeeded, false, true); + convertType(_type, *type, cleanupNeeded, false, true); return numBytes; } @@ -1639,12 +1641,10 @@ unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWords, "Memory store of more than 32 bytes requested (Type: " + _type.toString(true) + ")." ); - bool leftAligned = _type.category() == Type::Category::FixedBytes; - if (_cleanup) convertType(_type, _type, true); - if (numBytes != 32 && !leftAligned && !_padToWords) + if (numBytes != 32 && !_type.leftAligned() && !_padToWords) // shift the value accordingly before storing leftShiftNumberOnStack((32 - numBytes) * 8); diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index 75a7f2749..01befb8a4 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -113,6 +113,7 @@ void MemoryItem::storeValue(Type const& _sourceType, SourceLocation const&, bool if (!m_padded) { solAssert(m_dataType->calldataEncodedSize(false) == 1, "Invalid non-padded type."); + solAssert(m_dataType->category() != Type::Category::UserDefinedValueType, ""); if (m_dataType->category() == Type::Category::FixedBytes) m_context << u256(0) << Instruction::BYTE; m_context << Instruction::SWAP1 << Instruction::MSTORE8; @@ -233,7 +234,7 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const if (m_dataType->category() == Type::Category::FixedPoint) // implementation should be very similar to the integer case. solUnimplemented("Not yet implemented - FixedPointType."); - if (m_dataType->category() == Type::Category::FixedBytes) + if (m_dataType->leftAligned()) { CompilerUtils(m_context).leftShiftNumberOnStack(256 - 8 * m_dataType->storageBytes()); cleaned = true; @@ -329,10 +330,13 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc Instruction::AND; } } - else if (m_dataType->category() == Type::Category::FixedBytes) + else if (m_dataType->leftAligned()) { - solAssert(_sourceType.category() == Type::Category::FixedBytes, "source not fixed bytes"); - CompilerUtils(m_context).rightShiftNumberOnStack(256 - 8 * dynamic_cast(*m_dataType).numBytes()); + solAssert(_sourceType.category() == Type::Category::FixedBytes || ( + _sourceType.encodingType() && + _sourceType.encodingType()->category() == Type::Category::FixedBytes + ), "source not fixed bytes"); + CompilerUtils(m_context).rightShiftNumberOnStack(256 - 8 * m_dataType->storageBytes()); } else { diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index bb56c43df..ea3dd4526 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -2965,7 +2965,7 @@ string YulUtilFunctions::prepareStoreFunction(Type const& _type) } )"); templ("functionName", functionName); - if (_type.category() == Type::Category::FixedBytes) + if (_type.leftAligned()) templ("actualPrepare", shiftRightFunction(256 - 8 * _type.storageBytes()) + "(value)"); else templ("actualPrepare", "value"); @@ -3304,6 +3304,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) bodyTemplate("cleanOutput", cleanupFunction(_to)); string convert; + solAssert(_to.category() != Type::Category::UserDefinedValueType, ""); if (auto const* toFixedBytes = dynamic_cast(&_to)) convert = shiftLeftFunction(256 - toFixedBytes->numBytes() * 8); else if (dynamic_cast(&_to)) From 7b7e38768c1eb29a3e139f43075e6758074009d0 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Tue, 28 Sep 2021 10:54:12 +0200 Subject: [PATCH 200/232] Update tests. --- .../semanticTests/userDefinedValueType/calldata.sol | 12 ++++++------ .../userDefinedValueType/dirty_slot.sol | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol b/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol index 98b73acc2..3596d2c99 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/calldata.sol @@ -51,13 +51,13 @@ contract C { // compileViaYul: also // ---- // test_f() -> true -// gas irOptimized: 122656 -// gas legacy: 125037 -// gas legacyOptimized: 122605 +// gas irOptimized: 122887 +// gas legacy: 126168 +// gas legacyOptimized: 123199 // test_g() -> true -// gas irOptimized: 95908 -// gas legacy: 100586 -// gas legacyOptimized: 95996 +// gas irOptimized: 96673 +// gas legacy: 101311 +// gas legacyOptimized: 96566 // addresses(uint256): 0 -> 0x18 // addresses(uint256): 1 -> 0x19 // addresses(uint256): 3 -> 0x1b diff --git a/test/libsolidity/semanticTests/userDefinedValueType/dirty_slot.sol b/test/libsolidity/semanticTests/userDefinedValueType/dirty_slot.sol index 4e500f53a..a74d02ff1 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/dirty_slot.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/dirty_slot.sol @@ -31,7 +31,7 @@ contract C { // write_a() -> // a() -> 0x2001 // write_b() -> -// b() -> 0xf00e000000000000000000000000000000000000000000000000000000000000 -// get_b(uint256): 0 -> 0xf000000000000000000000000000000000000000000000000000000000000000 -// get_b(uint256): 1 -> 0x0e00000000000000000000000000000000000000000000000000000000000000 +// b() -> 0x5403000000000000000000000000000000000000000000000000000000000000 +// get_b(uint256): 0 -> 0x5400000000000000000000000000000000000000000000000000000000000000 +// get_b(uint256): 1 -> 0x0300000000000000000000000000000000000000000000000000000000000000 // get_b(uint256): 2 -> FAILURE, hex"4e487b71", 0x32 From cb052611cf1c50aa095efc92e098d6ce986b93d6 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 28 Sep 2021 15:39:18 +0200 Subject: [PATCH 201/232] Fix signextend for user defined value types. --- libsolidity/codegen/LValue.cpp | 21 ++++++++++++--------- libsolidity/codegen/YulUtilFunctions.cpp | 15 +++++++++------ 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index 01befb8a4..2ff69e4ac 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -227,27 +227,30 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const m_context << Instruction::POP << Instruction::SLOAD; else { + Type const* type = m_dataType; + if (type->category() == Type::Category::UserDefinedValueType) + type = type->encodingType(); bool cleaned = false; m_context << Instruction::SWAP1 << Instruction::SLOAD << Instruction::SWAP1 << u256(0x100) << Instruction::EXP << Instruction::SWAP1 << Instruction::DIV; - if (m_dataType->category() == Type::Category::FixedPoint) + if (type->category() == Type::Category::FixedPoint) // implementation should be very similar to the integer case. solUnimplemented("Not yet implemented - FixedPointType."); - if (m_dataType->leftAligned()) + if (type->leftAligned()) { - CompilerUtils(m_context).leftShiftNumberOnStack(256 - 8 * m_dataType->storageBytes()); + CompilerUtils(m_context).leftShiftNumberOnStack(256 - 8 * type->storageBytes()); cleaned = true; } else if ( - m_dataType->category() == Type::Category::Integer && - dynamic_cast(*m_dataType).isSigned() + type->category() == Type::Category::Integer && + dynamic_cast(*type).isSigned() ) { - m_context << u256(m_dataType->storageBytes() - 1) << Instruction::SIGNEXTEND; + m_context << u256(type->storageBytes() - 1) << Instruction::SIGNEXTEND; cleaned = true; } - else if (FunctionType const* fun = dynamic_cast(m_dataType)) + else if (FunctionType const* fun = dynamic_cast(type)) { if (fun->kind() == FunctionType::Kind::External) { @@ -263,8 +266,8 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const } if (!cleaned) { - solAssert(m_dataType->sizeOnStack() == 1, ""); - m_context << ((u256(0x1) << (8 * m_dataType->storageBytes())) - 1) << Instruction::AND; + solAssert(type->sizeOnStack() == 1, ""); + m_context << ((u256(0x1) << (8 * type->storageBytes())) - 1) << Instruction::AND; } } } diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index ea3dd4526..7f6f48e26 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -2912,9 +2912,12 @@ string YulUtilFunctions::cleanupFromStorageFunction(Type const& _type) )"); templ("functionName", functionName); - unsigned storageBytes = _type.storageBytes(); - if (IntegerType const* type = dynamic_cast(&_type)) - if (type->isSigned() && storageBytes != 32) + Type const* encodingType = &_type; + if (_type.category() == Type::Category::UserDefinedValueType) + encodingType = _type.encodingType(); + unsigned storageBytes = encodingType->storageBytes(); + if (IntegerType const* intType = dynamic_cast(encodingType)) + if (intType->isSigned() && storageBytes != 32) { templ("cleaned", "signextend(" + to_string(storageBytes - 1) + ", value)"); return templ.render(); @@ -2922,10 +2925,10 @@ string YulUtilFunctions::cleanupFromStorageFunction(Type const& _type) bool leftAligned = false; if ( - _type.category() != Type::Category::Function || - dynamic_cast(_type).kind() == FunctionType::Kind::External + encodingType->category() != Type::Category::Function || + dynamic_cast(*encodingType).kind() == FunctionType::Kind::External ) - leftAligned = _type.leftAligned(); + leftAligned = encodingType->leftAligned(); if (storageBytes == 32) templ("cleaned", "value"); From 77932edb02f429ac7d0cf664c6fd6aed3a656fb5 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 28 Sep 2021 16:07:43 +0200 Subject: [PATCH 202/232] Consider non-external functions not left-aligned. --- libsolidity/ast/Types.cpp | 5 +---- libsolidity/codegen/LValue.cpp | 27 ++++++++++++------------ libsolidity/codegen/YulUtilFunctions.cpp | 9 +------- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 5d624c26d..b1a77cf89 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -3072,10 +3072,7 @@ u256 FunctionType::storageSize() const bool FunctionType::leftAligned() const { - if (m_kind == Kind::External) - return true; - else - solAssert(false, "Alignment property of non-exportable function type requested."); + return m_kind == Kind::External; } unsigned FunctionType::storageBytes() const diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index 2ff69e4ac..b77141445 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -237,19 +237,6 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const if (type->category() == Type::Category::FixedPoint) // implementation should be very similar to the integer case. solUnimplemented("Not yet implemented - FixedPointType."); - if (type->leftAligned()) - { - CompilerUtils(m_context).leftShiftNumberOnStack(256 - 8 * type->storageBytes()); - cleaned = true; - } - else if ( - type->category() == Type::Category::Integer && - dynamic_cast(*type).isSigned() - ) - { - m_context << u256(type->storageBytes() - 1) << Instruction::SIGNEXTEND; - cleaned = true; - } else if (FunctionType const* fun = dynamic_cast(type)) { if (fun->kind() == FunctionType::Kind::External) @@ -264,6 +251,20 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const m_context << Instruction::MUL << Instruction::OR; } } + else if (type->leftAligned()) + { + CompilerUtils(m_context).leftShiftNumberOnStack(256 - 8 * type->storageBytes()); + cleaned = true; + } + else if ( + type->category() == Type::Category::Integer && + dynamic_cast(*type).isSigned() + ) + { + m_context << u256(type->storageBytes() - 1) << Instruction::SIGNEXTEND; + cleaned = true; + } + if (!cleaned) { solAssert(type->sizeOnStack() == 1, ""); diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 7f6f48e26..9da1d5063 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -2923,16 +2923,9 @@ string YulUtilFunctions::cleanupFromStorageFunction(Type const& _type) return templ.render(); } - bool leftAligned = false; - if ( - encodingType->category() != Type::Category::Function || - dynamic_cast(*encodingType).kind() == FunctionType::Kind::External - ) - leftAligned = encodingType->leftAligned(); - if (storageBytes == 32) templ("cleaned", "value"); - else if (leftAligned) + else if (encodingType->leftAligned()) templ("cleaned", shiftLeftFunction(256 - 8 * storageBytes) + "(value)"); else templ("cleaned", "and(value, " + toCompactHexWithPrefix((u256(1) << (8 * storageBytes)) - 1) + ")"); From 090a46c2a5e1c2a614934a2b5e72852920e5a30f Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 28 Sep 2021 15:19:15 +0200 Subject: [PATCH 203/232] New tests. --- .../userDefinedValueType/dirty_uint8_read.sol | 26 ++++++++++++++ .../userDefinedValueType/immutable_signed.sol | 21 +++++++++++ .../userDefinedValueType/storage_signed.sol | 35 +++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/dirty_uint8_read.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/immutable_signed.sol create mode 100644 test/libsolidity/semanticTests/userDefinedValueType/storage_signed.sol diff --git a/test/libsolidity/semanticTests/userDefinedValueType/dirty_uint8_read.sol b/test/libsolidity/semanticTests/userDefinedValueType/dirty_uint8_read.sol new file mode 100644 index 000000000..4100e17f8 --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/dirty_uint8_read.sol @@ -0,0 +1,26 @@ +type MyInt8 is int8; +contract C { + MyInt8 public x = MyInt8.wrap(-5); + + /// The most significant bit is flipped to 0 + function create_dirty_slot() external { + uint mask = 2**255 -1; + assembly { + let value := sload(x.slot) + sstore(x.slot, and(mask, value)) + } + } + + function read_unclean_value() external returns (bytes32 ret) { + MyInt8 value = x; + assembly { + ret := value + } + } +} +// ==== +// compileViaYul: also +// ---- +// x() -> -5 +// create_dirty_slot() -> +// read_unclean_value() -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb diff --git a/test/libsolidity/semanticTests/userDefinedValueType/immutable_signed.sol b/test/libsolidity/semanticTests/userDefinedValueType/immutable_signed.sol new file mode 100644 index 000000000..8923984a4 --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/immutable_signed.sol @@ -0,0 +1,21 @@ +type MyInt is int16; +type MyBytes is bytes2; +contract C { + MyInt immutable a = MyInt.wrap(-2); + MyBytes immutable b = MyBytes.wrap("ab"); + function() internal returns (uint) immutable f = g; + function direct() view external returns (MyInt, MyBytes) { + return (a, b); + } + function viaasm() view external returns (bytes32 x, bytes32 y) { + MyInt _a = a; + MyBytes _b = b; + assembly { x := _a y := _b } + } + function g() internal pure returns (uint) { return 2; } +} +// ==== +// compileViaYul: also +// ---- +// direct() -> -2, 0x6162000000000000000000000000000000000000000000000000000000000000 +// viaasm() -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 0x6162000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/storage_signed.sol b/test/libsolidity/semanticTests/userDefinedValueType/storage_signed.sol new file mode 100644 index 000000000..80745866a --- /dev/null +++ b/test/libsolidity/semanticTests/userDefinedValueType/storage_signed.sol @@ -0,0 +1,35 @@ +type MyInt is int16; +contract C { + bytes2 first = "ab"; + MyInt public a = MyInt.wrap(-2); + bytes2 third = "ef"; + function direct() external returns (MyInt) { + return a; + } + function indirect() external returns (int16) { + return MyInt.unwrap(a); + } + function toMemDirect() external returns (MyInt[1] memory) { + return [a]; + } + function toMemIndirect() external returns (int16[1] memory) { + return [MyInt.unwrap(a)]; + } + function div() external returns (int16) { + return MyInt.unwrap(a) / 2; + } + function viaasm() external returns (bytes32 x) { + MyInt st = a; + assembly { x := st } + } +} +// ==== +// compileViaYul: also +// ---- +// a() -> -2 +// direct() -> -2 +// indirect() -> -2 +// toMemDirect() -> -2 +// toMemIndirect() -> -2 +// div() -> -1 +// viaasm() -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe From 9d8a0a6f829ee9cbee06e1c84f3ff2ccd5b7e250 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Wed, 29 Sep 2021 11:43:40 +0200 Subject: [PATCH 204/232] Buglist entry for UserDefinedValueTypesBug --- docs/bugs.json | 11 +++++++++++ docs/bugs_by_version.json | 1 + 2 files changed, 12 insertions(+) diff --git a/docs/bugs.json b/docs/bugs.json index f6ce8f6fe..0b72c05c7 100644 --- a/docs/bugs.json +++ b/docs/bugs.json @@ -1,4 +1,15 @@ [ + { + "uid": "SOL-2021-4", + "name": "UserDefinedValueTypesBug", + "summary": "User defined value types with underlying type shorter than 32 bytes used incorrect storage layout and wasted storage", + "description": "The compiler did not correctly compute the storage layout of user defined value types based on types that are shorter than 32 bytes. It would always use a full storage slot for these types, even if the underlying type was shorter. This was wasteful and might have problems with tooling or contract upgrades.", + "link": "https://blog.soliditylang.org/2021/09/29/user-defined-value-types-bug/", + "introduced": "0.8.8", + "fixed": "0.8.9", + "severity": "very low" + + }, { "uid": "SOL-2021-3", "name": "SignedImmutables", diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index c6af59bda..bfba53e45 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1585,6 +1585,7 @@ }, "0.8.8": { "bugs": [ + "UserDefinedValueTypesBug", "SignedImmutables" ], "released": "2021-09-27" From 78a1c1ca6d56e9a81d89ddf1af5a163dad8b17fe Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 29 Sep 2021 13:22:13 +0200 Subject: [PATCH 205/232] Add one more test case. --- .../userDefinedValueType/storage_layout_struct.sol | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/libsolidity/semanticTests/userDefinedValueType/storage_layout_struct.sol b/test/libsolidity/semanticTests/userDefinedValueType/storage_layout_struct.sol index 445cd3d00..219145a57 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/storage_layout_struct.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/storage_layout_struct.sol @@ -136,6 +136,19 @@ contract C { } } + function read_contents_asm() external returns (bytes32 rxa, bytes32 rya, bytes32 rxb, bytes32 ryb) { + b.a = MyInt64.wrap(-2); + b.b = MyInt64.wrap(-3); + HalfSlot memory x = b; + MyInt64 y = b.a; + MyInt64 z = b.b; + assembly { + rxa := mload(x) + rya := y + rxb := mload(add(x, 0x20)) + ryb := z + } + } } // ==== @@ -165,3 +178,4 @@ contract C { // storage_rd() -> 7, 0 // set_rd(int96,address): 39614081257132168796771975167, 1461501637330902918203684832716283019655932542975 -> // read_slot(uint256): 7 -> -39614081257132168796771975169 +// read_contents_asm() -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe, 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd, 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd From e347c983b509abf504b4613d3e18b95c5a969472 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 29 Sep 2021 13:25:37 +0200 Subject: [PATCH 206/232] Update gas costs. --- .../userDefinedValueType/calldata_to_storage.sol | 12 ++++++------ .../userDefinedValueType/memory_to_storage.sol | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol b/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol index 72c9db1bf..7f5a060e4 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol @@ -25,19 +25,19 @@ contract C { // ---- // s() -> 0, 0, 0x00, 0 // f((uint8,uint16,bytes2,uint8)): 1, 0xff, "ab", 15 -> -// gas irOptimized: 110778 +// gas irOptimized: 44860 // gas legacy: 112851 -// gas legacyOptimized: 110766 +// gas legacyOptimized: 44923 // s() -> 1, 0xff, 0x6162000000000000000000000000000000000000000000000000000000000000, 15 // g(uint16[]): 0x20, 3, 1, 2, 3 -> 0x20, 3, 1, 2, 3 -// gas irOptimized: 112669 +// gas irOptimized: 69306 // gas legacy: 113715 -// gas legacyOptimized: 112488 +// gas legacyOptimized: 74255 // small(uint256): 0 -> 1 // small(uint256): 1 -> 2 // h(bytes2[]): 0x20, 3, "ab", "cd", "ef" -> 0x20, 3, "ab", "cd", "ef" -// gas irOptimized: 112797 +// gas irOptimized: 69510 // gas legacy: 113414 -// gas legacyOptimized: 112572 +// gas legacyOptimized: 74342 // l(uint256): 0 -> 0x6162000000000000000000000000000000000000000000000000000000000000 // l(uint256): 1 -> 0x6364000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/memory_to_storage.sol b/test/libsolidity/semanticTests/userDefinedValueType/memory_to_storage.sol index 2ed2b72db..526a19bac 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/memory_to_storage.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/memory_to_storage.sol @@ -25,19 +25,19 @@ contract C { // ---- // s() -> 0, 0, 0x00, 0 // f((uint8,uint16,bytes2,uint8)): 1, 0xff, "ab", 15 -> -// gas irOptimized: 110788 +// gas irOptimized: 44551 // gas legacy: 111668 -// gas legacyOptimized: 110908 +// gas legacyOptimized: 44671 // s() -> 1, 0xff, 0x6162000000000000000000000000000000000000000000000000000000000000, 15 // g(uint16[]): 0x20, 3, 1, 2, 3 -> 0x20, 3, 1, 2, 3 -// gas irOptimized: 113144 +// gas irOptimized: 69671 // gas legacy: 114806 -// gas legacyOptimized: 113085 +// gas legacyOptimized: 74834 // small(uint256): 0 -> 1 // small(uint256): 1 -> 2 // h(bytes2[]): 0x20, 3, "ab", "cd", "ef" -> 0x20, 3, "ab", "cd", "ef" -// gas irOptimized: 113317 +// gas irOptimized: 69928 // gas legacy: 114496 -// gas legacyOptimized: 113214 +// gas legacyOptimized: 74921 // l(uint256): 0 -> 0x6162000000000000000000000000000000000000000000000000000000000000 // l(uint256): 1 -> 0x6364000000000000000000000000000000000000000000000000000000000000 From 14a678eb677e30d0f4f0e4aaf84ac6968bb379d8 Mon Sep 17 00:00:00 2001 From: hrkrshnn Date: Wed, 29 Sep 2021 13:50:51 +0200 Subject: [PATCH 207/232] Fix gas stats --- .../userDefinedValueType/calldata_to_storage.sol | 6 +++--- .../userDefinedValueType/memory_to_storage.sol | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol b/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol index 7f5a060e4..9827d6cd1 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/calldata_to_storage.sol @@ -26,18 +26,18 @@ contract C { // s() -> 0, 0, 0x00, 0 // f((uint8,uint16,bytes2,uint8)): 1, 0xff, "ab", 15 -> // gas irOptimized: 44860 -// gas legacy: 112851 +// gas legacy: 47200 // gas legacyOptimized: 44923 // s() -> 1, 0xff, 0x6162000000000000000000000000000000000000000000000000000000000000, 15 // g(uint16[]): 0x20, 3, 1, 2, 3 -> 0x20, 3, 1, 2, 3 // gas irOptimized: 69306 -// gas legacy: 113715 +// gas legacy: 75466 // gas legacyOptimized: 74255 // small(uint256): 0 -> 1 // small(uint256): 1 -> 2 // h(bytes2[]): 0x20, 3, "ab", "cd", "ef" -> 0x20, 3, "ab", "cd", "ef" // gas irOptimized: 69510 -// gas legacy: 113414 +// gas legacy: 75156 // gas legacyOptimized: 74342 // l(uint256): 0 -> 0x6162000000000000000000000000000000000000000000000000000000000000 // l(uint256): 1 -> 0x6364000000000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/userDefinedValueType/memory_to_storage.sol b/test/libsolidity/semanticTests/userDefinedValueType/memory_to_storage.sol index 526a19bac..e1a7c1c5b 100644 --- a/test/libsolidity/semanticTests/userDefinedValueType/memory_to_storage.sol +++ b/test/libsolidity/semanticTests/userDefinedValueType/memory_to_storage.sol @@ -26,18 +26,18 @@ contract C { // s() -> 0, 0, 0x00, 0 // f((uint8,uint16,bytes2,uint8)): 1, 0xff, "ab", 15 -> // gas irOptimized: 44551 -// gas legacy: 111668 +// gas legacy: 46213 // gas legacyOptimized: 44671 // s() -> 1, 0xff, 0x6162000000000000000000000000000000000000000000000000000000000000, 15 // g(uint16[]): 0x20, 3, 1, 2, 3 -> 0x20, 3, 1, 2, 3 // gas irOptimized: 69671 -// gas legacy: 114806 +// gas legacy: 76557 // gas legacyOptimized: 74834 // small(uint256): 0 -> 1 // small(uint256): 1 -> 2 // h(bytes2[]): 0x20, 3, "ab", "cd", "ef" -> 0x20, 3, "ab", "cd", "ef" // gas irOptimized: 69928 -// gas legacy: 114496 +// gas legacy: 76238 // gas legacyOptimized: 74921 // l(uint256): 0 -> 0x6162000000000000000000000000000000000000000000000000000000000000 // l(uint256): 1 -> 0x6364000000000000000000000000000000000000000000000000000000000000 From 1a7faef0db867041231dfe18b83720c57aeb023e Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 29 Sep 2021 13:59:41 +0200 Subject: [PATCH 208/232] Set release date. --- Changelog.md | 2 +- docs/bugs_by_version.json | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 8f8489d1d..cb9b55904 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,4 +1,4 @@ -### 0.8.9 (unreleased) +### 0.8.9 (2021-09-29) Important Bugfixes: * Immutables: Properly perform sign extension on signed immutables. diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json index bfba53e45..4324b8339 100644 --- a/docs/bugs_by_version.json +++ b/docs/bugs_by_version.json @@ -1589,5 +1589,9 @@ "SignedImmutables" ], "released": "2021-09-27" + }, + "0.8.9": { + "bugs": [], + "released": "2021-09-29" } } \ No newline at end of file From 82287bd883eac2ee3ad53afc8108b686b1eacd07 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 29 Sep 2021 17:12:04 +0200 Subject: [PATCH 209/232] Set version to 0.8.10. --- CMakeLists.txt | 2 +- Changelog.md | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3fcf42d2a..230aff899 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ include(EthPolicy) eth_policy() # project name and version should be set after cmake_policy CMP0048 -set(PROJECT_VERSION "0.8.9") +set(PROJECT_VERSION "0.8.10") # OSX target needed in order to support std::visit set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX) diff --git a/Changelog.md b/Changelog.md index cb9b55904..96c6dd12e 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,16 @@ +### 0.8.10 (unreleased) + +Language Features: + + +Compiler Features: + + +Bugfixes: + + + + ### 0.8.9 (2021-09-29) Important Bugfixes: From ecded763f11bf889da2b0e22248d527333766028 Mon Sep 17 00:00:00 2001 From: Leo Arias Date: Wed, 29 Sep 2021 17:38:54 -0600 Subject: [PATCH 210/232] Snap: update command path --- snap/snapcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 45a5844b1..d7ead3644 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -19,7 +19,7 @@ confinement: strict apps: solc: - command: solc + command: usr/local/bin/solc plugs: [home] parts: From d25fb29178cb10894eacee77f9485cbc7824b493 Mon Sep 17 00:00:00 2001 From: Leo Alt Date: Mon, 27 Sep 2021 17:45:34 +0200 Subject: [PATCH 211/232] Add isoltest option to ignore OS --- test/libsolidity/SMTCheckerTest.cpp | 15 +++++++++++++++ .../external_calls/call_with_value_1.sol | 12 ++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/test/libsolidity/SMTCheckerTest.cpp b/test/libsolidity/SMTCheckerTest.cpp index 8235ffe2c..5606b0bfe 100644 --- a/test/libsolidity/SMTCheckerTest.cpp +++ b/test/libsolidity/SMTCheckerTest.cpp @@ -66,6 +66,21 @@ SMTCheckerTest::SMTCheckerTest(string const& _filename): SyntaxTest(_filename, E m_ignoreCex = true; else BOOST_THROW_EXCEPTION(runtime_error("Invalid SMT counterexample choice.")); + + auto const& ignoreOSSetting = m_reader.stringSetting("SMTIgnoreOS", "none"); + for (string const& os: ignoreOSSetting | ranges::views::split(',') | ranges::to>()) + { +#ifdef __APPLE__ + if (os == "macos") + m_shouldRun = false; +#elif _WIN32 + if (os == "windows") + m_shouldRun = false; +#elif __linux__ + if (os == "linux") + m_shouldRun = false; +#endif + } } TestCase::TestResult SMTCheckerTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) 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 ed27a4df8..256980225 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/call_with_value_1.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/call_with_value_1.sol @@ -2,13 +2,17 @@ contract C { function g(address payable i) public { require(address(this).balance == 100); i.call{value: 10}(""); - // Disabled due to Spacer nondeterminism - //assert(address(this).balance == 90); // should hold - // Disabled due to Spacer nondeterminism - //assert(address(this).balance == 100); // should fail + assert(address(this).balance == 90); // should hold + assert(address(this).balance == 100); // should fail } } // ==== // SMTEngine: all +// SMTIgnoreOS: macos // ---- // Warning 9302: (96-117): Return value of low-level calls not used. +// Warning 1218: (175-211): CHC: Error trying to invoke SMT solver. +// Warning 6328: (121-156): CHC: Assertion violation might happen here. +// Warning 6328: (175-211): CHC: Assertion violation might happen here. +// Warning 4661: (121-156): BMC: Assertion violation happens here. +// Warning 4661: (175-211): BMC: Assertion violation happens here. From d81ebe97c3c89ce3f333a267b75b21ccbda8ae42 Mon Sep 17 00:00:00 2001 From: Leo Alt Date: Mon, 27 Sep 2021 16:55:59 +0200 Subject: [PATCH 212/232] Fix magic access --- Changelog.md | 1 + libsolidity/formal/SMTEncoder.cpp | 64 +++++++++++-------- .../smtCheckerTests/special/msg_parens_1.sol | 12 ++++ 3 files changed, 50 insertions(+), 27 deletions(-) create mode 100644 test/libsolidity/smtCheckerTests/special/msg_parens_1.sol diff --git a/Changelog.md b/Changelog.md index 96c6dd12e..70e948b88 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ Compiler Features: Bugfixes: + * SMTChecker: Fix internal error in magic type access (``block``, ``msg``, ``tx``). diff --git a/libsolidity/formal/SMTEncoder.cpp b/libsolidity/formal/SMTEncoder.cpp index e011b1756..11ac5ab7a 100644 --- a/libsolidity/formal/SMTEncoder.cpp +++ b/libsolidity/formal/SMTEncoder.cpp @@ -1316,32 +1316,42 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess) solAssert(name == "block" || name == "msg" || name == "tx", ""); defineExpr(_memberAccess, state().txMember(name + "." + _memberAccess.memberName())); } - else if (auto magicType = dynamic_cast(exprType); magicType->kind() == MagicType::Kind::MetaType) + else if (auto magicType = dynamic_cast(exprType)) { - auto const& memberName = _memberAccess.memberName(); - if (memberName == "min" || memberName == "max") + if (magicType->kind() == MagicType::Kind::Block) + defineExpr(_memberAccess, state().txMember("block." + _memberAccess.memberName())); + else if (magicType->kind() == MagicType::Kind::Message) + defineExpr(_memberAccess, state().txMember("msg." + _memberAccess.memberName())); + else if (magicType->kind() == MagicType::Kind::Transaction) + defineExpr(_memberAccess, state().txMember("tx." + _memberAccess.memberName())); + else if (magicType->kind() == MagicType::Kind::MetaType) { - if (IntegerType const* integerType = dynamic_cast(magicType->typeArgument())) - defineExpr(_memberAccess, memberName == "min" ? integerType->minValue() : integerType->maxValue()); - else if (EnumType const* enumType = dynamic_cast(magicType->typeArgument())) - defineExpr(_memberAccess, memberName == "min" ? enumType->minValue() : enumType->maxValue()); + auto const& memberName = _memberAccess.memberName(); + if (memberName == "min" || memberName == "max") + { + if (IntegerType const* integerType = dynamic_cast(magicType->typeArgument())) + defineExpr(_memberAccess, memberName == "min" ? integerType->minValue() : integerType->maxValue()); + else if (EnumType const* enumType = dynamic_cast(magicType->typeArgument())) + defineExpr(_memberAccess, memberName == "min" ? enumType->minValue() : enumType->maxValue()); + } + else if (memberName == "interfaceId") + { + ContractDefinition const& contract = dynamic_cast(*magicType->typeArgument()).contractDefinition(); + defineExpr(_memberAccess, contract.interfaceId()); + } + else + // NOTE: supporting name, creationCode, runtimeCode would be easy enough, but the bytes/string they return are not + // at all usable in the SMT checker currently + m_errorReporter.warning( + 7507_error, + _memberAccess.location(), + "Assertion checker does not yet support this expression." + ); + } - else if (memberName == "interfaceId") - { - ContractDefinition const& contract = dynamic_cast(*magicType->typeArgument()).contractDefinition(); - defineExpr(_memberAccess, contract.interfaceId()); - } - else - // NOTE: supporting name, creationCode, runtimeCode would be easy enough, but the bytes/string they return are not - // at all usable in the SMT checker currently - m_errorReporter.warning( - 7507_error, - _memberAccess.location(), - "Assertion checker does not yet support this expression." - ); } else - solUnimplementedAssert(false, ""); + solAssert(false, ""); return false; } @@ -1419,12 +1429,12 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess) return false; } } - else - m_errorReporter.warning( - 7650_error, - _memberAccess.location(), - "Assertion checker does not yet support this expression." - ); + + m_errorReporter.warning( + 7650_error, + _memberAccess.location(), + "Assertion checker does not yet support this expression." + ); return true; } diff --git a/test/libsolidity/smtCheckerTests/special/msg_parens_1.sol b/test/libsolidity/smtCheckerTests/special/msg_parens_1.sol new file mode 100644 index 000000000..9a1df3724 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/special/msg_parens_1.sol @@ -0,0 +1,12 @@ +contract C { + function f() public payable { + assert((msg).value == 10); + assert((true ? msg : msg).value == 12); + } +} +// ==== +// SMTEngine: all +// SMTIgnoreOS: macos +// ---- +// Warning 6328: (46-71): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f(){ value: 11 } +// Warning 6328: (75-113): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f() From 7915f328529f551219febb838a0fb82911bb09fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 30 Sep 2021 16:17:36 +0200 Subject: [PATCH 213/232] Remove leftovers of compact-format and interface from --combined-json --- scripts/ASTImportTest.sh | 4 ++-- scripts/common_cmdline.sh | 2 +- solc/CommandLineInterface.h | 2 +- solc/CommandLineParser.cpp | 6 +----- test/cmdlineTests/ast_json_import_wrong_evmVersion/args | 2 +- test/stopAfterParseTests.sh | 2 +- 6 files changed, 7 insertions(+), 11 deletions(-) diff --git a/scripts/ASTImportTest.sh b/scripts/ASTImportTest.sh index ba8f33d3c..daf5a6163 100755 --- a/scripts/ASTImportTest.sh +++ b/scripts/ASTImportTest.sh @@ -45,9 +45,9 @@ function testImportExportEquivalence { ! [[ -e stderr.txt ]] || { echo "stderr.txt already exists. Refusing to overwrite."; exit 1; } # save exported json as expected result (silently) - $SOLC --combined-json ast,compact-format --pretty-json "$nth_input_file" "${all_input_files[@]}" > expected.json 2> /dev/null + $SOLC --combined-json ast --pretty-json "$nth_input_file" "${all_input_files[@]}" > expected.json 2> /dev/null # import it, and export it again as obtained result (silently) - if ! $SOLC --import-ast --combined-json ast,compact-format --pretty-json expected.json > obtained.json 2> stderr.txt + if ! $SOLC --import-ast --combined-json ast --pretty-json expected.json > obtained.json 2> stderr.txt then # For investigating, use exit 1 here so the script stops at the # first failing test diff --git a/scripts/common_cmdline.sh b/scripts/common_cmdline.sh index 59c334a4b..6718ca5b5 100644 --- a/scripts/common_cmdline.sh +++ b/scripts/common_cmdline.sh @@ -20,7 +20,7 @@ # ------------------------------------------------------------------------------ YULARGS=(--strict-assembly) -FULLARGS=(--optimize --ignore-missing --combined-json "abi,asm,ast,bin,bin-runtime,compact-format,devdoc,hashes,interface,metadata,opcodes,srcmap,srcmap-runtime,userdoc") +FULLARGS=(--optimize --ignore-missing --combined-json "abi,asm,ast,bin,bin-runtime,devdoc,hashes,metadata,opcodes,srcmap,srcmap-runtime,userdoc") OLDARGS=(--optimize --combined-json "abi,asm,ast,bin,bin-runtime,devdoc,interface,metadata,opcodes,srcmap,srcmap-runtime,userdoc") function compileFull() { diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 582b8f2a4..5504e51bb 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -95,7 +95,7 @@ private: /// Tries to read @ m_sourceCodes as a JSONs holding ASTs /// such that they can be imported into the compiler (importASTs()) - /// (produced by --combined-json ast,compact-format + /// (produced by --combined-json ast /// or standard-json output std::map parseAstFromInput(); diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 059a15a5f..ad6a32f6d 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -63,7 +63,6 @@ static string const g_strAstCompactJson = "ast-compact-json"; static string const g_strBinary = "bin"; static string const g_strBinaryRuntime = "bin-runtime"; static string const g_strCombinedJson = "combined-json"; -static string const g_strCompactJSON = "compact-format"; static string const g_strErrorRecovery = "error-recovery"; static string const g_strEVM = "evm"; static string const g_strEVMVersion = "evm-version"; @@ -75,7 +74,6 @@ static string const g_strGas = "gas"; static string const g_strHelp = "help"; static string const g_strImportAst = "import-ast"; static string const g_strInputFile = "input-file"; -static string const g_strInterface = "interface"; static string const g_strYul = "yul"; static string const g_strYulDialect = "yul-dialect"; static string const g_strIR = "ir"; @@ -146,12 +144,10 @@ static set const g_combinedJsonArgs g_strAst, g_strBinary, g_strBinaryRuntime, - g_strCompactJSON, g_strFunDebug, g_strFunDebugRuntime, g_strGeneratedSources, g_strGeneratedSourcesRuntime, - g_strInterface, g_strMetadata, g_strNatspecUser, g_strNatspecDev, @@ -627,7 +623,7 @@ General Information)").c_str(), g_strImportAst.c_str(), ("Import ASTs to be compiled, assumes input holds the AST in compact JSON format. " "Supported Inputs is the output of the --" + g_strStandardJSON + " or the one produced by " - "--" + g_strCombinedJson + " " + g_strAst + "," + g_strCompactJSON).c_str() + "--" + g_strCombinedJson + " " + g_strAst).c_str() ) ; desc.add(alternativeInputModes); diff --git a/test/cmdlineTests/ast_json_import_wrong_evmVersion/args b/test/cmdlineTests/ast_json_import_wrong_evmVersion/args index 87444708c..d8fddfec6 100644 --- a/test/cmdlineTests/ast_json_import_wrong_evmVersion/args +++ b/test/cmdlineTests/ast_json_import_wrong_evmVersion/args @@ -1 +1 @@ ---evm-version=homestead --import-ast --combined-json ast,compact-format --pretty-json +--evm-version=homestead --import-ast --combined-json ast --pretty-json diff --git a/test/stopAfterParseTests.sh b/test/stopAfterParseTests.sh index 8df15e842..a100146b0 100755 --- a/test/stopAfterParseTests.sh +++ b/test/stopAfterParseTests.sh @@ -18,7 +18,7 @@ cd "$FILETMP" || exit 1 function testFile() { set +e - ALLOUTPUT=$($SOLC --combined-json ast,compact-format --pretty-json "$@" --stop-after parsing 2>&1) + ALLOUTPUT=$($SOLC --combined-json ast --pretty-json "$@" --stop-after parsing 2>&1) local RESULT=$? set -e if test ${RESULT} -ne 0; then From 1247239fe861a18ff4fc4020913767e0a4a4a70d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 30 Sep 2021 16:24:56 +0200 Subject: [PATCH 214/232] CommandLineParser: Replace boost::join() with joinHumanReadable() --- solc/CommandLineParser.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index ad6a32f6d..06bc9373b 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -578,7 +578,7 @@ General Information)").c_str(), ) ( g_strRevertStrings.c_str(), - po::value()->value_name(boost::join(g_revertStringsArgs, ",")), + po::value()->value_name(joinHumanReadable(g_revertStringsArgs, ",")), "Strip revert (and require) reason strings or add additional debugging information." ) ( @@ -632,12 +632,12 @@ General Information)").c_str(), assemblyModeOptions.add_options() ( g_strMachine.c_str(), - po::value()->value_name(boost::join(g_machineArgs, ",")), + po::value()->value_name(joinHumanReadable(g_machineArgs, ",")), "Target machine in assembly or Yul mode." ) ( g_strYulDialect.c_str(), - po::value()->value_name(boost::join(g_yulDialectArgs, ",")), + po::value()->value_name(joinHumanReadable(g_yulDialectArgs, ",")), "Input dialect to use in assembly or yul mode." ) ; @@ -709,7 +709,7 @@ General Information)").c_str(), ) ( g_strCombinedJson.c_str(), - po::value()->value_name(boost::join(g_combinedJsonArgs, ",")), + po::value()->value_name(joinHumanReadable(g_combinedJsonArgs, ",")), "Output a single json document containing the specified information." ) ; @@ -719,7 +719,7 @@ General Information)").c_str(), metadataOptions.add_options() ( g_strMetadataHash.c_str(), - po::value()->value_name(boost::join(g_metadataHashArgs, ",")), + po::value()->value_name(joinHumanReadable(g_metadataHashArgs, ",")), "Choose hash method for the bytecode metadata or disable it." ) ( From 809321e88d9d18a534e6a1f351eea2f471b3044b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 30 Sep 2021 15:51:24 +0200 Subject: [PATCH 215/232] CommandLineParser: componentMap() for CompilerOutputs --- solc/CommandLineParser.cpp | 106 ++++++++++++++----------------------- solc/CommandLineParser.h | 23 ++++++++ 2 files changed, 63 insertions(+), 66 deletions(-) diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 06bc9373b..70b77e512 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -56,10 +56,8 @@ static string const g_strAllowPaths = "allow-paths"; static string const g_strBasePath = "base-path"; static string const g_strIncludePath = "include-path"; static string const g_strAsm = "asm"; -static string const g_strAsmJson = "asm-json"; static string const g_strAssemble = "assemble"; static string const g_strAst = "ast"; -static string const g_strAstCompactJson = "ast-compact-json"; static string const g_strBinary = "bin"; static string const g_strBinaryRuntime = "bin-runtime"; static string const g_strCombinedJson = "combined-json"; @@ -76,8 +74,6 @@ static string const g_strImportAst = "import-ast"; static string const g_strInputFile = "input-file"; static string const g_strYul = "yul"; static string const g_strYulDialect = "yul-dialect"; -static string const g_strIR = "ir"; -static string const g_strIROptimized = "ir-optimized"; static string const g_strIPFS = "ipfs"; static string const g_strLicense = "license"; static string const g_strLibraries = "libraries"; @@ -213,27 +209,22 @@ bool CommandLineParser::checkMutuallyExclusive(vector const& _optionName bool CompilerOutputs::operator==(CompilerOutputs const& _other) const noexcept { - static_assert( - sizeof(*this) == 15 * sizeof(bool), - "Remember to update code below if you add/remove fields." - ); + for (bool CompilerOutputs::* member: componentMap() | ranges::views::values) + if (this->*member != _other.*member) + return false; + return true; +} - return - astCompactJson == _other.astCompactJson && - asm_ == _other.asm_ && - asmJson == _other.asmJson && - opcodes == _other.opcodes && - binary == _other.binary && - binaryRuntime == _other.binaryRuntime && - abi == _other.abi && - ir == _other.ir && - irOptimized == _other.irOptimized && - ewasm == _other.ewasm && - signatureHashes == _other.signatureHashes && - natspecUser == _other.natspecUser && - natspecDev == _other.natspecDev && - metadata == _other.metadata && - storageLayout == _other.storageLayout; +string const& CompilerOutputs::componentName(bool CompilerOutputs::* _component) +{ + solAssert(_component, ""); + + // NOTE: Linear search is not optimal but it's simpler than getting pointers-to-members to work as map keys. + for (auto const& [componentName, component]: CompilerOutputs::componentMap()) + if (component == _component) + return componentName; + + solAssert(false, ""); } bool CombinedJsonRequests::operator==(CombinedJsonRequests const& _other) const noexcept @@ -511,7 +502,7 @@ at standard output or in files in the output directory, if specified. Imports are automatically read from the filesystem, but it is also possible to remap paths using the context:prefix=path syntax. Example: -solc --)" + g_strBinary + R"( -o /tmp/solcoutput dapp-bin=/usr/local/lib/dapp-bin contract.sol +solc --)" + CompilerOutputs::componentName(&CompilerOutputs::binary) + R"( -o /tmp/solcoutput dapp-bin=/usr/local/lib/dapp-bin contract.sol General Information)").c_str(), po::options_description::m_default_line_length, @@ -683,21 +674,21 @@ General Information)").c_str(), po::options_description outputComponents("Output Components"); outputComponents.add_options() - (g_strAstCompactJson.c_str(), "AST of all source files in a compact JSON format.") - (g_strAsm.c_str(), "EVM assembly of the contracts.") - (g_strAsmJson.c_str(), "EVM assembly of the contracts in JSON format.") - (g_strOpcodes.c_str(), "Opcodes of the contracts.") - (g_strBinary.c_str(), "Binary of the contracts in hex.") - (g_strBinaryRuntime.c_str(), "Binary of the runtime part of the contracts in hex.") - (g_strAbi.c_str(), "ABI specification of the contracts.") - (g_strIR.c_str(), "Intermediate Representation (IR) of all contracts (EXPERIMENTAL).") - (g_strIROptimized.c_str(), "Optimized intermediate Representation (IR) of all contracts (EXPERIMENTAL).") - (g_strEwasm.c_str(), "Ewasm text representation of all contracts (EXPERIMENTAL).") - (g_strSignatureHashes.c_str(), "Function signature hashes of the contracts.") - (g_strNatspecUser.c_str(), "Natspec user documentation of all contracts.") - (g_strNatspecDev.c_str(), "Natspec developer documentation of all contracts.") - (g_strMetadata.c_str(), "Combined Metadata JSON whose Swarm hash is stored on-chain.") - (g_strStorageLayout.c_str(), "Slots, offsets and types of the contract's state variables.") + (CompilerOutputs::componentName(&CompilerOutputs::astCompactJson).c_str(), "AST of all source files in a compact JSON format.") + (CompilerOutputs::componentName(&CompilerOutputs::asm_).c_str(), "EVM assembly of the contracts.") + (CompilerOutputs::componentName(&CompilerOutputs::asmJson).c_str(), "EVM assembly of the contracts in JSON format.") + (CompilerOutputs::componentName(&CompilerOutputs::opcodes).c_str(), "Opcodes of the contracts.") + (CompilerOutputs::componentName(&CompilerOutputs::binary).c_str(), "Binary of the contracts in hex.") + (CompilerOutputs::componentName(&CompilerOutputs::binaryRuntime).c_str(), "Binary of the runtime part of the contracts in hex.") + (CompilerOutputs::componentName(&CompilerOutputs::abi).c_str(), "ABI specification of the contracts.") + (CompilerOutputs::componentName(&CompilerOutputs::ir).c_str(), "Intermediate Representation (IR) of all contracts (EXPERIMENTAL).") + (CompilerOutputs::componentName(&CompilerOutputs::irOptimized).c_str(), "Optimized intermediate Representation (IR) of all contracts (EXPERIMENTAL).") + (CompilerOutputs::componentName(&CompilerOutputs::ewasm).c_str(), "Ewasm text representation of all contracts (EXPERIMENTAL).") + (CompilerOutputs::componentName(&CompilerOutputs::signatureHashes).c_str(), "Function signature hashes of the contracts.") + (CompilerOutputs::componentName(&CompilerOutputs::natspecUser).c_str(), "Natspec user documentation of all contracts.") + (CompilerOutputs::componentName(&CompilerOutputs::natspecDev).c_str(), "Natspec developer documentation of all contracts.") + (CompilerOutputs::componentName(&CompilerOutputs::metadata).c_str(), "Combined Metadata JSON whose Swarm hash is stored on-chain.") + (CompilerOutputs::componentName(&CompilerOutputs::storageLayout).c_str(), "Slots, offsets and types of the contract's state variables.") ; desc.add(outputComponents); @@ -889,14 +880,14 @@ bool CommandLineParser::processArgs() return false; array const conflictingWithStopAfter{ - g_strBinary, - g_strIR, - g_strIROptimized, - g_strEwasm, + CompilerOutputs::componentName(&CompilerOutputs::binary), + CompilerOutputs::componentName(&CompilerOutputs::ir), + CompilerOutputs::componentName(&CompilerOutputs::irOptimized), + CompilerOutputs::componentName(&CompilerOutputs::ewasm), g_strGas, - g_strAsm, - g_strAsmJson, - g_strOpcodes + CompilerOutputs::componentName(&CompilerOutputs::asm_), + CompilerOutputs::componentName(&CompilerOutputs::asmJson), + CompilerOutputs::componentName(&CompilerOutputs::opcodes), }; for (auto& option: conflictingWithStopAfter) @@ -965,25 +956,8 @@ bool CommandLineParser::processArgs() m_options.formatting.json.indent = m_args[g_strJsonIndent].as(); } - static_assert( - sizeof(m_options.compiler.outputs) == 15 * sizeof(bool), - "Remember to update code below if you add/remove fields." - ); - m_options.compiler.outputs.astCompactJson = (m_args.count(g_strAstCompactJson) > 0); - m_options.compiler.outputs.asm_ = (m_args.count(g_strAsm) > 0); - m_options.compiler.outputs.asmJson = (m_args.count(g_strAsmJson) > 0); - m_options.compiler.outputs.opcodes = (m_args.count(g_strOpcodes) > 0); - m_options.compiler.outputs.binary = (m_args.count(g_strBinary) > 0); - m_options.compiler.outputs.binaryRuntime = (m_args.count(g_strBinaryRuntime) > 0); - m_options.compiler.outputs.abi = (m_args.count(g_strAbi) > 0); - m_options.compiler.outputs.ir = (m_args.count(g_strIR) > 0); - m_options.compiler.outputs.irOptimized = (m_args.count(g_strIROptimized) > 0); - m_options.compiler.outputs.ewasm = (m_args.count(g_strEwasm) > 0); - m_options.compiler.outputs.signatureHashes = (m_args.count(g_strSignatureHashes) > 0); - m_options.compiler.outputs.natspecUser = (m_args.count(g_strNatspecUser) > 0); - m_options.compiler.outputs.natspecDev = (m_args.count(g_strNatspecDev) > 0); - m_options.compiler.outputs.metadata = (m_args.count(g_strMetadata) > 0); - m_options.compiler.outputs.storageLayout = (m_args.count(g_strStorageLayout) > 0); + for (auto&& [optionName, outputComponent]: CompilerOutputs::componentMap()) + m_options.compiler.outputs.*outputComponent = (m_args.count(optionName) > 0); m_options.compiler.estimateGas = (m_args.count(g_strGas) > 0); diff --git a/solc/CommandLineParser.h b/solc/CommandLineParser.h index 4159e2ac2..250b28d82 100644 --- a/solc/CommandLineParser.h +++ b/solc/CommandLineParser.h @@ -56,6 +56,29 @@ struct CompilerOutputs bool operator!=(CompilerOutputs const& _other) const noexcept { return !(*this == _other); } bool operator==(CompilerOutputs const& _other) const noexcept; + static std::string const& componentName(bool CompilerOutputs::* _component); + static auto const& componentMap() + { + static std::map const components = { + {"ast-compact-json", &CompilerOutputs::astCompactJson}, + {"asm", &CompilerOutputs::asm_}, + {"asm-json", &CompilerOutputs::asmJson}, + {"opcodes", &CompilerOutputs::opcodes}, + {"bin", &CompilerOutputs::binary}, + {"bin-runtime", &CompilerOutputs::binaryRuntime}, + {"abi", &CompilerOutputs::abi}, + {"ir", &CompilerOutputs::ir}, + {"ir-optimized", &CompilerOutputs::irOptimized}, + {"ewasm", &CompilerOutputs::ewasm}, + {"hashes", &CompilerOutputs::signatureHashes}, + {"userdoc", &CompilerOutputs::natspecUser}, + {"devdoc", &CompilerOutputs::natspecDev}, + {"metadata", &CompilerOutputs::metadata}, + {"storage-layout", &CompilerOutputs::storageLayout}, + }; + return components; + } + bool astCompactJson = false; bool asm_ = false; bool asmJson = false; From 4b394f0b351a0fafb0b759421e1a9f7820193185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 30 Sep 2021 16:33:00 +0200 Subject: [PATCH 216/232] CommandLineParser: componentMap() for CombinedJsonRequests --- solc/CommandLineParser.cpp | 100 +++++++------------------------------ solc/CommandLineParser.h | 25 ++++++++++ 2 files changed, 44 insertions(+), 81 deletions(-) diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 70b77e512..2758f1b63 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -51,23 +51,16 @@ ostream& CommandLineParser::serr() #define cout #define cerr -static string const g_strAbi = "abi"; static string const g_strAllowPaths = "allow-paths"; static string const g_strBasePath = "base-path"; static string const g_strIncludePath = "include-path"; -static string const g_strAsm = "asm"; static string const g_strAssemble = "assemble"; -static string const g_strAst = "ast"; -static string const g_strBinary = "bin"; -static string const g_strBinaryRuntime = "bin-runtime"; static string const g_strCombinedJson = "combined-json"; static string const g_strErrorRecovery = "error-recovery"; static string const g_strEVM = "evm"; static string const g_strEVMVersion = "evm-version"; static string const g_strEwasm = "ewasm"; static string const g_strExperimentalViaIR = "experimental-via-ir"; -static string const g_strGeneratedSources = "generated-sources"; -static string const g_strGeneratedSourcesRuntime = "generated-sources-runtime"; static string const g_strGas = "gas"; static string const g_strHelp = "help"; static string const g_strImportAst = "import-ast"; @@ -79,7 +72,6 @@ static string const g_strLicense = "license"; static string const g_strLibraries = "libraries"; static string const g_strLink = "link"; static string const g_strMachine = "machine"; -static string const g_strMetadata = "metadata"; static string const g_strMetadataHash = "metadata-hash"; static string const g_strMetadataLiteral = "metadata-literal"; static string const g_strModelCheckerContracts = "model-checker-contracts"; @@ -89,11 +81,8 @@ static string const g_strModelCheckerShowUnproved = "model-checker-show-unproved static string const g_strModelCheckerSolvers = "model-checker-solvers"; static string const g_strModelCheckerTargets = "model-checker-targets"; static string const g_strModelCheckerTimeout = "model-checker-timeout"; -static string const g_strNatspecDev = "devdoc"; -static string const g_strNatspecUser = "userdoc"; static string const g_strNone = "none"; static string const g_strNoOptimizeYul = "no-optimize-yul"; -static string const g_strOpcodes = "opcodes"; static string const g_strOptimize = "optimize"; static string const g_strOptimizeRuns = "optimize-runs"; static string const g_strOptimizeYul = "optimize-yul"; @@ -101,7 +90,6 @@ static string const g_strYulOptimizations = "yul-optimizations"; static string const g_strOutputDir = "output-dir"; static string const g_strOverwrite = "overwrite"; static string const g_strRevertStrings = "revert-strings"; -static string const g_strStorageLayout = "storage-layout"; static string const g_strStopAfter = "stop-after"; static string const g_strParsing = "parsing"; @@ -114,13 +102,8 @@ static set const g_revertStringsArgs revertStringsToString(RevertStrings::VerboseDebug) }; -static string const g_strSignatureHashes = "hashes"; static string const g_strSources = "sources"; static string const g_strSourceList = "sourceList"; -static string const g_strSrcMap = "srcmap"; -static string const g_strSrcMapRuntime = "srcmap-runtime"; -static string const g_strFunDebug = "function-debug"; -static string const g_strFunDebugRuntime = "function-debug-runtime"; static string const g_strStandardJSON = "standard-json"; static string const g_strStrictAssembly = "strict-assembly"; static string const g_strSwarm = "swarm"; @@ -132,28 +115,6 @@ static string const g_strColor = "color"; static string const g_strNoColor = "no-color"; static string const g_strErrorIds = "error-codes"; -/// Possible arguments to for --combined-json -static set const g_combinedJsonArgs -{ - g_strAbi, - g_strAsm, - g_strAst, - g_strBinary, - g_strBinaryRuntime, - g_strFunDebug, - g_strFunDebugRuntime, - g_strGeneratedSources, - g_strGeneratedSourcesRuntime, - g_strMetadata, - g_strNatspecUser, - g_strNatspecDev, - g_strOpcodes, - g_strSignatureHashes, - g_strSrcMap, - g_strSrcMapRuntime, - g_strStorageLayout -}; - /// Possible arguments to for --machine static set const g_machineArgs { @@ -229,29 +190,21 @@ string const& CompilerOutputs::componentName(bool CompilerOutputs::* _component) bool CombinedJsonRequests::operator==(CombinedJsonRequests const& _other) const noexcept { - static_assert( - sizeof(*this) == 17 * sizeof(bool), - "Remember to update code below if you add/remove fields." - ); + for (bool CombinedJsonRequests::* member: componentMap() | ranges::views::values) + if (this->*member != _other.*member) + return false; + return true; +} - return - abi == _other.abi && - metadata == _other.metadata && - binary == _other.binary && - binaryRuntime == _other.binaryRuntime && - opcodes == _other.opcodes && - asm_ == _other.asm_ && - storageLayout == _other.storageLayout && - generatedSources == _other.generatedSources && - generatedSourcesRuntime == _other.generatedSourcesRuntime && - srcMap == _other.srcMap && - srcMapRuntime == _other.srcMapRuntime && - funDebug == _other.funDebug && - funDebugRuntime == _other.funDebugRuntime && - signatureHashes == _other.signatureHashes && - natspecDev == _other.natspecDev && - natspecUser == _other.natspecUser && - ast == _other.ast; +string const& CombinedJsonRequests::componentName(bool CombinedJsonRequests::* _component) +{ + solAssert(_component, ""); + + for (auto const& [componentName, component]: CombinedJsonRequests::componentMap()) + if (component == _component) + return componentName; + + solAssert(false, ""); } bool CommandLineOptions::operator==(CommandLineOptions const& _other) const noexcept @@ -614,7 +567,7 @@ General Information)").c_str(), g_strImportAst.c_str(), ("Import ASTs to be compiled, assumes input holds the AST in compact JSON format. " "Supported Inputs is the output of the --" + g_strStandardJSON + " or the one produced by " - "--" + g_strCombinedJson + " " + g_strAst).c_str() + "--" + g_strCombinedJson + " " + CombinedJsonRequests::componentName(&CombinedJsonRequests::ast)).c_str() ) ; desc.add(alternativeInputModes); @@ -700,7 +653,7 @@ General Information)").c_str(), ) ( g_strCombinedJson.c_str(), - po::value()->value_name(joinHumanReadable(g_combinedJsonArgs, ",")), + po::value()->value_name(joinHumanReadable(CombinedJsonRequests::componentMap() | ranges::views::keys, ",")), "Output a single json document containing the specified information." ) ; @@ -1244,30 +1197,15 @@ bool CommandLineParser::parseCombinedJsonOption() set requests; for (string const& item: boost::split(requests, m_args[g_strCombinedJson].as(), boost::is_any_of(","))) - if (!g_combinedJsonArgs.count(item)) + if (CombinedJsonRequests::componentMap().count(item) == 0) { serr() << "Invalid option to --" << g_strCombinedJson << ": " << item << endl; return false; } m_options.compiler.combinedJsonRequests = CombinedJsonRequests{}; - m_options.compiler.combinedJsonRequests->abi = (requests.count(g_strAbi) > 0); - m_options.compiler.combinedJsonRequests->metadata = (requests.count("metadata") > 0); - m_options.compiler.combinedJsonRequests->binary = (requests.count(g_strBinary) > 0); - m_options.compiler.combinedJsonRequests->binaryRuntime = (requests.count(g_strBinaryRuntime) > 0); - m_options.compiler.combinedJsonRequests->opcodes = (requests.count(g_strOpcodes) > 0); - m_options.compiler.combinedJsonRequests->asm_ = (requests.count(g_strAsm) > 0); - m_options.compiler.combinedJsonRequests->storageLayout = (requests.count(g_strStorageLayout) > 0); - m_options.compiler.combinedJsonRequests->generatedSources = (requests.count(g_strGeneratedSources) > 0); - m_options.compiler.combinedJsonRequests->generatedSourcesRuntime = (requests.count(g_strGeneratedSourcesRuntime) > 0); - m_options.compiler.combinedJsonRequests->srcMap = (requests.count(g_strSrcMap) > 0); - m_options.compiler.combinedJsonRequests->srcMapRuntime = (requests.count(g_strSrcMapRuntime) > 0); - m_options.compiler.combinedJsonRequests->funDebug = (requests.count(g_strFunDebug) > 0); - m_options.compiler.combinedJsonRequests->funDebugRuntime = (requests.count(g_strFunDebugRuntime) > 0); - m_options.compiler.combinedJsonRequests->signatureHashes = (requests.count(g_strSignatureHashes) > 0); - m_options.compiler.combinedJsonRequests->natspecDev = (requests.count(g_strNatspecDev) > 0); - m_options.compiler.combinedJsonRequests->natspecUser = (requests.count(g_strNatspecUser) > 0); - m_options.compiler.combinedJsonRequests->ast = (requests.count(g_strAst) > 0); + for (auto&& [componentName, component]: CombinedJsonRequests::componentMap()) + m_options.compiler.combinedJsonRequests.value().*component = (requests.count(componentName) > 0); return true; } diff --git a/solc/CommandLineParser.h b/solc/CommandLineParser.h index 250b28d82..1c2cd2820 100644 --- a/solc/CommandLineParser.h +++ b/solc/CommandLineParser.h @@ -101,6 +101,31 @@ struct CombinedJsonRequests bool operator!=(CombinedJsonRequests const& _other) const noexcept { return !(*this == _other); } bool operator==(CombinedJsonRequests const& _other) const noexcept; + static std::string const& componentName(bool CombinedJsonRequests::* _component); + static auto const& componentMap() + { + static std::map const components = { + {"abi", &CombinedJsonRequests::abi}, + {"metadata", &CombinedJsonRequests::metadata}, + {"bin", &CombinedJsonRequests::binary}, + {"bin-runtime", &CombinedJsonRequests::binaryRuntime}, + {"opcodes", &CombinedJsonRequests::opcodes}, + {"asm", &CombinedJsonRequests::asm_}, + {"storage-layout", &CombinedJsonRequests::storageLayout}, + {"generated-sources", &CombinedJsonRequests::generatedSources}, + {"generated-sources-runtime", &CombinedJsonRequests::generatedSourcesRuntime}, + {"srcmap", &CombinedJsonRequests::srcMap}, + {"srcmap-runtime", &CombinedJsonRequests::srcMapRuntime}, + {"function-debug", &CombinedJsonRequests::funDebug}, + {"function-debug-runtime", &CombinedJsonRequests::funDebugRuntime}, + {"hashes", &CombinedJsonRequests::signatureHashes}, + {"devdoc", &CombinedJsonRequests::natspecDev}, + {"userdoc", &CombinedJsonRequests::natspecUser}, + {"ast", &CombinedJsonRequests::ast}, + }; + return components; + } + bool abi = false; bool metadata = false; bool binary = false; From 8a7695784cb1aa1a5083a2f75b057b6282b04ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 10 Jun 2021 15:46:46 +0200 Subject: [PATCH 217/232] CommandLineParser: operator << for CompilerOutputs and CombinedJsonRequests --- solc/CommandLineParser.cpp | 21 +++++++++++++++++++++ solc/CommandLineParser.h | 2 ++ 2 files changed, 23 insertions(+) diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index 2758f1b63..d77636507 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -176,6 +176,16 @@ bool CompilerOutputs::operator==(CompilerOutputs const& _other) const noexcept return true; } +ostream& operator<<(ostream& _out, CompilerOutputs const& _selection) +{ + vector serializedSelection; + for (auto&& [componentName, component]: CompilerOutputs::componentMap()) + if (_selection.*component) + serializedSelection.push_back(CompilerOutputs::componentName(component)); + + return _out << joinHumanReadable(serializedSelection, ","); +} + string const& CompilerOutputs::componentName(bool CompilerOutputs::* _component) { solAssert(_component, ""); @@ -196,6 +206,17 @@ bool CombinedJsonRequests::operator==(CombinedJsonRequests const& _other) const return true; } + +ostream& operator<<(ostream& _out, CombinedJsonRequests const& _requests) +{ + vector serializedRequests; + for (auto&& [componentName, component]: CombinedJsonRequests::componentMap()) + if (_requests.*component) + serializedRequests.push_back(CombinedJsonRequests::componentName(component)); + + return _out << joinHumanReadable(serializedRequests, ","); +} + string const& CombinedJsonRequests::componentName(bool CombinedJsonRequests::* _component) { solAssert(_component, ""); diff --git a/solc/CommandLineParser.h b/solc/CommandLineParser.h index 1c2cd2820..7e1266653 100644 --- a/solc/CommandLineParser.h +++ b/solc/CommandLineParser.h @@ -55,6 +55,7 @@ struct CompilerOutputs { bool operator!=(CompilerOutputs const& _other) const noexcept { return !(*this == _other); } bool operator==(CompilerOutputs const& _other) const noexcept; + friend std::ostream& operator<<(std::ostream& _out, CompilerOutputs const& _requests); static std::string const& componentName(bool CompilerOutputs::* _component); static auto const& componentMap() @@ -100,6 +101,7 @@ struct CombinedJsonRequests { bool operator!=(CombinedJsonRequests const& _other) const noexcept { return !(*this == _other); } bool operator==(CombinedJsonRequests const& _other) const noexcept; + friend std::ostream& operator<<(std::ostream& _out, CombinedJsonRequests const& _requests); static std::string const& componentName(bool CombinedJsonRequests::* _component); static auto const& componentMap() From def01ea59913e21af4a89c9b4e5312a5e223c94c Mon Sep 17 00:00:00 2001 From: Leo Arias Date: Sat, 2 Oct 2021 10:41:38 -0600 Subject: [PATCH 218/232] Snap: update cvc4 to 1.8 --- snap/snapcraft.yaml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index d7ead3644..9c4debd96 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -40,7 +40,7 @@ parts: source: https://github.com/Z3Prover/z3.git source-tag: z3-4.8.4 plugin: make - build-packages: [python] + build-packages: [python3] stage-packages: [libstdc++6] override-build: | python scripts/mk_make.py @@ -49,14 +49,13 @@ parts: make install DESTDIR=$SNAPCRAFT_PART_INSTALL cvc4: source: https://github.com/CVC4/CVC4.git - source-tag: "1.7" + source-tag: "1.8" plugin: nil - build-packages: [python, cmake, openjdk-11-jre, libgmp-dev, wget] + build-packages: [python3, python3-toml, cmake, openjdk-11-jre, libgmp-dev, wget, antlr3, libantlr3c-3.4-0, libantlr3c-dev] override-build: | - ./contrib/get-antlr-3.4 - ./configure.sh --prefix=$SNAPCRAFT_STAGE/usr + ./configure.sh --python3 --prefix=$SNAPCRAFT_STAGE/usr cd build make -j -l $(grep -c "^processor" /proc/cpuinfo) make install mkdir -p $SNAPCRAFT_PART_INSTALL/usr/lib/ - cp $SNAPCRAFT_STAGE/usr/lib/libcvc4.so.6 $SNAPCRAFT_PART_INSTALL/usr/lib/ + cp $SNAPCRAFT_STAGE/usr/lib/libcvc4.so.7 $SNAPCRAFT_PART_INSTALL/usr/lib/ From 559fab39a80b4507edf430487d01b7f6c8f85864 Mon Sep 17 00:00:00 2001 From: Leo Arias Date: Sat, 2 Oct 2021 18:09:22 +0000 Subject: [PATCH 219/232] Remote trailing spaces --- snap/snapcraft.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 9c4debd96..0826749ee 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -53,7 +53,7 @@ parts: plugin: nil build-packages: [python3, python3-toml, cmake, openjdk-11-jre, libgmp-dev, wget, antlr3, libantlr3c-3.4-0, libantlr3c-dev] override-build: | - ./configure.sh --python3 --prefix=$SNAPCRAFT_STAGE/usr + ./configure.sh --python3 --prefix=$SNAPCRAFT_STAGE/usr cd build make -j -l $(grep -c "^processor" /proc/cpuinfo) make install From ca232142beaf02168b024a1f166a4eb3febdff3a Mon Sep 17 00:00:00 2001 From: sgmoore Date: Sat, 2 Oct 2021 20:32:25 -0700 Subject: [PATCH 220/232] Update value-types.rst - fix typo Fix typo at line 69. --- docs/types/value-types.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/types/value-types.rst b/docs/types/value-types.rst index c1b439c7e..c02eea8a9 100644 --- a/docs/types/value-types.rst +++ b/docs/types/value-types.rst @@ -66,7 +66,7 @@ Shifts ^^^^^^ The result of a shift operation has the type of the left operand, truncating the result to match the type. -The right operand must be of unsigned type, trying to shift by an signed type will produce a compilation error. +The right operand must be of unsigned type, trying to shift by a signed type will produce a compilation error. Shifts can be "simulated" using multiplication by powers of two in the following way. Note that the truncation to the type of the left operand is always performed at the end, but not mentioned explicitly. From 1f087ce15c20ef57d468bb6b94d6e5263aa812cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 23 Sep 2021 16:26:10 +0200 Subject: [PATCH 221/232] Define an assertThrow() variant that allows providing the default message --- libsolutil/Assertions.h | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/libsolutil/Assertions.h b/libsolutil/Assertions.h index b143e6ed7..815a76290 100644 --- a/libsolutil/Assertions.h +++ b/libsolutil/Assertions.h @@ -27,6 +27,8 @@ #include +#include + namespace solidity::util { @@ -38,16 +40,32 @@ namespace solidity::util #define ETH_FUNC __func__ #endif -/// Assertion that throws an exception containing the given description if it is not met. -/// Use it as assertThrow(1 == 1, ExceptionType, "Mathematics is wrong."); -/// Do NOT supply an exception object as the second parameter. -#define assertThrow(_condition, _exceptionType, _description) \ +namespace assertions +{ + +inline std::string stringOrDefault(std::string _string, std::string _defaultString) +{ + // NOTE: Putting this in a function rather than directly in a macro prevents the string from + // being evaluated multiple times if it's not just a literal. + return (!_string.empty() ? _string : _defaultString); +} + +} + +/// Base macro that can be used to implement assertion macros. +/// Throws an exception containing the given description if the condition is not met. +/// Allows you to provide the default description for the case where the user of your macro does +/// not provide any. +/// The second parameter must be an exception class (rather than an instance). +#define assertThrowWithDefaultDescription(_condition, _exceptionType, _description, _defaultDescription) \ do \ { \ if (!(_condition)) \ ::boost::throw_exception( \ _exceptionType() << \ - ::solidity::util::errinfo_comment(_description) << \ + ::solidity::util::errinfo_comment( \ + ::solidity::util::assertions::stringOrDefault(_description, _defaultDescription) \ + ) << \ ::boost::throw_function(ETH_FUNC) << \ ::boost::throw_file(__FILE__) << \ ::boost::throw_line(__LINE__) \ @@ -55,4 +73,10 @@ namespace solidity::util } \ while (false) +/// Assertion that throws an exception containing the given description if it is not met. +/// Use it as assertThrow(1 == 1, ExceptionType, "Mathematics is wrong."); +/// The second parameter must be an exception class (rather than an instance). +#define assertThrow(_condition, _exceptionType, _description) \ + assertThrowWithDefaultDescription(_condition, _exceptionType, _description, "") + } From 4fe6aa1328232a7820bbf35363a6c5606e22fcc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 23 Sep 2021 16:26:35 +0200 Subject: [PATCH 222/232] Add default messages to assertion macros --- liblangutil/Exceptions.h | 6 +++--- libsmtutil/Exceptions.h | 2 +- libsolutil/Assertions.h | 2 +- libyul/Exceptions.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/liblangutil/Exceptions.h b/liblangutil/Exceptions.h index 68f109717..9a4051a87 100644 --- a/liblangutil/Exceptions.h +++ b/liblangutil/Exceptions.h @@ -47,16 +47,16 @@ struct InvalidAstError: virtual util::Exception {}; /// Assertion that throws an InternalCompilerError containing the given description if it is not met. #define solAssert(CONDITION, DESCRIPTION) \ - assertThrow(CONDITION, ::solidity::langutil::InternalCompilerError, DESCRIPTION) + assertThrowWithDefaultDescription(CONDITION, ::solidity::langutil::InternalCompilerError, DESCRIPTION, "Solidity assertion failed") #define solUnimplementedAssert(CONDITION, DESCRIPTION) \ - assertThrow(CONDITION, ::solidity::langutil::UnimplementedFeatureError, DESCRIPTION) + assertThrowWithDefaultDescription(CONDITION, ::solidity::langutil::UnimplementedFeatureError, DESCRIPTION, "Unimplemented feature") #define solUnimplemented(DESCRIPTION) \ solUnimplementedAssert(false, DESCRIPTION) #define astAssert(CONDITION, DESCRIPTION) \ - assertThrow(CONDITION, ::solidity::langutil::InvalidAstError, DESCRIPTION) + assertThrowWithDefaultDescription(CONDITION, ::solidity::langutil::InvalidAstError, DESCRIPTION, "AST assertion failed") using errorSourceLocationInfo = std::pair; diff --git a/libsmtutil/Exceptions.h b/libsmtutil/Exceptions.h index 29011dab9..85f751f08 100644 --- a/libsmtutil/Exceptions.h +++ b/libsmtutil/Exceptions.h @@ -27,6 +27,6 @@ namespace solidity::smtutil struct SMTLogicError: virtual util::Exception {}; #define smtAssert(CONDITION, DESCRIPTION) \ - assertThrow(CONDITION, SMTLogicError, DESCRIPTION) + assertThrowWithDefaultDescription(CONDITION, SMTLogicError, DESCRIPTION, "SMT assertion failed") } diff --git a/libsolutil/Assertions.h b/libsolutil/Assertions.h index 815a76290..f04e90a1f 100644 --- a/libsolutil/Assertions.h +++ b/libsolutil/Assertions.h @@ -77,6 +77,6 @@ inline std::string stringOrDefault(std::string _string, std::string _defaultStri /// Use it as assertThrow(1 == 1, ExceptionType, "Mathematics is wrong."); /// The second parameter must be an exception class (rather than an instance). #define assertThrow(_condition, _exceptionType, _description) \ - assertThrowWithDefaultDescription(_condition, _exceptionType, _description, "") + assertThrowWithDefaultDescription(_condition, _exceptionType, _description, "Assertion failed") } diff --git a/libyul/Exceptions.h b/libyul/Exceptions.h index 3be61bd18..96e07d620 100644 --- a/libyul/Exceptions.h +++ b/libyul/Exceptions.h @@ -53,6 +53,6 @@ struct StackTooDeepError: virtual YulException /// Assertion that throws an YulAssertion containing the given description if it is not met. #define yulAssert(CONDITION, DESCRIPTION) \ - assertThrow(CONDITION, ::solidity::yul::YulAssertion, DESCRIPTION) + assertThrowWithDefaultDescription(CONDITION, ::solidity::yul::YulAssertion, DESCRIPTION, "Yul assertion failed") } From 0745842d46fff0e04908dda327b92f4d723c0bb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 23 Sep 2021 16:52:08 +0200 Subject: [PATCH 223/232] Use BOOST_PP_OVERLOAD() to allow invoking the assertion macros without a message --- liblangutil/Exceptions.h | 66 ++++++++++++++++++++++++++++++++++++---- libsmtutil/Exceptions.h | 23 ++++++++++++-- libyul/Exceptions.h | 22 ++++++++++++-- 3 files changed, 101 insertions(+), 10 deletions(-) diff --git a/liblangutil/Exceptions.h b/liblangutil/Exceptions.h index 9a4051a87..6946ff463 100644 --- a/liblangutil/Exceptions.h +++ b/liblangutil/Exceptions.h @@ -28,6 +28,10 @@ #include #include +#include +#include +#include + #include #include #include @@ -45,18 +49,68 @@ struct FatalError: virtual util::Exception {}; struct UnimplementedFeatureError: virtual util::Exception {}; struct InvalidAstError: virtual util::Exception {}; + /// Assertion that throws an InternalCompilerError containing the given description if it is not met. -#define solAssert(CONDITION, DESCRIPTION) \ - assertThrowWithDefaultDescription(CONDITION, ::solidity::langutil::InternalCompilerError, DESCRIPTION, "Solidity assertion failed") +#if !BOOST_PP_VARIADICS_MSVC +#define solAssert(...) BOOST_PP_OVERLOAD(solAssert_,__VA_ARGS__)(__VA_ARGS__) +#else +#define solAssert(...) BOOST_PP_CAT(BOOST_PP_OVERLOAD(solAssert_,__VA_ARGS__)(__VA_ARGS__),BOOST_PP_EMPTY()) +#endif -#define solUnimplementedAssert(CONDITION, DESCRIPTION) \ - assertThrowWithDefaultDescription(CONDITION, ::solidity::langutil::UnimplementedFeatureError, DESCRIPTION, "Unimplemented feature") +#define solAssert_1(CONDITION) \ + solAssert_2(CONDITION, "") +#define solAssert_2(CONDITION, DESCRIPTION) \ + assertThrowWithDefaultDescription( \ + CONDITION, \ + ::solidity::langutil::InternalCompilerError, \ + DESCRIPTION, \ + "Solidity assertion failed" \ + ) + + +/// Assertion that throws an UnimplementedFeatureError containing the given description if it is not met. +#if !BOOST_PP_VARIADICS_MSVC +#define solUnimplementedAssert(...) BOOST_PP_OVERLOAD(solUnimplementedAssert_,__VA_ARGS__)(__VA_ARGS__) +#else +#define solUnimplementedAssert(...) BOOST_PP_CAT(BOOST_PP_OVERLOAD(solUnimplementedAssert_,__VA_ARGS__)(__VA_ARGS__),BOOST_PP_EMPTY()) +#endif + +#define solUnimplementedAssert_1(CONDITION) \ + solUnimplementedAssert_2(CONDITION, "") + +#define solUnimplementedAssert_2(CONDITION, DESCRIPTION) \ + assertThrowWithDefaultDescription( \ + CONDITION, \ + ::solidity::langutil::UnimplementedFeatureError, \ + DESCRIPTION, \ + "Unimplemented feature" \ + ) + + +/// Helper that unconditionally reports an unimplemented feature. #define solUnimplemented(DESCRIPTION) \ solUnimplementedAssert(false, DESCRIPTION) -#define astAssert(CONDITION, DESCRIPTION) \ - assertThrowWithDefaultDescription(CONDITION, ::solidity::langutil::InvalidAstError, DESCRIPTION, "AST assertion failed") + +/// Assertion that throws an InvalidAstError containing the given description if it is not met. +#if !BOOST_PP_VARIADICS_MSVC +#define astAssert(...) BOOST_PP_OVERLOAD(astAssert_,__VA_ARGS__)(__VA_ARGS__) +#else +#define astAssert(...) BOOST_PP_CAT(BOOST_PP_OVERLOAD(astAssert_,__VA_ARGS__)(__VA_ARGS__),BOOST_PP_EMPTY()) +#endif + +#define astAssert_1(CONDITION) \ + astAssert_2(CONDITION, "") + +#define astAssert_2(CONDITION, DESCRIPTION) \ + assertThrowWithDefaultDescription( \ + CONDITION, \ + ::solidity::langutil::InvalidAstError, \ + DESCRIPTION, \ + "AST assertion failed" \ + ) + using errorSourceLocationInfo = std::pair; diff --git a/libsmtutil/Exceptions.h b/libsmtutil/Exceptions.h index 85f751f08..fd144ca72 100644 --- a/libsmtutil/Exceptions.h +++ b/libsmtutil/Exceptions.h @@ -21,12 +21,31 @@ #include #include +#include +#include +#include + namespace solidity::smtutil { struct SMTLogicError: virtual util::Exception {}; -#define smtAssert(CONDITION, DESCRIPTION) \ - assertThrowWithDefaultDescription(CONDITION, SMTLogicError, DESCRIPTION, "SMT assertion failed") +/// Assertion that throws an SMTLogicError containing the given description if it is not met. +#if !BOOST_PP_VARIADICS_MSVC +#define smtAssert(...) BOOST_PP_OVERLOAD(smtAssert_,__VA_ARGS__)(__VA_ARGS__) +#else +#define smtAssert(...) BOOST_PP_CAT(BOOST_PP_OVERLOAD(smtAssert_,__VA_ARGS__)(__VA_ARGS__),BOOST_PP_EMPTY()) +#endif + +#define smtAssert_1(CONDITION) \ + smtAssert_2(CONDITION, "") + +#define smtAssert_2(CONDITION, DESCRIPTION) \ + assertThrowWithDefaultDescription( \ + CONDITION, \ + ::solidity::smtutil::SMTLogicError, \ + DESCRIPTION, \ + "SMT assertion failed" \ + ) } diff --git a/libyul/Exceptions.h b/libyul/Exceptions.h index 96e07d620..1ad7785e9 100644 --- a/libyul/Exceptions.h +++ b/libyul/Exceptions.h @@ -26,6 +26,10 @@ #include +#include +#include +#include + namespace solidity::yul { @@ -52,7 +56,21 @@ struct StackTooDeepError: virtual YulException }; /// Assertion that throws an YulAssertion containing the given description if it is not met. -#define yulAssert(CONDITION, DESCRIPTION) \ - assertThrowWithDefaultDescription(CONDITION, ::solidity::yul::YulAssertion, DESCRIPTION, "Yul assertion failed") +#if !BOOST_PP_VARIADICS_MSVC +#define yulAssert(...) BOOST_PP_OVERLOAD(yulAssert_,__VA_ARGS__)(__VA_ARGS__) +#else +#define yulAssert(...) BOOST_PP_CAT(BOOST_PP_OVERLOAD(yulAssert_,__VA_ARGS__)(__VA_ARGS__),BOOST_PP_EMPTY()) +#endif + +#define yulAssert_1(CONDITION) \ + yulAssert_2(CONDITION, "") + +#define yulAssert_2(CONDITION, DESCRIPTION) \ + assertThrowWithDefaultDescription( \ + CONDITION, \ + ::solidity::yul::YulAssertion, \ + DESCRIPTION, \ + "Yul assertion failed" \ + ) } From 7f7107405fddf648c0562a685e35b682c71e6ff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 23 Sep 2021 17:18:13 +0200 Subject: [PATCH 224/232] Try out the new assertion macro variants with less arguments --- libsmtutil/CHCSmtLib2Interface.cpp | 12 +++++------ libsolidity/analysis/ControlFlowBuilder.cpp | 2 +- libsolidity/ast/ASTJsonImporter.cpp | 8 ++++---- libsolidity/codegen/ExpressionCompiler.cpp | 3 +-- libsolidity/codegen/LValue.cpp | 4 ++-- libsolidity/codegen/YulUtilFunctions.cpp | 18 ++++++++--------- libsolidity/codegen/ir/IRGenerator.cpp | 6 +++--- .../codegen/ir/IRGeneratorForStatements.cpp | 20 +++++++++---------- libsolidity/interface/CompilerStack.cpp | 2 +- solc/CommandLineParser.cpp | 2 +- test/tools/yulopti.cpp | 4 ++-- 11 files changed, 40 insertions(+), 41 deletions(-) diff --git a/libsmtutil/CHCSmtLib2Interface.cpp b/libsmtutil/CHCSmtLib2Interface.cpp index 028c5efc2..48fdbd328 100644 --- a/libsmtutil/CHCSmtLib2Interface.cpp +++ b/libsmtutil/CHCSmtLib2Interface.cpp @@ -60,8 +60,8 @@ void CHCSmtLib2Interface::reset() void CHCSmtLib2Interface::registerRelation(Expression const& _expr) { - smtAssert(_expr.sort, ""); - smtAssert(_expr.sort->kind == Kind::Function, ""); + smtAssert(_expr.sort); + smtAssert(_expr.sort->kind == Kind::Function); if (!m_variables.count(_expr.name)) { auto fSort = dynamic_pointer_cast(_expr.sort); @@ -124,7 +124,7 @@ pair CHCSmtLib2Interface::query(Expre void CHCSmtLib2Interface::declareVariable(string const& _name, SortPointer const& _sort) { - smtAssert(_sort, ""); + smtAssert(_sort); if (_sort->kind == Kind::Function) declareFunction(_name, _sort); else if (!m_variables.count(_name)) @@ -172,13 +172,13 @@ string CHCSmtLib2Interface::forall() void CHCSmtLib2Interface::declareFunction(string const& _name, SortPointer const& _sort) { - smtAssert(_sort, ""); - smtAssert(_sort->kind == Kind::Function, ""); + smtAssert(_sort); + smtAssert(_sort->kind == Kind::Function); // TODO Use domain and codomain as key as well if (!m_variables.count(_name)) { auto fSort = dynamic_pointer_cast(_sort); - smtAssert(fSort->codomain, ""); + smtAssert(fSort->codomain); string domain = toSmtLibSort(fSort->domain); string codomain = toSmtLibSort(*fSort->codomain); m_variables.insert(_name); diff --git a/libsolidity/analysis/ControlFlowBuilder.cpp b/libsolidity/analysis/ControlFlowBuilder.cpp index 9e3ac3ae1..2d03aaf9c 100644 --- a/libsolidity/analysis/ControlFlowBuilder.cpp +++ b/libsolidity/analysis/ControlFlowBuilder.cpp @@ -553,7 +553,7 @@ void ControlFlowBuilder::operator()(yul::FunctionDefinition const&) void ControlFlowBuilder::operator()(yul::Leave const&) { // This has to be implemented, if we ever decide to visit functions. - solUnimplementedAssert(false, ""); + solUnimplemented(""); } bool ControlFlowBuilder::visit(VariableDeclaration const& _variableDeclaration) diff --git a/libsolidity/ast/ASTJsonImporter.cpp b/libsolidity/ast/ASTJsonImporter.cpp index dd928cc03..2e69df93f 100644 --- a/libsolidity/ast/ASTJsonImporter.cpp +++ b/libsolidity/ast/ASTJsonImporter.cpp @@ -61,7 +61,7 @@ map> ASTJsonImporter::jsonToSourceUnit(map(src.first)); for (auto const& srcPair: _sourceList) { - astAssert(!srcPair.second.isNull(), ""); + astAssert(!srcPair.second.isNull()); astAssert(member(srcPair.second,"nodeType") == "SourceUnit", "The 'nodeType' of the highest node must be 'SourceUnit'."); m_sourceUnits[srcPair.first] = createSourceUnit(srcPair.second, srcPair.first); } @@ -485,17 +485,17 @@ ASTPointer ASTJsonImporter::createVariableDeclaration(Json: if (mutabilityStr == "constant") { mutability = VariableDeclaration::Mutability::Constant; - astAssert(memberAsBool(_node, "constant"), ""); + astAssert(memberAsBool(_node, "constant")); } else { - astAssert(!memberAsBool(_node, "constant"), ""); + astAssert(!memberAsBool(_node, "constant")); if (mutabilityStr == "mutable") mutability = VariableDeclaration::Mutability::Mutable; else if (mutabilityStr == "immutable") mutability = VariableDeclaration::Mutability::Immutable; else - astAssert(false, ""); + astAssert(false); } return createASTNode( diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 8f364df1b..731cf1a41 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -2112,8 +2112,7 @@ bool ExpressionCompiler::visit(IndexRangeAccess const& _indexAccess) solUnimplementedAssert( arrayType->location() == DataLocation::CallData && arrayType->isDynamicallySized() && - !arrayType->baseType()->isDynamicallyEncoded(), - "" + !arrayType->baseType()->isDynamicallyEncoded() ); if (_indexAccess.startExpression()) diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index b77141445..bd9252953 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -155,7 +155,7 @@ ImmutableItem::ImmutableItem(CompilerContext& _compilerContext, VariableDeclarat void ImmutableItem::retrieveValue(SourceLocation const&, bool) const { - solUnimplementedAssert(m_dataType->isValueType(), ""); + solUnimplementedAssert(m_dataType->isValueType()); if (m_context.runtimeContext()) CompilerUtils(m_context).loadFromMemory( @@ -172,7 +172,7 @@ void ImmutableItem::retrieveValue(SourceLocation const&, bool) const void ImmutableItem::storeValue(Type const& _sourceType, SourceLocation const&, bool _move) const { CompilerUtils utils(m_context); - solUnimplementedAssert(m_dataType->isValueType(), ""); + solUnimplementedAssert(m_dataType->isValueType()); solAssert(_sourceType.isValueType(), ""); utils.convertType(_sourceType, *m_dataType, true); diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 1b36b3f10..1ad9aafa7 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -1217,7 +1217,7 @@ string YulUtilFunctions::extractByteArrayLengthFunction() std::string YulUtilFunctions::resizeArrayFunction(ArrayType const& _type) { solAssert(_type.location() == DataLocation::Storage, ""); - solUnimplementedAssert(_type.baseType()->storageBytes() <= 32, "..."); + solUnimplementedAssert(_type.baseType()->storageBytes() <= 32); if (_type.isByteArray()) return resizeDynamicByteArrayFunction(_type); @@ -1259,7 +1259,7 @@ string YulUtilFunctions::cleanUpStorageArrayEndFunction(ArrayType const& _type) solAssert(_type.location() == DataLocation::Storage, ""); solAssert(_type.baseType()->category() != Type::Category::Mapping, ""); solAssert(!_type.isByteArray(), ""); - solUnimplementedAssert(_type.baseType()->storageBytes() <= 32, ""); + solUnimplementedAssert(_type.baseType()->storageBytes() <= 32); string functionName = "cleanup_storage_array_end_" + _type.identifier(); return m_functionCollector.createFunction(functionName, [&](vector& _args, vector&) { @@ -1555,7 +1555,7 @@ string YulUtilFunctions::storageArrayPushFunction(ArrayType const& _type, Type c if (!_fromType) _fromType = _type.baseType(); else if (_fromType->isValueType()) - solUnimplementedAssert(*_fromType == *_type.baseType(), ""); + solUnimplementedAssert(*_fromType == *_type.baseType()); string functionName = string{"array_push_from_"} + @@ -3304,10 +3304,10 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) if (auto const* toFixedBytes = dynamic_cast(&_to)) convert = shiftLeftFunction(256 - toFixedBytes->numBytes() * 8); else if (dynamic_cast(&_to)) - solUnimplementedAssert(false, ""); + solUnimplemented(""); else if (dynamic_cast(&_to)) { - solUnimplementedAssert(fromCategory != Type::Category::FixedPoint, ""); + solUnimplementedAssert(fromCategory != Type::Category::FixedPoint); convert = identityFunction(); } else if (toCategory == Type::Category::Enum) @@ -3346,8 +3346,8 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) body = "converted := value"; else { - solUnimplementedAssert(toStructType.location() == DataLocation::Memory, ""); - solUnimplementedAssert(fromStructType.location() != DataLocation::Memory, ""); + solUnimplementedAssert(toStructType.location() == DataLocation::Memory); + solUnimplementedAssert(fromStructType.location() != DataLocation::Memory); if (fromStructType.location() == DataLocation::CallData) body = Whiskers(R"( @@ -3416,7 +3416,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) } case Type::Category::Tuple: { - solUnimplementedAssert(false, "Tuple conversion not implemented."); + solUnimplemented("Tuple conversion not implemented."); break; } case Type::Category::TypeType: @@ -4107,7 +4107,7 @@ string YulUtilFunctions::zeroValueFunction(Type const& _type, bool _splitFunctio else if (auto const* structType = dynamic_cast(&_type)) templ("zeroValue", allocateAndInitializeMemoryStructFunction(*structType) + "()"); else - solUnimplementedAssert(false, ""); + solUnimplemented(""); } return templ.render(); diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 0b314bc9b..c1bfce4e3 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -544,7 +544,7 @@ string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) if (_varDecl.immutable()) { solAssert(paramTypes.empty(), ""); - solUnimplementedAssert(type->sizeOnStack() == 1, ""); + solUnimplementedAssert(type->sizeOnStack() == 1); return Whiskers(R"( /// @ast-id @@ -925,8 +925,8 @@ string IRGenerator::deployCode(ContractDefinition const& _contract) else for (VariableDeclaration const* immutable: ContractType(_contract).immutableVariables()) { - solUnimplementedAssert(immutable->type()->isValueType(), ""); - solUnimplementedAssert(immutable->type()->sizeOnStack() == 1, ""); + solUnimplementedAssert(immutable->type()->isValueType()); + solUnimplementedAssert(immutable->type()->sizeOnStack() == 1); immutables.emplace_back(map{ {"immutableName"s, to_string(immutable->id())}, {"value"s, "mload(" + to_string(m_context.immutableMemoryOffset(*immutable)) + ")"} diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index e097c753b..9298ac9d2 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -108,7 +108,7 @@ private: { auto const& reference = m_references.at(&_identifier); auto const varDecl = dynamic_cast(reference.declaration); - solUnimplementedAssert(varDecl, ""); + solUnimplementedAssert(varDecl); string const& suffix = reference.suffix; string value; @@ -737,7 +737,7 @@ bool IRGeneratorForStatements::visit(UnaryOperation const& _unaryOperation) ) << "(" << IRVariable(_unaryOperation.subExpression()).name() << ")\n"; } else - solUnimplementedAssert(false, "Unary operator not yet implemented"); + solUnimplemented("Unary operator not yet implemented"); } else if (resultType.category() == Type::Category::FixedBytes) { @@ -755,7 +755,7 @@ bool IRGeneratorForStatements::visit(UnaryOperation const& _unaryOperation) appendSimpleUnaryOperation(_unaryOperation, _unaryOperation.subExpression()); } else - solUnimplementedAssert(false, "Unary operator not yet implemented"); + solUnimplemented("Unary operator not yet implemented"); return false; } @@ -1546,7 +1546,7 @@ void IRGeneratorForStatements::endVisit(FunctionCallOptions const& _options) setLocation(_options); FunctionType const& previousType = dynamic_cast(*_options.expression().annotation().type); - solUnimplementedAssert(!previousType.bound(), ""); + solUnimplementedAssert(!previousType.bound()); // Copy over existing values. for (auto const& item: previousType.stackItems()) @@ -1716,7 +1716,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) { solUnimplementedAssert( dynamic_cast(*_memberAccess.expression().annotation().type).kind() == - FunctionType::Kind::External, "" + FunctionType::Kind::External ); define(IRVariable{_memberAccess}, IRVariable(_memberAccess.expression()).part("address")); } @@ -2264,7 +2264,7 @@ void IRGeneratorForStatements::endVisit(IndexRangeAccess const& _indexRangeAcces break; } default: - solUnimplementedAssert(false, "Index range accesses is implemented only on calldata arrays."); + solUnimplemented("Index range accesses is implemented only on calldata arrays."); } } @@ -2910,8 +2910,8 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable [&](IRLValue::Stack const& _stack) { assign(_stack.variable, _value); }, [&](IRLValue::Immutable const& _immutable) { - solUnimplementedAssert(_lvalue.type.isValueType(), ""); - solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1, ""); + solUnimplementedAssert(_lvalue.type.isValueType()); + solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1); solAssert(_lvalue.type == *_immutable.variable->type(), ""); size_t memOffset = m_context.immutableMemoryOffset(*_immutable.variable); @@ -2970,8 +2970,8 @@ IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue) define(result, _stack.variable); }, [&](IRLValue::Immutable const& _immutable) { - solUnimplementedAssert(_lvalue.type.isValueType(), ""); - solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1, ""); + solUnimplementedAssert(_lvalue.type.isValueType()); + solUnimplementedAssert(_lvalue.type.sizeOnStack() == 1); solAssert(_lvalue.type == *_immutable.variable->type(), ""); if (m_context.executionContext() == IRGenerationContext::ExecutionContext::Creation) { diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index a2ed2fc9b..e49c15387 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -253,7 +253,7 @@ void CompilerStack::setRevertStringBehaviour(RevertStrings _revertStrings) { if (m_stackState >= ParsedAndImported) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Must set revert string settings before parsing.")); - solUnimplementedAssert(_revertStrings != RevertStrings::VerboseDebug, ""); + solUnimplementedAssert(_revertStrings != RevertStrings::VerboseDebug); m_revertStrings = _revertStrings; } diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index ad6a32f6d..1ece2047b 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -1259,7 +1259,7 @@ bool CommandLineParser::processArgs() if (m_options.input.mode == InputMode::Compiler) m_options.input.errorRecovery = (m_args.count(g_strErrorRecovery) > 0); - solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, ""); + solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport); return true; } diff --git a/test/tools/yulopti.cpp b/test/tools/yulopti.cpp index 357311595..752aaafa6 100644 --- a/test/tools/yulopti.cpp +++ b/test/tools/yulopti.cpp @@ -118,7 +118,7 @@ public: size_t _columns ) { - yulAssert(_columns > 0, ""); + yulAssert(_columns > 0); auto hasShorterString = [](auto const& a, auto const& b) { return a.second.size() < b.second.size(); }; size_t longestDescriptionLength = std::max( @@ -151,7 +151,7 @@ public: ); }); - yulAssert(sortedOptions.size() > 0, ""); + yulAssert(sortedOptions.size() > 0); size_t rows = (sortedOptions.size() - 1) / _columns + 1; for (size_t row = 0; row < rows; ++row) { From 9662e9a8df77853390a6bb278367da7a536116e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 1 Oct 2021 16:31:08 +0200 Subject: [PATCH 225/232] cmdlineTests.sh: Enable set -o pipefail --- test/cmdlineTests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index ab0037bd9..479b26978 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -26,7 +26,7 @@ # (c) 2016 solidity contributors. #------------------------------------------------------------------------------ -set -e +set -eo pipefail ## GLOBAL VARIABLES From 05ba53ecc3efa5c2898d248e3dc4cf205b38ad28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 1 Oct 2021 17:17:51 +0200 Subject: [PATCH 226/232] cmdlineTests.sh: Don't use --force with rm unless actually needed --- test/cmdlineTests.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 479b26978..426004cf5 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -283,7 +283,7 @@ EOF [[ $stderr_expectation_file == "" ]] && exit 1 fi - rm -f "$stdout_path" "$stderr_path" + rm "$stdout_path" "$stderr_path" } @@ -471,7 +471,7 @@ SOLTMPDIR=$(mktemp -d) compileFull "${opts[@]}" "$SOLTMPDIR/$f" done ) -rm -rf "$SOLTMPDIR" +rm -r "$SOLTMPDIR" echo "Done." printTask "Testing library checksum..." @@ -497,7 +497,7 @@ SOLTMPDIR=$(mktemp -d) # Now the placeholder and explanation should be gone. grep -q -v '[/_]' C.bin ) -rm -rf "$SOLTMPDIR" +rm -r "$SOLTMPDIR" printTask "Testing overwriting files..." SOLTMPDIR=$(mktemp -d) @@ -510,7 +510,7 @@ SOLTMPDIR=$(mktemp -d) # Unless we force echo 'contract C {} ' | "$SOLC" - --overwrite --bin -o "$SOLTMPDIR/non-existing-stuff-to-create" 2>/dev/null ) -rm -rf "$SOLTMPDIR" +rm -r "$SOLTMPDIR" printTask "Testing assemble, yul, strict-assembly and optimize..." ( @@ -574,7 +574,7 @@ SOLTMPDIR=$(mktemp -d) exit 1 fi ) -rm -rf "$SOLTMPDIR" +rm -r "$SOLTMPDIR" printTask "Testing AST export with stop-after=parsing..." "$REPO_ROOT/test/stopAfterParseTests.sh" @@ -590,6 +590,6 @@ SOLTMPDIR=$(mktemp -d) echo ./*.sol | xargs -P 4 -n 50 "${SOLIDITY_BUILD_DIR}/test/tools/solfuzzer" --quiet --input-files echo ./*.sol | xargs -P 4 -n 50 "${SOLIDITY_BUILD_DIR}/test/tools/solfuzzer" --without-optimizer --quiet --input-files ) -rm -rf "$SOLTMPDIR" +rm -r "$SOLTMPDIR" echo "Commandline tests successful." From ce61a2bf281274236bb184ec24f66723e8707178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 1 Oct 2021 17:18:41 +0200 Subject: [PATCH 227/232] cmdlineTests.sh: Add missing rm SOLTMPDIR and remove stray set -e --- test/cmdlineTests.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 426004cf5..a994fa5dd 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -485,7 +485,6 @@ printTask "Testing linking itself..." SOLTMPDIR=$(mktemp -d) ( cd "$SOLTMPDIR" - set -e echo 'library L { function f() public pure {} } contract C { function f() public pure { L.f(); } }' > x.sol "$SOLC" --bin -o . x.sol 2>/dev/null # Explanation and placeholder should be there @@ -502,7 +501,6 @@ rm -r "$SOLTMPDIR" printTask "Testing overwriting files..." SOLTMPDIR=$(mktemp -d) ( - set -e # First time it works echo 'contract C {} ' | "$SOLC" - --bin -o "$SOLTMPDIR/non-existing-stuff-to-create" 2>/dev/null # Second time it fails @@ -538,7 +536,7 @@ printTask "Testing standard input..." SOLTMPDIR=$(mktemp -d) ( set +e - output=$("$SOLC" --bin 2>&1) + output=$("$SOLC" --bin 2>&1) result=$? set -e @@ -563,6 +561,7 @@ SOLTMPDIR=$(mktemp -d) exit 1 fi ) +rm -r "$SOLTMPDIR" printTask "Testing AST import..." SOLTMPDIR=$(mktemp -d) From 26f9a554fb4d659cbab6af0533b4950b6c14dff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 1 Oct 2021 17:21:11 +0200 Subject: [PATCH 228/232] cmdlineTests.sh: Add fail helper to make exiting on an error more convenient --- scripts/common.sh | 6 ++++++ test/cmdlineTests.sh | 19 +++++++------------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/scripts/common.sh b/scripts/common.sh index 7df8b85db..12aa09a58 100644 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -33,6 +33,12 @@ else function printLog() { echo "$(tput setaf 3)$1$(tput sgr0)"; } fi +function fail() +{ + printError "$@" + return 1 +} + safe_kill() { local PID=${1} diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index a994fa5dd..992b95301 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -323,8 +323,7 @@ printTask "Testing unknown options..." then echo "Passed" else - printError "Incorrect response to unknown options: $output" - exit 1 + fail "Incorrect response to unknown options: $output" fi ) @@ -346,8 +345,7 @@ printTask "Running general commandline tests..." do if ! [[ -d $tdir ]] then - printError "Test directory not found: $tdir" - exit 1 + fail "Test directory not found: $tdir" fi printTask " - ${tdir}" @@ -383,7 +381,7 @@ printTask "Running general commandline tests..." if [ "${inputFile}" = "${tdir}/input.json" ] then - ! [ -e "${tdir}/stdin" ] || { printError "Found a file called 'stdin' but redirecting standard input in JSON mode is not allowed."; exit 1; } + ! [ -e "${tdir}/stdin" ] || fail "Found a file called 'stdin' but redirecting standard input in JSON mode is not allowed." stdin="${inputFile}" inputFile="" @@ -394,7 +392,7 @@ printTask "Running general commandline tests..." if [ -e "${tdir}/stdin" ] then stdin="${tdir}/stdin" - [ -f "${tdir}/stdin" ] || { printError "'stdin' is not a regular file."; exit 1; } + [ -f "${tdir}/stdin" ] || fail "'stdin' is not a regular file." else stdin="" fi @@ -543,22 +541,19 @@ SOLTMPDIR=$(mktemp -d) # This should fail if [[ ! ("$output" =~ "No input files given") || ($result == 0) ]] then - printError "Incorrect response to empty input arg list: $output" - exit 1 + fail "Incorrect response to empty input arg list: $output" fi # The contract should be compiled if ! output=$(echo 'contract C {} ' | "$SOLC" - --bin 2>/dev/null | grep -q ":C") then - printError "Failed to compile a simple contract from standard input" - exit 1 + fail "Failed to compile a simple contract from standard input" fi # This should not fail if ! output=$(echo '' | "$SOLC" --ast-compact-json - 2>/dev/null) then - printError "Incorrect response to --ast-compact-json option with empty stdin" - exit 1 + fail "Incorrect response to --ast-compact-json option with empty stdin" fi ) rm -r "$SOLTMPDIR" From b4073179d7034b6fe55d3101e5ec100a8ece9969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 1 Oct 2021 17:27:09 +0200 Subject: [PATCH 229/232] cmdlineTests.sh: Add msg_on_error helper that automatically prints stderr and stdout of a failed command --- scripts/common.sh | 68 ++++++++++++++++++++++++++++++++++++++++++++ test/cmdlineTests.sh | 30 +++++++++---------- 2 files changed, 82 insertions(+), 16 deletions(-) diff --git a/scripts/common.sh b/scripts/common.sh index 12aa09a58..b3a5f82e4 100644 --- a/scripts/common.sh +++ b/scripts/common.sh @@ -39,6 +39,74 @@ function fail() return 1 } +function msg_on_error() +{ + local error_message + local no_stdout=false + local no_stderr=false + + while [[ $1 =~ ^-- ]] + do + case "$1" in + --msg) + error_message="$2" + shift + shift + ;; + --no-stdout) + no_stdout=true + shift + ;; + --no-stderr) + no_stderr=true + shift + ;; + --silent) + no_stdout=true + no_stderr=true + shift + ;; + *) + fail "Invalid option for msg_on_error: $1" + ;; + esac + done + + local command=("$@") + + local stdout_file stderr_file + stdout_file="$(mktemp -t cmdline_test_command_stdout_XXXXXX.txt)" + stderr_file="$(mktemp -t cmdline_test_command_stderr_XXXXXX.txt)" + + if "${command[@]}" > "$stdout_file" 2> "$stderr_file" + then + [[ $no_stdout == "true" ]] || cat "$stdout_file" + [[ $no_stderr == "true" ]] || >&2 cat "$stderr_file" + rm "$stdout_file" "$stderr_file" + return 0 + else + printError "Command failed: $SOLC ${command[*]}" + if [[ -s "$stdout_file" ]] + then + printError "stdout:" + >&2 cat "$stdout_file" + else + printError "stdout: " + fi + if [[ -s "$stderr_file" ]] + then + printError "stderr:" + >&2 cat "$stderr_file" + else + printError "stderr: " + fi + + printError "$error_message" + rm "$stdout_file" "$stderr_file" + return 1 + fi +} + safe_kill() { local PID=${1} diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 992b95301..c413eef0f 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -295,7 +295,7 @@ function test_solc_assembly_output() local expected_object="object \"object\" { code ${expected} }" - output=$(echo "${input}" | "$SOLC" - "${solc_args[@]}" 2>/dev/null) + output=$(echo "${input}" | msg_on_error --no-stderr "$SOLC" - "${solc_args[@]}") empty=$(echo "$output" | tr '\n' ' ' | tr -s ' ' | sed -ne "/${expected_object}/p") if [ -z "$empty" ] then @@ -473,24 +473,24 @@ rm -r "$SOLTMPDIR" echo "Done." printTask "Testing library checksum..." -echo '' | "$SOLC" - --link --libraries a=0x90f20564390eAe531E810af625A22f51385Cd222 >/dev/null +echo '' | msg_on_error --no-stdout "$SOLC" - --link --libraries a=0x90f20564390eAe531E810af625A22f51385Cd222 echo '' | "$SOLC" - --link --libraries a=0x80f20564390eAe531E810af625A22f51385Cd222 &>/dev/null && exit 1 printTask "Testing long library names..." -echo '' | "$SOLC" - --link --libraries aveeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeerylonglibraryname=0x90f20564390eAe531E810af625A22f51385Cd222 >/dev/null +echo '' | msg_on_error --no-stdout "$SOLC" - --link --libraries aveeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeerylonglibraryname=0x90f20564390eAe531E810af625A22f51385Cd222 printTask "Testing linking itself..." SOLTMPDIR=$(mktemp -d) ( cd "$SOLTMPDIR" echo 'library L { function f() public pure {} } contract C { function f() public pure { L.f(); } }' > x.sol - "$SOLC" --bin -o . x.sol 2>/dev/null + msg_on_error --no-stderr "$SOLC" --bin -o . x.sol # Explanation and placeholder should be there grep -q '//' C.bin && grep -q '__' C.bin # But not in library file. grep -q -v '[/_]' L.bin # Now link - "$SOLC" --link --libraries x.sol:L=0x90f20564390eAe531E810af625A22f51385Cd222 C.bin + msg_on_error "$SOLC" --link --libraries x.sol:L=0x90f20564390eAe531E810af625A22f51385Cd222 C.bin # Now the placeholder and explanation should be gone. grep -q -v '[/_]' C.bin ) @@ -500,19 +500,19 @@ printTask "Testing overwriting files..." SOLTMPDIR=$(mktemp -d) ( # First time it works - echo 'contract C {} ' | "$SOLC" - --bin -o "$SOLTMPDIR/non-existing-stuff-to-create" 2>/dev/null + echo 'contract C {}' | msg_on_error --no-stderr "$SOLC" - --bin -o "$SOLTMPDIR/non-existing-stuff-to-create" # Second time it fails - echo 'contract C {} ' | "$SOLC" - --bin -o "$SOLTMPDIR/non-existing-stuff-to-create" 2>/dev/null && exit 1 + echo 'contract C {}' | "$SOLC" - --bin -o "$SOLTMPDIR/non-existing-stuff-to-create" 2>/dev/null && exit 1 # Unless we force - echo 'contract C {} ' | "$SOLC" - --overwrite --bin -o "$SOLTMPDIR/non-existing-stuff-to-create" 2>/dev/null + echo 'contract C {}' | msg_on_error --no-stderr "$SOLC" - --overwrite --bin -o "$SOLTMPDIR/non-existing-stuff-to-create" ) rm -r "$SOLTMPDIR" printTask "Testing assemble, yul, strict-assembly and optimize..." ( - echo '{}' | "$SOLC" - --assemble &>/dev/null - echo '{}' | "$SOLC" - --yul &>/dev/null - echo '{}' | "$SOLC" - --strict-assembly &>/dev/null + echo '{}' | msg_on_error --silent "$SOLC" - --assemble + echo '{}' | msg_on_error --silent "$SOLC" - --yul + echo '{}' | msg_on_error --silent "$SOLC" - --strict-assembly # Test options above in conjunction with --optimize. # Using both, --assemble and --optimize should fail. @@ -545,16 +545,14 @@ SOLTMPDIR=$(mktemp -d) fi # The contract should be compiled - if ! output=$(echo 'contract C {} ' | "$SOLC" - --bin 2>/dev/null | grep -q ":C") + if ! echo 'contract C {}' | msg_on_error --no-stderr "$SOLC" - --bin | grep -q ":C" then fail "Failed to compile a simple contract from standard input" fi # This should not fail - if ! output=$(echo '' | "$SOLC" --ast-compact-json - 2>/dev/null) - then - fail "Incorrect response to --ast-compact-json option with empty stdin" - fi + echo '' | msg_on_error --silent --msg "Incorrect response to --ast-compact-json option with empty stdin" \ + "$SOLC" --ast-compact-json - ) rm -r "$SOLTMPDIR" From 98dd78362e5fea433f21b18c10c81e63bf2cd75e Mon Sep 17 00:00:00 2001 From: Marenz Date: Wed, 22 Sep 2021 12:06:57 +0200 Subject: [PATCH 230/232] Add ``.address`` and ``.selector`` in inside assembly for external function pointers --- Changelog.md | 1 + docs/assembly.rst | 21 +++++++++++++++++ libsolidity/analysis/ReferencesResolver.cpp | 6 +++-- libsolidity/analysis/TypeChecker.cpp | 15 +++++++++++- libsolidity/ast/ASTAnnotations.h | 2 +- libsolidity/ast/ASTJsonConverter.cpp | 4 ++++ libsolidity/codegen/ContractCompiler.cpp | 20 ++++++++++++++++ .../codegen/ir/IRGeneratorForStatements.cpp | 12 ++++++++++ scripts/test_antlr_grammar.sh | 4 +++- .../external_function_pointer_address.sol | 19 +++++++++++++++ ...al_function_pointer_address_assignment.sol | 18 +++++++++++++++ .../external_function_pointer_selector.sol | 23 +++++++++++++++++++ ...l_function_pointer_selector_assignment.sol | 18 +++++++++++++++ .../external_function_pointer_offset.sol | 15 ++++++++++++ .../internal_function_pointer_address.sol | 18 +++++++++++++++ .../internal_function_pointer_selector.sol | 20 ++++++++++++++++ 16 files changed, 211 insertions(+), 5 deletions(-) create mode 100644 test/libsolidity/semanticTests/inlineAssembly/external_function_pointer_address.sol create mode 100644 test/libsolidity/semanticTests/inlineAssembly/external_function_pointer_address_assignment.sol create mode 100644 test/libsolidity/semanticTests/inlineAssembly/external_function_pointer_selector.sol create mode 100644 test/libsolidity/semanticTests/inlineAssembly/external_function_pointer_selector_assignment.sol create mode 100644 test/libsolidity/syntaxTests/inlineAssembly/invalid/external_function_pointer_offset.sol create mode 100644 test/libsolidity/syntaxTests/inlineAssembly/invalid/internal_function_pointer_address.sol create mode 100644 test/libsolidity/syntaxTests/inlineAssembly/invalid/internal_function_pointer_selector.sol diff --git a/Changelog.md b/Changelog.md index 70e948b88..cd38019be 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,7 @@ ### 0.8.10 (unreleased) Language Features: + * Inline Assembly: Support ``.address`` and ``.selector`` on external function pointers to access their address and function selector. Compiler Features: diff --git a/docs/assembly.rst b/docs/assembly.rst index 232e77777..c26a53e49 100644 --- a/docs/assembly.rst +++ b/docs/assembly.rst @@ -136,6 +136,27 @@ evaluate to the address of the variable in calldata, not the value itself. The variable can also be assigned a new offset, but note that no validation to ensure that the variable will not point beyond ``calldatasize()`` is performed. +For external function pointers the address and the function selector can be +accessed using ``x.address`` and ``x.selector``. +The selector consists of four right-aligned bytes. +Both values are can be assigned to. For example: + +.. code-block:: solidity + :force: + + // SPDX-License-Identifier: GPL-3.0 + pragma solidity >=0.8.10 <0.9.0; + + contract C { + // Assigns a new selector and address to the return variable @fun + function combineToFunctionPointer(address newAddress, uint newSelector) public pure returns (function() external fun) { + assembly { + fun.selector := newSelector + fun.address := newAddress + } + } + } + For dynamic calldata arrays, you can access their calldata offset (in bytes) and length (number of elements) using ``x.offset`` and ``x.length``. Both expressions can also be assigned to, but as for the static case, no validation will be performed diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index ee0c7d726..6b58ab27c 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -219,13 +219,15 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier) { solAssert(nativeLocationOf(_identifier) == originLocationOf(_identifier), ""); - static set suffixes{"slot", "offset", "length"}; + static set suffixes{"slot", "offset", "length", "address", "selector"}; string suffix; for (string const& s: suffixes) if (boost::algorithm::ends_with(_identifier.name.str(), "." + s)) suffix = s; - // Could also use `pathFromCurrentScope`, split by '.' + // Could also use `pathFromCurrentScope`, split by '.'. + // If we do that, suffix should only be set for when it has a special + // meaning, not for normal identifierPaths. auto declarations = m_resolver.nameFromCurrentScope(_identifier.name.str()); if (!suffix.empty()) { diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index eabf466a7..f11756b25 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -828,7 +828,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) if (!identifierInfo.suffix.empty()) { string const& suffix = identifierInfo.suffix; - solAssert((set{"offset", "slot", "length"}).count(suffix), ""); + solAssert((set{"offset", "slot", "length", "selector", "address"}).count(suffix), ""); if (!var->isConstant() && (var->isStateVariable() || var->type()->dataStoredIn(DataLocation::Storage))) { if (suffix != "slot" && suffix != "offset") @@ -861,6 +861,19 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly) return false; } } + else if (auto const* fpType = dynamic_cast(var->type())) + { + if (suffix != "selector" && suffix != "address") + { + m_errorReporter.typeError(9272_error, nativeLocationOf(_identifier), "Variables of type function pointer only support \".selector\" and \".address\"."); + return false; + } + if (fpType->kind() != FunctionType::Kind::External) + { + m_errorReporter.typeError(8533_error, nativeLocationOf(_identifier), "Only Variables of type external function pointer support \".selector\" and \".address\"."); + return false; + } + } else { m_errorReporter.typeError(3622_error, nativeLocationOf(_identifier), "The suffix \"." + suffix + "\" is not supported by this variable or type."); diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index 9c08a374f..53931e426 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -211,7 +211,7 @@ struct InlineAssemblyAnnotation: StatementAnnotation struct ExternalIdentifierInfo { Declaration const* declaration = nullptr; - /// Suffix used, one of "slot", "offset", "length" or empty. + /// Suffix used, one of "slot", "offset", "length", "address", "selector" or empty. std::string suffix; size_t valueSize = size_t(-1); }; diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index fd79a6f62..326cca43e 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -31,6 +31,7 @@ #include #include +#include #include @@ -178,9 +179,12 @@ Json::Value ASTJsonConverter::inlineAssemblyIdentifierToJson(pair(variable->type()); + functionType && functionType->kind() == FunctionType::Kind::External + ) + { + solAssert(suffix == "selector" || suffix == "address", ""); + solAssert(variable->type()->sizeOnStack() == 2, ""); + if (suffix == "selector") + stackDiff--; + } else solAssert(false, ""); } @@ -889,6 +899,16 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly) solAssert(suffix.empty(), ""); } } + else if ( + auto const* functionType = dynamic_cast(variable->type()); + functionType && functionType->kind() == FunctionType::Kind::External + ) + { + solAssert(suffix == "selector" || suffix == "address", ""); + solAssert(variable->type()->sizeOnStack() == 2, ""); + if (suffix == "selector") + stackDiff--; + } else solAssert(suffix.empty(), ""); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index e097c753b..cd12b7e05 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -188,6 +188,18 @@ private: solAssert(suffix == "offset" || suffix == "length", ""); value = IRVariable{*varDecl}.part(suffix).name(); } + else if ( + auto const* functionType = dynamic_cast(varDecl->type()); + functionType && functionType->kind() == FunctionType::Kind::External + ) + { + 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, ""); diff --git a/scripts/test_antlr_grammar.sh b/scripts/test_antlr_grammar.sh index 04c1b08ac..97aaa3b93 100755 --- a/scripts/test_antlr_grammar.sh +++ b/scripts/test_antlr_grammar.sh @@ -124,7 +124,9 @@ done < <( # Skipping license error, unrelated to the grammar grep -v -E 'license/license_double5.sol' | grep -v -E 'license/license_hidden_unicode.sol' | - grep -v -E 'license/license_unicode.sol' + grep -v -E 'license/license_unicode.sol' | + # Skipping tests with 'something.address' as 'address' as the grammar fails on those + grep -v -E 'inlineAssembly/external_function_pointer_address.*.sol' ) YUL_FILES=() diff --git a/test/libsolidity/semanticTests/inlineAssembly/external_function_pointer_address.sol b/test/libsolidity/semanticTests/inlineAssembly/external_function_pointer_address.sol new file mode 100644 index 000000000..7c3ad6d50 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/external_function_pointer_address.sol @@ -0,0 +1,19 @@ +contract C { + function testFunction() external {} + + function testYul() public returns (address adr) { + function() external fp = this.testFunction; + + assembly { + adr := fp.address + } + } + function testSol() public returns (address) { + return this.testFunction.address; + } +} +// ==== +// compileViaYul: also +// ---- +// testYul() -> 0x0fdd67305928fcac8d213d1e47bfa6165cd0b87b +// testSol() -> 0x0fdd67305928fcac8d213d1e47bfa6165cd0b87b diff --git a/test/libsolidity/semanticTests/inlineAssembly/external_function_pointer_address_assignment.sol b/test/libsolidity/semanticTests/inlineAssembly/external_function_pointer_address_assignment.sol new file mode 100644 index 000000000..7550e7785 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/external_function_pointer_address_assignment.sol @@ -0,0 +1,18 @@ +contract C { + function testFunction() external {} + + function testYul(address newAddress) view public returns (address adr) { + function() external fp = this.testFunction; + + assembly { + fp.address := newAddress + } + + return fp.address; + } +} +// ==== +// compileViaYul: also +// ---- +// testYul(address): 0x1234567890 -> 0x1234567890 +// testYul(address): 0xC0FFEE3EA7 -> 0xC0FFEE3EA7 diff --git a/test/libsolidity/semanticTests/inlineAssembly/external_function_pointer_selector.sol b/test/libsolidity/semanticTests/inlineAssembly/external_function_pointer_selector.sol new file mode 100644 index 000000000..99ba2370f --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/external_function_pointer_selector.sol @@ -0,0 +1,23 @@ +contract C { + function testFunction() external {} + + function testYul() public returns (uint32) { + function() external fp = this.testFunction; + uint selectorValue = 0; + + assembly { + selectorValue := fp.selector + } + + // Value is right-aligned, we shift it so it can be compared + return uint32(bytes4(bytes32(selectorValue << (256 - 32)))); + } + function testSol() public returns (uint32) { + return uint32(this.testFunction.selector); + } +} +// ==== +// compileViaYul: also +// ---- +// testYul() -> 0xe16b4a9b +// testSol() -> 0xe16b4a9b diff --git a/test/libsolidity/semanticTests/inlineAssembly/external_function_pointer_selector_assignment.sol b/test/libsolidity/semanticTests/inlineAssembly/external_function_pointer_selector_assignment.sol new file mode 100644 index 000000000..3bec26382 --- /dev/null +++ b/test/libsolidity/semanticTests/inlineAssembly/external_function_pointer_selector_assignment.sol @@ -0,0 +1,18 @@ +contract C { + function testFunction() external {} + + function testYul(uint32 newSelector) view public returns (uint32) { + function() external fp = this.testFunction; + + assembly { + fp.selector := newSelector + } + + return uint32(fp.selector); + } +} +// ==== +// compileViaYul: also +// ---- +// testYul(uint32): 0x12345678 -> 0x12345678 +// testYul(uint32): 0xABCDEF00 -> 0xABCDEF00 diff --git a/test/libsolidity/syntaxTests/inlineAssembly/invalid/external_function_pointer_offset.sol b/test/libsolidity/syntaxTests/inlineAssembly/invalid/external_function_pointer_offset.sol new file mode 100644 index 000000000..f6abe2976 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/invalid/external_function_pointer_offset.sol @@ -0,0 +1,15 @@ +contract C { + function testFunction() external {} + + function testYul() public { + function() external fp = this.testFunction; + + uint myOffset; + + assembly { + myOffset := fp.offset + } + } +} +// ---- +// TypeError 9272: (173-182): Variables of type function pointer only support ".selector" and ".address". diff --git a/test/libsolidity/syntaxTests/inlineAssembly/invalid/internal_function_pointer_address.sol b/test/libsolidity/syntaxTests/inlineAssembly/invalid/internal_function_pointer_address.sol new file mode 100644 index 000000000..c252657ca --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/invalid/internal_function_pointer_address.sol @@ -0,0 +1,18 @@ +contract C { + function testFunction() internal {} + + function testYul() public returns (address adr) { + function() internal fp = testFunction; + uint selectorValue = 0; + + assembly { + adr := fp.address + } + } + function testSol() public returns (address) { + return testFunction.address; + } +} +// ---- +// TypeError 8533: (193-203): Only Variables of type external function pointer support ".selector" and ".address". +// TypeError 9582: (267-287): Member "address" not found or not visible after argument-dependent lookup in function (). diff --git a/test/libsolidity/syntaxTests/inlineAssembly/invalid/internal_function_pointer_selector.sol b/test/libsolidity/syntaxTests/inlineAssembly/invalid/internal_function_pointer_selector.sol new file mode 100644 index 000000000..4913bf5d6 --- /dev/null +++ b/test/libsolidity/syntaxTests/inlineAssembly/invalid/internal_function_pointer_selector.sol @@ -0,0 +1,20 @@ +contract C { + function testFunction() internal {} + + function testYul() public returns (uint32) { + function() internal fp = testFunction; + uint selectorValue = 0; + + assembly { + selectorValue := fp.selector + } + + return uint32(bytes4(bytes32(selectorValue))); + } + function testSol() public returns (uint32) { + return uint32(testFunction.selector); + } +} +// ---- +// TypeError 8533: (198-209): Only Variables of type external function pointer support ".selector" and ".address". +// TypeError 9582: (329-350): Member "selector" not found or not visible after argument-dependent lookup in function (). From 4c2b661eaa192a4625ad07976da7c94375df9eff Mon Sep 17 00:00:00 2001 From: Leo Alt Date: Thu, 16 Sep 2021 19:18:26 +0200 Subject: [PATCH 231/232] [SMTChecker] Report values for block, msg and tx variables in counterexamples --- Changelog.md | 3 +- libsolidity/formal/CHC.cpp | 5 +- libsolidity/formal/Predicate.cpp | 95 ++++++++++++++++--- libsolidity/formal/Predicate.h | 3 +- .../model_checker_targets_all_all_engines/err | 24 ++--- .../model_checker_targets_all_chc/err | 24 ++--- .../model_checker_targets_assert_chc/err | 4 +- .../err | 16 ++-- .../model_checker_targets_default_chc/err | 16 ++-- .../model_checker_targets_div_by_zero_chc/err | 4 +- .../err | 4 +- .../model_checker_targets_overflow_chc/err | 4 +- .../model_checker_targets_pop_empty_chc/err | 4 +- .../model_checker_targets_underflow_chc/err | 4 +- .../err | 12 +-- .../err | 8 +- .../output.json | 8 +- .../output.json | 32 +++---- .../output.json | 32 +++---- .../output.json | 8 +- .../output.json | 8 +- .../output.json | 8 +- .../output.json | 8 +- .../output.json | 8 +- .../output.json | 24 ++--- .../output.json | 16 ++-- .../array_push_string_literal.sol | 2 +- .../blockchain_state/balance_non_zero.sol | 4 +- .../blockchain_state/balance_non_zero_2.sol | 2 +- .../blockchain_state/balance_receive_2.sol | 4 +- .../blockchain_state/balance_receive_3.sol | 2 +- .../blockchain_state/balance_receive_4.sol | 2 +- .../balance_receive_calls.sol | 6 +- .../external_calls/call_mutex_unsafe.sol | 2 +- .../external_calls/call_with_value_2.sol | 2 +- .../external_calls/external_reentrancy_1.sol | 2 +- .../external_calls/external_reentrancy_2.sol | 2 +- .../constant_string_at_file_level.sol | 2 +- .../file_level/file_level_call_via_module.sol | 4 +- .../smtCheckerTests/file_level/overloads.sol | 2 +- .../function_selector/homer.sol | 2 +- .../function_selector/selector_2.sol | 2 +- .../functions/getters/address.sol | 4 +- .../functions/getters/fixed_bytes.sol | 4 +- .../smtCheckerTests/functions/payable_2.sol | 2 +- .../smtCheckerTests/imports/import_base.sol | 2 +- .../imports/import_free_functions.sol | 2 +- .../imports/import_library_2.sol | 2 +- .../inheritance/receive_fallback.sol | 2 +- .../modifier_inside_branch_assignment.sol | 2 +- ...nside_branch_assignment_multi_branches.sol | 2 +- .../operators/bitwise_not_fixed_bytes.sol | 2 +- .../operators/bitwise_or_fixed_bytes.sol | 2 +- .../smtCheckerTests/operators/bytes_new.sol | 4 +- .../compound_bitwise_and_fixed_bytes.sol | 2 +- .../compound_bitwise_or_fixed_bytes.sol | 2 +- .../compound_bitwise_string_literal_2.sol | 2 +- .../compound_bitwise_string_literal_3.sol | 4 +- .../compound_bitwise_xor_fixed_bytes.sol | 2 +- .../operators/index_access_for_bytes.sol | 2 +- .../out_of_bounds/fixed_bytes_2.sol | 2 +- .../special/abi_decode_simple.sol | 2 +- .../special/block_vars_chc_internal.sol | 3 + .../smtCheckerTests/special/msg_parens_1.sol | 5 +- .../smtCheckerTests/special/msg_sig.sol | 6 +- .../smtCheckerTests/special/msg_value_1.sol | 4 +- .../smtCheckerTests/special/msg_value_2.sol | 2 +- .../smtCheckerTests/special/msg_value_4.sol | 2 +- .../special/msg_value_inheritance_1.sol | 2 +- .../special/msg_value_inheritance_2.sol | 4 +- .../special/msg_value_inheritance_3.sol | 2 +- .../special/msg_vars_chc_internal.sol | 3 + .../smtCheckerTests/special/shadowing_1.sol | 24 +++++ .../smtCheckerTests/special/timestamp_2.sol | 2 +- .../special/tx_vars_chc_internal.sol | 3 + .../special/tx_vars_reentrancy_1.sol | 16 ++++ .../special/tx_vars_reentrancy_2.sol | 16 ++++ .../typecast/address_literal.sol | 2 +- .../typecast/bytes_to_fixed_bytes_1.sol | 8 +- .../typecast/cast_larger_3.sol | 2 +- .../implicit_cast_string_literal_byte.sol | 2 +- .../string_literal_to_dynamic_bytes.sol | 2 +- ...string_literal_to_fixed_bytes_modifier.sol | 2 +- ...ng_literal_to_fixed_bytes_return_multi.sol | 2 +- .../typecast/string_to_bytes_push_1.sol | 2 +- .../types/address_transfer.sol | 2 +- .../types/address_transfer_insufficient.sol | 2 +- .../smtCheckerTests/types/fixed_bytes_2.sol | 2 +- .../types/fixed_bytes_access_4.sol | 2 +- .../types/fixed_bytes_access_5.sol | 6 +- .../types/fixed_bytes_access_7.sol | 4 +- .../smtCheckerTests/types/mapping_5.sol | 2 +- .../types/static_array_length_1.sol | 4 +- .../types/static_array_length_2.sol | 4 +- .../types/static_array_length_3.sol | 4 +- .../types/storage_value_vars_1.sol | 2 +- .../types/storage_value_vars_2.sol | 2 +- .../types/string_literal_assignment_1.sol | 2 +- .../types/string_literal_assignment_2.sol | 2 +- .../types/string_literal_assignment_3.sol | 2 +- .../types/string_literal_assignment_4.sol | 2 +- .../types/string_literal_assignment_5.sol | 2 +- .../types/string_literal_comparison_1.sol | 2 +- .../unchecked/check_var_init.sol | 2 +- .../smtCheckerTests/userTypes/multisource.sol | 2 +- 105 files changed, 390 insertions(+), 250 deletions(-) create mode 100644 test/libsolidity/smtCheckerTests/special/shadowing_1.sol create mode 100644 test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_1.sol create mode 100644 test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_2.sol diff --git a/Changelog.md b/Changelog.md index cd38019be..1b7e87642 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,10 +5,11 @@ Language Features: Compiler Features: + * SMTChecker: Output values for ``block.*``, ``msg.*`` and ``tx.*`` variables that are present in the called functions. Bugfixes: - * SMTChecker: Fix internal error in magic type access (``block``, ``msg``, ``tx``). + * SMTChecker: Fix internal error in magic type access (``block``, ``msg``, ``tx``). diff --git a/libsolidity/formal/CHC.cpp b/libsolidity/formal/CHC.cpp index 53098e081..fc97ab0ca 100644 --- a/libsolidity/formal/CHC.cpp +++ b/libsolidity/formal/CHC.cpp @@ -1892,7 +1892,10 @@ optional CHC::generateCounterexample(CHCSolverInterface::CexGraph const& if (!pred->isConstructorSummary()) for (unsigned v: callGraph[node]) _dfs(node, v, depth + 1, _dfs); - calls.push_front(string(depth * 4, ' ') + pred->formatSummaryCall(nodeArgs(node), m_charStreamProvider)); + + bool appendTxVars = pred->isConstructorSummary() || pred->isFunctionSummary() || pred->isExternalCallUntrusted(); + + calls.push_front(string(depth * 4, ' ') + pred->formatSummaryCall(nodeArgs(node), m_charStreamProvider, appendTxVars)); if (pred->isInternalCall()) calls.front() += " -- internal call"; else if (pred->isExternalCallTrusted()) diff --git a/libsolidity/formal/Predicate.cpp b/libsolidity/formal/Predicate.cpp index e058fa2b3..23aa7590e 100644 --- a/libsolidity/formal/Predicate.cpp +++ b/libsolidity/formal/Predicate.cpp @@ -200,7 +200,8 @@ bool Predicate::isInterface() const string Predicate::formatSummaryCall( vector const& _args, - langutil::CharStreamProvider const& _charStreamProvider + langutil::CharStreamProvider const& _charStreamProvider, + bool _appendTxVars ) const { solAssert(isSummary(), ""); @@ -214,19 +215,67 @@ string Predicate::formatSummaryCall( } /// The signature of a function summary predicate is: summary(error, this, abiFunctions, cryptoFunctions, txData, preBlockChainState, preStateVars, preInputVars, postBlockchainState, postStateVars, postInputVars, outputVars). - /// Here we are interested in preInputVars to format the function call, - /// and in txData to retrieve `msg.value`. + /// Here we are interested in preInputVars to format the function call. - string value; - if (auto v = readTxVars(_args.at(4)).at("msg.value")) + string txModel; + + if (_appendTxVars) { - bigint x(*v); - if (x > 0) - value = "{ value: " + *v + " }"; + set txVars; + if (isFunctionSummary()) + { + solAssert(programFunction(), ""); + if (programFunction()->isPayable()) + txVars.insert("msg.value"); + } + else if (isConstructorSummary()) + { + FunctionDefinition const* fun = programFunction(); + if (fun && fun->isPayable()) + txVars.insert("msg.value"); + } + + struct TxVarsVisitor: public ASTConstVisitor + { + bool visit(MemberAccess const& _memberAccess) + { + Expression const* memberExpr = SMTEncoder::innermostTuple(_memberAccess.expression()); + + Type const* exprType = memberExpr->annotation().type; + solAssert(exprType, ""); + if (exprType->category() == Type::Category::Magic) + if (auto const* identifier = dynamic_cast(memberExpr)) + { + ASTString const& name = identifier->name(); + if (name == "block" || name == "msg" || name == "tx") + txVars.insert(name + "." + _memberAccess.memberName()); + } + + return true; + } + + set txVars; + } txVarsVisitor; + + if (auto fun = programFunction()) + { + fun->accept(txVarsVisitor); + txVars += txVarsVisitor.txVars; + } + + // Here we are interested in txData from the summary predicate. + auto txValues = readTxVars(_args.at(4)); + vector values; + for (auto const& _var: txVars) + if (auto v = txValues.at(_var)) + values.push_back(_var + ": " + *v); + + if (!values.empty()) + txModel = "{ " + boost::algorithm::join(values, ", ") + " }"; } if (auto contract = programContract()) - return contract->name() + ".constructor()" + value; + return contract->name() + ".constructor()" + txModel; auto stateVars = stateVariables(); solAssert(stateVars.has_value(), ""); @@ -262,7 +311,7 @@ string Predicate::formatSummaryCall( solAssert(fun->annotation().contract, ""); prefix = fun->annotation().contract->name() + "."; } - return prefix + fName + "(" + boost::algorithm::join(functionArgs, ", ") + ")" + value; + return prefix + fName + "(" + boost::algorithm::join(functionArgs, ", ") + ")" + txModel; } vector> Predicate::summaryStateValues(vector const& _args) const @@ -384,7 +433,27 @@ optional Predicate::expressionToString(smtutil::Expression const& _expr, { solAssert(_expr.sort->kind == Kind::Int, ""); solAssert(_expr.arguments.empty(), ""); - // TODO assert that _expr.name is a number. + + if ( + _type->category() == Type::Category::Address || + _type->category() == Type::Category::FixedBytes + ) + { + try + { + if (_expr.name == "0") + return "0x0"; + // For some reason the code below returns "0x" for "0". + return toHex(toCompactBigEndian(bigint(_expr.name)), HexPrefix::Add, HexCase::Lower); + } + catch (out_of_range const&) + { + } + catch (invalid_argument const&) + { + } + } + return _expr.name; } if (smt::isBool(*_type)) @@ -526,9 +595,9 @@ map> Predicate::readTxVars(smtutil::Expression const& _ {"block.number", TypeProvider::uint256()}, {"block.timestamp", TypeProvider::uint256()}, {"blockhash", TypeProvider::array(DataLocation::Memory, TypeProvider::uint256())}, - {"msg.data", TypeProvider::bytesMemory()}, + {"msg.data", TypeProvider::array(DataLocation::CallData)}, {"msg.sender", TypeProvider::address()}, - {"msg.sig", TypeProvider::uint256()}, + {"msg.sig", TypeProvider::fixedBytes(4)}, {"msg.value", TypeProvider::uint256()}, {"tx.gasprice", TypeProvider::uint256()}, {"tx.origin", TypeProvider::address()} diff --git a/libsolidity/formal/Predicate.h b/libsolidity/formal/Predicate.h index 6f5a05a50..7357c9beb 100644 --- a/libsolidity/formal/Predicate.h +++ b/libsolidity/formal/Predicate.h @@ -149,7 +149,8 @@ public: /// with _args. std::string formatSummaryCall( std::vector const& _args, - langutil::CharStreamProvider const& _charStreamProvider + langutil::CharStreamProvider const& _charStreamProvider, + bool _appendTxVars = false ) const; /// @returns the values of the state variables from _args at the point diff --git a/test/cmdlineTests/model_checker_targets_all_all_engines/err b/test/cmdlineTests/model_checker_targets_all_all_engines/err index 0f2e84b48..cc8a8ea33 100644 --- a/test/cmdlineTests/model_checker_targets_all_all_engines/err +++ b/test/cmdlineTests/model_checker_targets_all_all_engines/err @@ -1,13 +1,13 @@ Warning: CHC: Underflow (resulting value less than 0) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 0) +test.f(0x0, 0) --> model_checker_targets_all_all_engines/input.sol:7:3: | 7 | --x; @@ -16,13 +16,13 @@ test.f(0, 0) Warning: CHC: Overflow (resulting value larger than 2**256 - 1) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 1 Transaction trace: test.constructor() State: arr = [] -test.f(0, 2) +test.f(0x0, 2) --> model_checker_targets_all_all_engines/input.sol:8:3: | 8 | x + type(uint).max; @@ -31,13 +31,13 @@ test.f(0, 2) Warning: CHC: Division by zero happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_all_all_engines/input.sol:9:3: | 9 | 2 / x; @@ -46,13 +46,13 @@ test.f(0, 1) Warning: CHC: Assertion violation happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_all_all_engines/input.sol:11:3: | 11 | assert(x > 0); @@ -61,13 +61,13 @@ test.f(0, 1) Warning: CHC: Empty array "pop" happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_all_all_engines/input.sol:12:3: | 12 | arr.pop(); @@ -76,13 +76,13 @@ test.f(0, 1) Warning: CHC: Out of bounds access happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_all_all_engines/input.sol:13:3: | 13 | arr[x]; diff --git a/test/cmdlineTests/model_checker_targets_all_chc/err b/test/cmdlineTests/model_checker_targets_all_chc/err index 1484e7f2d..d0404ecfb 100644 --- a/test/cmdlineTests/model_checker_targets_all_chc/err +++ b/test/cmdlineTests/model_checker_targets_all_chc/err @@ -1,13 +1,13 @@ Warning: CHC: Underflow (resulting value less than 0) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 0) +test.f(0x0, 0) --> model_checker_targets_all_chc/input.sol:7:3: | 7 | --x; @@ -16,13 +16,13 @@ test.f(0, 0) Warning: CHC: Overflow (resulting value larger than 2**256 - 1) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 1 Transaction trace: test.constructor() State: arr = [] -test.f(0, 2) +test.f(0x0, 2) --> model_checker_targets_all_chc/input.sol:8:3: | 8 | x + type(uint).max; @@ -31,13 +31,13 @@ test.f(0, 2) Warning: CHC: Division by zero happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_all_chc/input.sol:9:3: | 9 | 2 / x; @@ -46,13 +46,13 @@ test.f(0, 1) Warning: CHC: Assertion violation happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_all_chc/input.sol:11:3: | 11 | assert(x > 0); @@ -61,13 +61,13 @@ test.f(0, 1) Warning: CHC: Empty array "pop" happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_all_chc/input.sol:12:3: | 12 | arr.pop(); @@ -76,13 +76,13 @@ test.f(0, 1) Warning: CHC: Out of bounds access happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_all_chc/input.sol:13:3: | 13 | arr[x]; diff --git a/test/cmdlineTests/model_checker_targets_assert_chc/err b/test/cmdlineTests/model_checker_targets_assert_chc/err index a7b73b418..1bf48bfa9 100644 --- a/test/cmdlineTests/model_checker_targets_assert_chc/err +++ b/test/cmdlineTests/model_checker_targets_assert_chc/err @@ -1,13 +1,13 @@ Warning: CHC: Assertion violation happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_assert_chc/input.sol:11:3: | 11 | assert(x > 0); diff --git a/test/cmdlineTests/model_checker_targets_default_all_engines/err b/test/cmdlineTests/model_checker_targets_default_all_engines/err index 14f3b95ff..c1fe2f5b3 100644 --- a/test/cmdlineTests/model_checker_targets_default_all_engines/err +++ b/test/cmdlineTests/model_checker_targets_default_all_engines/err @@ -1,13 +1,13 @@ Warning: CHC: Division by zero happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_default_all_engines/input.sol:9:3: | 9 | 2 / x; @@ -16,13 +16,13 @@ test.f(0, 1) Warning: CHC: Assertion violation happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_default_all_engines/input.sol:11:3: | 11 | assert(x > 0); @@ -31,13 +31,13 @@ test.f(0, 1) Warning: CHC: Empty array "pop" happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_default_all_engines/input.sol:12:3: | 12 | arr.pop(); @@ -46,13 +46,13 @@ test.f(0, 1) Warning: CHC: Out of bounds access happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_default_all_engines/input.sol:13:3: | 13 | arr[x]; diff --git a/test/cmdlineTests/model_checker_targets_default_chc/err b/test/cmdlineTests/model_checker_targets_default_chc/err index 1c21226e1..bd2aa0b4d 100644 --- a/test/cmdlineTests/model_checker_targets_default_chc/err +++ b/test/cmdlineTests/model_checker_targets_default_chc/err @@ -1,13 +1,13 @@ Warning: CHC: Division by zero happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_default_chc/input.sol:9:3: | 9 | 2 / x; @@ -16,13 +16,13 @@ test.f(0, 1) Warning: CHC: Assertion violation happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_default_chc/input.sol:11:3: | 11 | assert(x > 0); @@ -31,13 +31,13 @@ test.f(0, 1) Warning: CHC: Empty array "pop" happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_default_chc/input.sol:12:3: | 12 | arr.pop(); @@ -46,13 +46,13 @@ test.f(0, 1) Warning: CHC: Out of bounds access happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_default_chc/input.sol:13:3: | 13 | arr[x]; diff --git a/test/cmdlineTests/model_checker_targets_div_by_zero_chc/err b/test/cmdlineTests/model_checker_targets_div_by_zero_chc/err index 4318a501e..3156dd90b 100644 --- a/test/cmdlineTests/model_checker_targets_div_by_zero_chc/err +++ b/test/cmdlineTests/model_checker_targets_div_by_zero_chc/err @@ -1,13 +1,13 @@ Warning: CHC: Division by zero happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_div_by_zero_chc/input.sol:9:3: | 9 | 2 / x; diff --git a/test/cmdlineTests/model_checker_targets_out_of_bounds_chc/err b/test/cmdlineTests/model_checker_targets_out_of_bounds_chc/err index 661ae5b79..b4426a80e 100644 --- a/test/cmdlineTests/model_checker_targets_out_of_bounds_chc/err +++ b/test/cmdlineTests/model_checker_targets_out_of_bounds_chc/err @@ -1,13 +1,13 @@ Warning: CHC: Out of bounds access happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_out_of_bounds_chc/input.sol:13:3: | 13 | arr[x]; diff --git a/test/cmdlineTests/model_checker_targets_overflow_chc/err b/test/cmdlineTests/model_checker_targets_overflow_chc/err index fca12d076..e7f98ff4d 100644 --- a/test/cmdlineTests/model_checker_targets_overflow_chc/err +++ b/test/cmdlineTests/model_checker_targets_overflow_chc/err @@ -1,13 +1,13 @@ Warning: CHC: Overflow (resulting value larger than 2**256 - 1) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 1 Transaction trace: test.constructor() State: arr = [] -test.f(0, 2) +test.f(0x0, 2) --> model_checker_targets_overflow_chc/input.sol:8:3: | 8 | x + type(uint).max; diff --git a/test/cmdlineTests/model_checker_targets_pop_empty_chc/err b/test/cmdlineTests/model_checker_targets_pop_empty_chc/err index 7ec616853..d3478a700 100644 --- a/test/cmdlineTests/model_checker_targets_pop_empty_chc/err +++ b/test/cmdlineTests/model_checker_targets_pop_empty_chc/err @@ -1,13 +1,13 @@ Warning: CHC: Empty array "pop" happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_pop_empty_chc/input.sol:12:3: | 12 | arr.pop(); diff --git a/test/cmdlineTests/model_checker_targets_underflow_chc/err b/test/cmdlineTests/model_checker_targets_underflow_chc/err index ac56c82b5..448b0e25c 100644 --- a/test/cmdlineTests/model_checker_targets_underflow_chc/err +++ b/test/cmdlineTests/model_checker_targets_underflow_chc/err @@ -1,13 +1,13 @@ Warning: CHC: Underflow (resulting value less than 0) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 0) +test.f(0x0, 0) --> model_checker_targets_underflow_chc/input.sol:7:3: | 7 | --x; diff --git a/test/cmdlineTests/model_checker_targets_underflow_overflow_assert_chc/err b/test/cmdlineTests/model_checker_targets_underflow_overflow_assert_chc/err index 25680bc15..a0fbbe61a 100644 --- a/test/cmdlineTests/model_checker_targets_underflow_overflow_assert_chc/err +++ b/test/cmdlineTests/model_checker_targets_underflow_overflow_assert_chc/err @@ -1,13 +1,13 @@ Warning: CHC: Underflow (resulting value less than 0) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 0) +test.f(0x0, 0) --> model_checker_targets_underflow_overflow_assert_chc/input.sol:7:3: | 7 | --x; @@ -16,13 +16,13 @@ test.f(0, 0) Warning: CHC: Overflow (resulting value larger than 2**256 - 1) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 1 Transaction trace: test.constructor() State: arr = [] -test.f(0, 2) +test.f(0x0, 2) --> model_checker_targets_underflow_overflow_assert_chc/input.sol:8:3: | 8 | x + type(uint).max; @@ -31,13 +31,13 @@ test.f(0, 2) Warning: CHC: Assertion violation happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> model_checker_targets_underflow_overflow_assert_chc/input.sol:11:3: | 11 | assert(x > 0); diff --git a/test/cmdlineTests/model_checker_targets_underflow_overflow_chc/err b/test/cmdlineTests/model_checker_targets_underflow_overflow_chc/err index 9bb4b52f1..0dcfb1c25 100644 --- a/test/cmdlineTests/model_checker_targets_underflow_overflow_chc/err +++ b/test/cmdlineTests/model_checker_targets_underflow_overflow_chc/err @@ -1,13 +1,13 @@ Warning: CHC: Underflow (resulting value less than 0) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 0) +test.f(0x0, 0) --> model_checker_targets_underflow_overflow_chc/input.sol:7:3: | 7 | --x; @@ -16,13 +16,13 @@ test.f(0, 0) Warning: CHC: Overflow (resulting value larger than 2**256 - 1) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 1 Transaction trace: test.constructor() State: arr = [] -test.f(0, 2) +test.f(0x0, 2) --> model_checker_targets_underflow_overflow_chc/input.sol:8:3: | 8 | x + type(uint).max; diff --git a/test/cmdlineTests/standard_model_checker_targets_assert_chc/output.json b/test/cmdlineTests/standard_model_checker_targets_assert_chc/output.json index 0ecf87bd7..fc4b9b9da 100644 --- a/test/cmdlineTests/standard_model_checker_targets_assert_chc/output.json +++ b/test/cmdlineTests/standard_model_checker_targets_assert_chc/output.json @@ -1,13 +1,13 @@ {"errors":[{"component":"general","errorCode":"6328","formattedMessage":"Warning: CHC: Assertion violation happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> A:12:7: | 12 | \t\t\t\t\t\tassert(x > 0); @@ -16,10 +16,10 @@ test.f(0, 1) ","message":"CHC: Assertion violation happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1)","severity":"warning","sourceLocation":{"end":258,"file":"A","start":245},"type":"Warning"}],"sources":{"A":{"id":0}}} +test.f(0x0, 1)","severity":"warning","sourceLocation":{"end":258,"file":"A","start":245},"type":"Warning"}],"sources":{"A":{"id":0}}} diff --git a/test/cmdlineTests/standard_model_checker_targets_default_all_engines/output.json b/test/cmdlineTests/standard_model_checker_targets_default_all_engines/output.json index d5491b274..ad6418636 100644 --- a/test/cmdlineTests/standard_model_checker_targets_default_all_engines/output.json +++ b/test/cmdlineTests/standard_model_checker_targets_default_all_engines/output.json @@ -126,13 +126,13 @@ "}},"errors":[{"component":"general","errorCode":"4281","formattedMessage":"Warning: CHC: Division by zero happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> A:10:7: | 10 | \t\t\t\t\t\t2 / x; @@ -141,22 +141,22 @@ test.f(0, 1) ","message":"CHC: Division by zero happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1)","severity":"warning","sourceLocation":{"end":216,"file":"A","start":211},"type":"Warning"},{"component":"general","errorCode":"6328","formattedMessage":"Warning: CHC: Assertion violation happens here. +test.f(0x0, 1)","severity":"warning","sourceLocation":{"end":216,"file":"A","start":211},"type":"Warning"},{"component":"general","errorCode":"6328","formattedMessage":"Warning: CHC: Assertion violation happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> A:12:7: | 12 | \t\t\t\t\t\tassert(x > 0); @@ -165,22 +165,22 @@ test.f(0, 1) ","message":"CHC: Assertion violation happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1)","severity":"warning","sourceLocation":{"end":258,"file":"A","start":245},"type":"Warning"},{"component":"general","errorCode":"2529","formattedMessage":"Warning: CHC: Empty array \"pop\" happens here. +test.f(0x0, 1)","severity":"warning","sourceLocation":{"end":258,"file":"A","start":245},"type":"Warning"},{"component":"general","errorCode":"2529","formattedMessage":"Warning: CHC: Empty array \"pop\" happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> A:13:7: | 13 | \t\t\t\t\t\tarr.pop(); @@ -189,22 +189,22 @@ test.f(0, 1) ","message":"CHC: Empty array \"pop\" happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1)","severity":"warning","sourceLocation":{"end":275,"file":"A","start":266},"type":"Warning"},{"component":"general","errorCode":"6368","formattedMessage":"Warning: CHC: Out of bounds access happens here. +test.f(0x0, 1)","severity":"warning","sourceLocation":{"end":275,"file":"A","start":266},"type":"Warning"},{"component":"general","errorCode":"6368","formattedMessage":"Warning: CHC: Out of bounds access happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> A:14:7: | 14 | \t\t\t\t\t\tarr[x]; @@ -213,13 +213,13 @@ test.f(0, 1) ","message":"CHC: Out of bounds access happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1)","severity":"warning","sourceLocation":{"end":289,"file":"A","start":283},"type":"Warning"},{"component":"general","errorCode":"6838","formattedMessage":"Warning: BMC: Condition is always true. +test.f(0x0, 1)","severity":"warning","sourceLocation":{"end":289,"file":"A","start":283},"type":"Warning"},{"component":"general","errorCode":"6838","formattedMessage":"Warning: BMC: Condition is always true. --> A:7:15: | 7 | \t\t\t\t\t\trequire(x >= 0); diff --git a/test/cmdlineTests/standard_model_checker_targets_default_chc/output.json b/test/cmdlineTests/standard_model_checker_targets_default_chc/output.json index 4049582dc..bcdf48e50 100644 --- a/test/cmdlineTests/standard_model_checker_targets_default_chc/output.json +++ b/test/cmdlineTests/standard_model_checker_targets_default_chc/output.json @@ -1,13 +1,13 @@ {"errors":[{"component":"general","errorCode":"4281","formattedMessage":"Warning: CHC: Division by zero happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> A:10:7: | 10 | \t\t\t\t\t\t2 / x; @@ -16,22 +16,22 @@ test.f(0, 1) ","message":"CHC: Division by zero happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1)","severity":"warning","sourceLocation":{"end":216,"file":"A","start":211},"type":"Warning"},{"component":"general","errorCode":"6328","formattedMessage":"Warning: CHC: Assertion violation happens here. +test.f(0x0, 1)","severity":"warning","sourceLocation":{"end":216,"file":"A","start":211},"type":"Warning"},{"component":"general","errorCode":"6328","formattedMessage":"Warning: CHC: Assertion violation happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> A:12:7: | 12 | \t\t\t\t\t\tassert(x > 0); @@ -40,22 +40,22 @@ test.f(0, 1) ","message":"CHC: Assertion violation happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1)","severity":"warning","sourceLocation":{"end":258,"file":"A","start":245},"type":"Warning"},{"component":"general","errorCode":"2529","formattedMessage":"Warning: CHC: Empty array \"pop\" happens here. +test.f(0x0, 1)","severity":"warning","sourceLocation":{"end":258,"file":"A","start":245},"type":"Warning"},{"component":"general","errorCode":"2529","formattedMessage":"Warning: CHC: Empty array \"pop\" happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> A:13:7: | 13 | \t\t\t\t\t\tarr.pop(); @@ -64,22 +64,22 @@ test.f(0, 1) ","message":"CHC: Empty array \"pop\" happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1)","severity":"warning","sourceLocation":{"end":275,"file":"A","start":266},"type":"Warning"},{"component":"general","errorCode":"6368","formattedMessage":"Warning: CHC: Out of bounds access happens here. +test.f(0x0, 1)","severity":"warning","sourceLocation":{"end":275,"file":"A","start":266},"type":"Warning"},{"component":"general","errorCode":"6368","formattedMessage":"Warning: CHC: Out of bounds access happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> A:14:7: | 14 | \t\t\t\t\t\tarr[x]; @@ -88,10 +88,10 @@ test.f(0, 1) ","message":"CHC: Out of bounds access happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1)","severity":"warning","sourceLocation":{"end":289,"file":"A","start":283},"type":"Warning"}],"sources":{"A":{"id":0}}} +test.f(0x0, 1)","severity":"warning","sourceLocation":{"end":289,"file":"A","start":283},"type":"Warning"}],"sources":{"A":{"id":0}}} diff --git a/test/cmdlineTests/standard_model_checker_targets_div_by_zero_chc/output.json b/test/cmdlineTests/standard_model_checker_targets_div_by_zero_chc/output.json index eca84d4b0..bd8b26c12 100644 --- a/test/cmdlineTests/standard_model_checker_targets_div_by_zero_chc/output.json +++ b/test/cmdlineTests/standard_model_checker_targets_div_by_zero_chc/output.json @@ -1,13 +1,13 @@ {"errors":[{"component":"general","errorCode":"4281","formattedMessage":"Warning: CHC: Division by zero happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> A:10:7: | 10 | \t\t\t\t\t\t2 / x; @@ -16,10 +16,10 @@ test.f(0, 1) ","message":"CHC: Division by zero happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1)","severity":"warning","sourceLocation":{"end":216,"file":"A","start":211},"type":"Warning"}],"sources":{"A":{"id":0}}} +test.f(0x0, 1)","severity":"warning","sourceLocation":{"end":216,"file":"A","start":211},"type":"Warning"}],"sources":{"A":{"id":0}}} diff --git a/test/cmdlineTests/standard_model_checker_targets_out_of_bounds_chc/output.json b/test/cmdlineTests/standard_model_checker_targets_out_of_bounds_chc/output.json index bdaa14b50..436942c45 100644 --- a/test/cmdlineTests/standard_model_checker_targets_out_of_bounds_chc/output.json +++ b/test/cmdlineTests/standard_model_checker_targets_out_of_bounds_chc/output.json @@ -1,13 +1,13 @@ {"errors":[{"component":"general","errorCode":"6368","formattedMessage":"Warning: CHC: Out of bounds access happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> A:14:7: | 14 | \t\t\t\t\t\tarr[x]; @@ -16,10 +16,10 @@ test.f(0, 1) ","message":"CHC: Out of bounds access happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1)","severity":"warning","sourceLocation":{"end":289,"file":"A","start":283},"type":"Warning"}],"sources":{"A":{"id":0}}} +test.f(0x0, 1)","severity":"warning","sourceLocation":{"end":289,"file":"A","start":283},"type":"Warning"}],"sources":{"A":{"id":0}}} diff --git a/test/cmdlineTests/standard_model_checker_targets_overflow_chc/output.json b/test/cmdlineTests/standard_model_checker_targets_overflow_chc/output.json index 794a11b04..5a5410b0c 100644 --- a/test/cmdlineTests/standard_model_checker_targets_overflow_chc/output.json +++ b/test/cmdlineTests/standard_model_checker_targets_overflow_chc/output.json @@ -1,13 +1,13 @@ {"errors":[{"component":"general","errorCode":"4984","formattedMessage":"Warning: CHC: Overflow (resulting value larger than 2**256 - 1) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 1 Transaction trace: test.constructor() State: arr = [] -test.f(0, 2) +test.f(0x0, 2) --> A:9:7: | 9 | \t\t\t\t\t\tx + type(uint).max; @@ -16,10 +16,10 @@ test.f(0, 2) ","message":"CHC: Overflow (resulting value larger than 2**256 - 1) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 1 Transaction trace: test.constructor() State: arr = [] -test.f(0, 2)","severity":"warning","sourceLocation":{"end":203,"file":"A","start":185},"type":"Warning"}],"sources":{"A":{"id":0}}} +test.f(0x0, 2)","severity":"warning","sourceLocation":{"end":203,"file":"A","start":185},"type":"Warning"}],"sources":{"A":{"id":0}}} diff --git a/test/cmdlineTests/standard_model_checker_targets_pop_empty_chc/output.json b/test/cmdlineTests/standard_model_checker_targets_pop_empty_chc/output.json index b6e891d6c..87edd534d 100644 --- a/test/cmdlineTests/standard_model_checker_targets_pop_empty_chc/output.json +++ b/test/cmdlineTests/standard_model_checker_targets_pop_empty_chc/output.json @@ -1,13 +1,13 @@ {"errors":[{"component":"general","errorCode":"2529","formattedMessage":"Warning: CHC: Empty array \"pop\" happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> A:13:7: | 13 | \t\t\t\t\t\tarr.pop(); @@ -16,10 +16,10 @@ test.f(0, 1) ","message":"CHC: Empty array \"pop\" happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1)","severity":"warning","sourceLocation":{"end":275,"file":"A","start":266},"type":"Warning"}],"sources":{"A":{"id":0}}} +test.f(0x0, 1)","severity":"warning","sourceLocation":{"end":275,"file":"A","start":266},"type":"Warning"}],"sources":{"A":{"id":0}}} diff --git a/test/cmdlineTests/standard_model_checker_targets_underflow_chc/output.json b/test/cmdlineTests/standard_model_checker_targets_underflow_chc/output.json index 7a22d148a..096bb971b 100644 --- a/test/cmdlineTests/standard_model_checker_targets_underflow_chc/output.json +++ b/test/cmdlineTests/standard_model_checker_targets_underflow_chc/output.json @@ -1,13 +1,13 @@ {"errors":[{"component":"general","errorCode":"3944","formattedMessage":"Warning: CHC: Underflow (resulting value less than 0) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 0) +test.f(0x0, 0) --> A:8:7: | 8 | \t\t\t\t\t\t--x; @@ -16,10 +16,10 @@ test.f(0, 0) ","message":"CHC: Underflow (resulting value less than 0) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 0)","severity":"warning","sourceLocation":{"end":177,"file":"A","start":174},"type":"Warning"}],"sources":{"A":{"id":0}}} +test.f(0x0, 0)","severity":"warning","sourceLocation":{"end":177,"file":"A","start":174},"type":"Warning"}],"sources":{"A":{"id":0}}} diff --git a/test/cmdlineTests/standard_model_checker_targets_underflow_overflow_assert_chc/output.json b/test/cmdlineTests/standard_model_checker_targets_underflow_overflow_assert_chc/output.json index 472866447..3ea910cba 100644 --- a/test/cmdlineTests/standard_model_checker_targets_underflow_overflow_assert_chc/output.json +++ b/test/cmdlineTests/standard_model_checker_targets_underflow_overflow_assert_chc/output.json @@ -1,13 +1,13 @@ {"errors":[{"component":"general","errorCode":"3944","formattedMessage":"Warning: CHC: Underflow (resulting value less than 0) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 0) +test.f(0x0, 0) --> A:8:7: | 8 | \t\t\t\t\t\t--x; @@ -16,22 +16,22 @@ test.f(0, 0) ","message":"CHC: Underflow (resulting value less than 0) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 0)","severity":"warning","sourceLocation":{"end":177,"file":"A","start":174},"type":"Warning"},{"component":"general","errorCode":"4984","formattedMessage":"Warning: CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +test.f(0x0, 0)","severity":"warning","sourceLocation":{"end":177,"file":"A","start":174},"type":"Warning"},{"component":"general","errorCode":"4984","formattedMessage":"Warning: CHC: Overflow (resulting value larger than 2**256 - 1) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 1 Transaction trace: test.constructor() State: arr = [] -test.f(0, 2) +test.f(0x0, 2) --> A:9:7: | 9 | \t\t\t\t\t\tx + type(uint).max; @@ -40,22 +40,22 @@ test.f(0, 2) ","message":"CHC: Overflow (resulting value larger than 2**256 - 1) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 1 Transaction trace: test.constructor() State: arr = [] -test.f(0, 2)","severity":"warning","sourceLocation":{"end":203,"file":"A","start":185},"type":"Warning"},{"component":"general","errorCode":"6328","formattedMessage":"Warning: CHC: Assertion violation happens here. +test.f(0x0, 2)","severity":"warning","sourceLocation":{"end":203,"file":"A","start":185},"type":"Warning"},{"component":"general","errorCode":"6328","formattedMessage":"Warning: CHC: Assertion violation happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1) +test.f(0x0, 1) --> A:12:7: | 12 | \t\t\t\t\t\tassert(x > 0); @@ -64,10 +64,10 @@ test.f(0, 1) ","message":"CHC: Assertion violation happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 1)","severity":"warning","sourceLocation":{"end":258,"file":"A","start":245},"type":"Warning"}],"sources":{"A":{"id":0}}} +test.f(0x0, 1)","severity":"warning","sourceLocation":{"end":258,"file":"A","start":245},"type":"Warning"}],"sources":{"A":{"id":0}}} diff --git a/test/cmdlineTests/standard_model_checker_targets_underflow_overflow_chc/output.json b/test/cmdlineTests/standard_model_checker_targets_underflow_overflow_chc/output.json index d4a502b4b..88ed4136b 100644 --- a/test/cmdlineTests/standard_model_checker_targets_underflow_overflow_chc/output.json +++ b/test/cmdlineTests/standard_model_checker_targets_underflow_overflow_chc/output.json @@ -1,13 +1,13 @@ {"errors":[{"component":"general","errorCode":"3944","formattedMessage":"Warning: CHC: Underflow (resulting value less than 0) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 0) +test.f(0x0, 0) --> A:8:7: | 8 | \t\t\t\t\t\t--x; @@ -16,22 +16,22 @@ test.f(0, 0) ","message":"CHC: Underflow (resulting value less than 0) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 0 Transaction trace: test.constructor() State: arr = [] -test.f(0, 0)","severity":"warning","sourceLocation":{"end":177,"file":"A","start":174},"type":"Warning"},{"component":"general","errorCode":"4984","formattedMessage":"Warning: CHC: Overflow (resulting value larger than 2**256 - 1) happens here. +test.f(0x0, 0)","severity":"warning","sourceLocation":{"end":177,"file":"A","start":174},"type":"Warning"},{"component":"general","errorCode":"4984","formattedMessage":"Warning: CHC: Overflow (resulting value larger than 2**256 - 1) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 1 Transaction trace: test.constructor() State: arr = [] -test.f(0, 2) +test.f(0x0, 2) --> A:9:7: | 9 | \t\t\t\t\t\tx + type(uint).max; @@ -40,10 +40,10 @@ test.f(0, 2) ","message":"CHC: Overflow (resulting value larger than 2**256 - 1) happens here. Counterexample: arr = [] -a = 0 +a = 0x0 x = 1 Transaction trace: test.constructor() State: arr = [] -test.f(0, 2)","severity":"warning","sourceLocation":{"end":203,"file":"A","start":185},"type":"Warning"}],"sources":{"A":{"id":0}}} +test.f(0x0, 2)","severity":"warning","sourceLocation":{"end":203,"file":"A","start":185},"type":"Warning"}],"sources":{"A":{"id":0}}} diff --git a/test/libsolidity/smtCheckerTests/array_members/array_push_string_literal.sol b/test/libsolidity/smtCheckerTests/array_members/array_push_string_literal.sol index f401bc11e..55b2160c4 100644 --- a/test/libsolidity/smtCheckerTests/array_members/array_push_string_literal.sol +++ b/test/libsolidity/smtCheckerTests/array_members/array_push_string_literal.sol @@ -15,4 +15,4 @@ contract C { // SMTEngine: all // ---- // Warning 6328: (139-161): CHC: Assertion violation happens here. -// Warning 6328: (263-290): CHC: Assertion violation happens here.\nCounterexample:\ndata = [1]\n\nTransaction trace:\nC.constructor()\nState: data = []\nC.g() +// Warning 6328: (263-290): CHC: Assertion violation happens here.\nCounterexample:\ndata = [0x01]\n\nTransaction trace:\nC.constructor()\nState: data = []\nC.g() diff --git a/test/libsolidity/smtCheckerTests/blockchain_state/balance_non_zero.sol b/test/libsolidity/smtCheckerTests/blockchain_state/balance_non_zero.sol index 22d9ae86a..bf7fc6de9 100644 --- a/test/libsolidity/smtCheckerTests/blockchain_state/balance_non_zero.sol +++ b/test/libsolidity/smtCheckerTests/blockchain_state/balance_non_zero.sol @@ -7,5 +7,5 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (40-74): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor() -// Warning 6328: (93-126): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor() +// Warning 6328: (40-74): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor(){ msg.value: 0 } +// Warning 6328: (93-126): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor(){ msg.value: 0 } diff --git a/test/libsolidity/smtCheckerTests/blockchain_state/balance_non_zero_2.sol b/test/libsolidity/smtCheckerTests/blockchain_state/balance_non_zero_2.sol index 1bf99fca3..100f11066 100644 --- a/test/libsolidity/smtCheckerTests/blockchain_state/balance_non_zero_2.sol +++ b/test/libsolidity/smtCheckerTests/blockchain_state/balance_non_zero_2.sol @@ -10,4 +10,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (153-188): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor(){ value: 101 }\nC.f() +// Warning 6328: (153-188): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor(){ msg.value: 101 }\nC.f() diff --git a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_2.sol b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_2.sol index f9f0093b0..c561179ec 100644 --- a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_2.sol +++ b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_2.sol @@ -15,5 +15,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(){ value: 28100 }\nState: x = 115792089237316195423570985008687907853269984665640564039457584007913129639926, once = false\nC.f(){ value: 8 } -// Warning 6328: (235-273): CHC: Assertion violation happens here.\nCounterexample:\nx = 0, once = true\n\nTransaction trace:\nC.constructor()\nState: x = 0, once = false\nC.f(){ value: 8 } +// 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 } diff --git a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_3.sol b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_3.sol index b581a537d..169e1a066 100644 --- a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_3.sol +++ b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_3.sol @@ -6,4 +6,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (40-82): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor() +// Warning 6328: (40-82): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor(){ msg.value: 0 } diff --git a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_4.sol b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_4.sol index 47eade523..183e60d95 100644 --- a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_4.sol +++ b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_4.sol @@ -15,7 +15,7 @@ contract C { // Warning 4984: (82-85): CHC: Overflow (resulting value larger than 2**256 - 1) might happen here. // Warning 4984: (154-160): CHC: Overflow (resulting value larger than 2**256 - 1) might happen here. // Warning 4984: (212-218): CHC: Overflow (resulting value larger than 2**256 - 1) might happen here. -// Warning 6328: (180-219): CHC: Assertion violation happens here.\nCounterexample:\nc = 1\n\nTransaction trace:\nC.constructor()\nState: c = 0\nC.f(){ value: 11 }\nState: c = 1\nC.inv() +// Warning 6328: (180-219): CHC: Assertion violation happens here.\nCounterexample:\nc = 1\n\nTransaction trace:\nC.constructor()\nState: c = 0\nC.f(){ msg.value: 11 }\nState: c = 1\nC.inv() // Warning 2661: (82-85): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. // Warning 2661: (154-160): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. // Warning 2661: (212-218): BMC: Overflow (resulting value larger than 2**256 - 1) happens here. diff --git a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_calls.sol b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_calls.sol index 68bae9ac5..3bc569997 100644 --- a/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_calls.sol +++ b/test/libsolidity/smtCheckerTests/blockchain_state/balance_receive_calls.sol @@ -21,6 +21,6 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (173-208): CHC: Assertion violation happens here.\nCounterexample:\nonce = true\n\nTransaction trace:\nC.constructor()\nState: once = false\nC.f(){ value: 10 } -// Warning 6328: (321-356): CHC: Assertion violation happens here.\nCounterexample:\nonce = true\n\nTransaction trace:\nC.constructor()\nState: once = false\nC.f(){ value: 10 }\n C.g(){ value: 10 } -- internal call -// Warning 6328: (469-504): CHC: Assertion violation happens here.\nCounterexample:\nonce = true\n\nTransaction trace:\nC.constructor()\nState: once = false\nC.f(){ value: 10 }\n C.g(){ value: 10 } -- internal call\n C.h(){ value: 10 } -- internal call +// Warning 6328: (173-208): CHC: Assertion violation happens here.\nCounterexample:\nonce = true\n\nTransaction trace:\nC.constructor()\nState: once = false\nC.f(){ msg.value: 10 } +// Warning 6328: (321-356): CHC: Assertion violation happens here.\nCounterexample:\nonce = true\n\nTransaction trace:\nC.constructor()\nState: once = false\nC.f(){ msg.value: 10 }\n C.g() -- internal call +// Warning 6328: (469-504): CHC: Assertion violation happens here.\nCounterexample:\nonce = true\n\nTransaction trace:\nC.constructor()\nState: once = false\nC.f(){ msg.value: 10 }\n C.g() -- internal call\n C.h() -- internal call diff --git a/test/libsolidity/smtCheckerTests/external_calls/call_mutex_unsafe.sol b/test/libsolidity/smtCheckerTests/external_calls/call_mutex_unsafe.sol index f53178198..ad17e3d05 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/call_mutex_unsafe.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/call_mutex_unsafe.sol @@ -23,4 +23,4 @@ contract C { // SMTEngine: all // ---- // 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 = 0\ny = 0\n\nTransaction trace:\nC.constructor()\nState: x = 0, lock = false\nC.f(0)\n _a.call("aaaaa") -- untrusted external call, synthesized as:\n C.set(1) -- reentrant call +// 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 diff --git a/test/libsolidity/smtCheckerTests/external_calls/call_with_value_2.sol b/test/libsolidity/smtCheckerTests/external_calls/call_with_value_2.sol index 792bb0730..c38658080 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/call_with_value_2.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/call_with_value_2.sol @@ -11,5 +11,5 @@ contract C { // ---- // Warning 9302: (96-116): Return value of low-level calls not used. // Warning 6328: (120-156): CHC: Assertion violation might happen here. -// Warning 6328: (175-210): CHC: Assertion violation happens here.\nCounterexample:\n\ni = 0\n\nTransaction trace:\nC.constructor()\nC.g(0)\n i.call{value: 0}("") -- untrusted external call +// Warning 6328: (175-210): CHC: Assertion violation happens here.\nCounterexample:\n\ni = 0x0\n\nTransaction trace:\nC.constructor()\nC.g(0x0)\n i.call{value: 0}("") -- untrusted external call // Warning 4661: (120-156): BMC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_reentrancy_1.sol b/test/libsolidity/smtCheckerTests/external_calls/external_reentrancy_1.sol index d92de6f04..adde1eb61 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_reentrancy_1.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_reentrancy_1.sol @@ -16,4 +16,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (206-220): CHC: Assertion violation happens here.\nCounterexample:\nlocked = false\ntarget = 0\n\nTransaction trace:\nC.constructor()\nState: locked = true\nC.call(0)\n D(target).e() -- untrusted external call, synthesized as:\n C.broken() -- reentrant call +// Warning 6328: (206-220): 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.broken() -- reentrant call diff --git a/test/libsolidity/smtCheckerTests/external_calls/external_reentrancy_2.sol b/test/libsolidity/smtCheckerTests/external_calls/external_reentrancy_2.sol index 92c53a5e8..19ff2bbad 100644 --- a/test/libsolidity/smtCheckerTests/external_calls/external_reentrancy_2.sol +++ b/test/libsolidity/smtCheckerTests/external_calls/external_reentrancy_2.sol @@ -13,4 +13,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (117-131): CHC: Assertion violation happens here.\nCounterexample:\nlocked = false\ntarget = 0\n\nTransaction trace:\nC.constructor()\nState: locked = true\nC.call(0)\n D(target).e() -- untrusted external call, synthesized as:\n C.call(0) -- reentrant call +// 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 diff --git a/test/libsolidity/smtCheckerTests/file_level/constant_string_at_file_level.sol b/test/libsolidity/smtCheckerTests/file_level/constant_string_at_file_level.sol index a40fbc216..fe2ebfdde 100644 --- a/test/libsolidity/smtCheckerTests/file_level/constant_string_at_file_level.sol +++ b/test/libsolidity/smtCheckerTests/file_level/constant_string_at_file_level.sol @@ -38,4 +38,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (968-983): CHC: Assertion violation happens here.\nCounterexample:\n\nw = 56\nz = 1\nt = 44048180624707321370159228589897778088919435935156254407473833945046349512704\n\nTransaction trace:\nC.constructor()\nC.p()\n C.f() -- internal call\n C.g() -- internal call\n C.h() -- internal call\n C.i() -- internal call +// Warning 6328: (968-983): CHC: Assertion violation happens here.\nCounterexample:\n\nw = 56\nz = 1\nt = 0x61626300ff5f5f00000000000000000000000000000000000000000000000000\n\nTransaction trace:\nC.constructor()\nC.p()\n C.f() -- internal call\n C.g() -- internal call\n C.h() -- internal call\n C.i() -- internal call diff --git a/test/libsolidity/smtCheckerTests/file_level/file_level_call_via_module.sol b/test/libsolidity/smtCheckerTests/file_level/file_level_call_via_module.sol index 9cea98f6b..0297428c6 100644 --- a/test/libsolidity/smtCheckerTests/file_level/file_level_call_via_module.sol +++ b/test/libsolidity/smtCheckerTests/file_level/file_level_call_via_module.sol @@ -18,5 +18,5 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (b.sol:208-222): CHC: Assertion violation happens here.\nCounterexample:\n\na = 7\nb = 3\n\nTransaction trace:\nC.constructor()\nC.p()\n C.f() -- internal call\n a.sol:f(2) -- internal call\n a.sol:f([97, 98, 99]) -- internal call -// Warning 6328: (b.sol:274-288): CHC: Assertion violation happens here.\nCounterexample:\n\na = 7\nb = 3\n\nTransaction trace:\nC.constructor()\nC.p()\n C.f() -- internal call\n a.sol:f(2) -- internal call\n a.sol:f([97, 98, 99]) -- internal call +// Warning 6328: (b.sol:208-222): CHC: Assertion violation happens here.\nCounterexample:\n\na = 7\nb = 3\n\nTransaction trace:\nC.constructor()\nC.p()\n C.f() -- internal call\n a.sol:f(2) -- internal call\n a.sol:f([0x61, 0x62, 0x63]) -- internal call +// Warning 6328: (b.sol:274-288): CHC: Assertion violation happens here.\nCounterexample:\n\na = 7\nb = 3\n\nTransaction trace:\nC.constructor()\nC.p()\n C.f() -- internal call\n a.sol:f(2) -- internal call\n a.sol:f([0x61, 0x62, 0x63]) -- internal call diff --git a/test/libsolidity/smtCheckerTests/file_level/overloads.sol b/test/libsolidity/smtCheckerTests/file_level/overloads.sol index 9f7e63466..7224464b4 100644 --- a/test/libsolidity/smtCheckerTests/file_level/overloads.sol +++ b/test/libsolidity/smtCheckerTests/file_level/overloads.sol @@ -15,4 +15,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (229-243): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 2\ny = 3\n\nTransaction trace:\nC.constructor()\nC.g()\n f(2) -- internal call\n f([97, 98, 99]) -- internal call +// Warning 6328: (229-243): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 2\ny = 3\n\nTransaction trace:\nC.constructor()\nC.g()\n f(2) -- internal call\n f([0x61, 0x62, 0x63]) -- internal call diff --git a/test/libsolidity/smtCheckerTests/function_selector/homer.sol b/test/libsolidity/smtCheckerTests/function_selector/homer.sol index 4fec30995..552a4d895 100644 --- a/test/libsolidity/smtCheckerTests/function_selector/homer.sol +++ b/test/libsolidity/smtCheckerTests/function_selector/homer.sol @@ -43,4 +43,4 @@ contract Homer is ERC165, Simpson { // ==== // SMTEngine: all // ---- -// Warning 6328: (1340-1395): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nHomer.constructor()\nHomer.check()\n Homer.supportsInterface(1941353618) -- internal call\n Homer.supportsInterface(33540519) -- internal call\n Homer.supportsInterface(2342435274) -- internal call +// Warning 6328: (1340-1395): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nHomer.constructor()\nHomer.check()\n Homer.supportsInterface(0x73b6b492) -- internal call\n Homer.supportsInterface(0x01ffc9a7) -- internal call\n Homer.supportsInterface(0x8b9eb9ca) -- internal call diff --git a/test/libsolidity/smtCheckerTests/function_selector/selector_2.sol b/test/libsolidity/smtCheckerTests/function_selector/selector_2.sol index 7cabb7ade..c3a4b8866 100644 --- a/test/libsolidity/smtCheckerTests/function_selector/selector_2.sol +++ b/test/libsolidity/smtCheckerTests/function_selector/selector_2.sol @@ -9,4 +9,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (92-126): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (92-126): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f(){ msg.sig: 0x26121ff0 } diff --git a/test/libsolidity/smtCheckerTests/functions/getters/address.sol b/test/libsolidity/smtCheckerTests/functions/getters/address.sol index ff4032a65..92bb2761d 100644 --- a/test/libsolidity/smtCheckerTests/functions/getters/address.sol +++ b/test/libsolidity/smtCheckerTests/functions/getters/address.sol @@ -14,5 +14,5 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (171-197): CHC: Assertion violation happens here.\nCounterexample:\nx = 0, y = 0\na = 0\nb = 0\n\nTransaction trace:\nC.constructor()\nState: x = 0, y = 0\nC.f() -// Warning 6328: (249-275): CHC: Assertion violation happens here.\nCounterexample:\nx = 0, y = 0\na = 0\nb = 0\n\nTransaction trace:\nC.constructor()\nState: x = 0, y = 0\nC.f() +// Warning 6328: (171-197): CHC: Assertion violation happens here.\nCounterexample:\nx = 0x0, y = 0x0\na = 0x0\nb = 0x0\n\nTransaction trace:\nC.constructor()\nState: x = 0x0, y = 0x0\nC.f() +// Warning 6328: (249-275): CHC: Assertion violation happens here.\nCounterexample:\nx = 0x0, y = 0x0\na = 0x0\nb = 0x0\n\nTransaction trace:\nC.constructor()\nState: x = 0x0, y = 0x0\nC.f() diff --git a/test/libsolidity/smtCheckerTests/functions/getters/fixed_bytes.sol b/test/libsolidity/smtCheckerTests/functions/getters/fixed_bytes.sol index fa56e15c8..ac47ded03 100644 --- a/test/libsolidity/smtCheckerTests/functions/getters/fixed_bytes.sol +++ b/test/libsolidity/smtCheckerTests/functions/getters/fixed_bytes.sol @@ -14,5 +14,5 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (159-175): CHC: Assertion violation happens here.\nCounterexample:\nx = 0, y = 0\na = 0\nb = 0\n\nTransaction trace:\nC.constructor()\nState: x = 0, y = 0\nC.f() -// Warning 6328: (227-245): CHC: Assertion violation happens here.\nCounterexample:\nx = 0, y = 0\na = 0\nb = 0\n\nTransaction trace:\nC.constructor()\nState: x = 0, y = 0\nC.f() +// Warning 6328: (159-175): CHC: Assertion violation happens here.\nCounterexample:\nx = 0x0, y = 0x0\na = 0x0\nb = 0x0\n\nTransaction trace:\nC.constructor()\nState: x = 0x0, y = 0x0\nC.f() +// Warning 6328: (227-245): CHC: Assertion violation happens here.\nCounterexample:\nx = 0x0, y = 0x0\na = 0x0\nb = 0x0\n\nTransaction trace:\nC.constructor()\nState: x = 0x0, y = 0x0\nC.f() diff --git a/test/libsolidity/smtCheckerTests/functions/payable_2.sol b/test/libsolidity/smtCheckerTests/functions/payable_2.sol index 6411eae62..98717b133 100644 --- a/test/libsolidity/smtCheckerTests/functions/payable_2.sol +++ b/test/libsolidity/smtCheckerTests/functions/payable_2.sol @@ -24,4 +24,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (261-283): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.g2(){ value: 35 }\n C.i(){ value: 35 } -- internal call +// Warning 6328: (261-283): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.g2(){ msg.value: 35 }\n C.i() -- internal call diff --git a/test/libsolidity/smtCheckerTests/imports/import_base.sol b/test/libsolidity/smtCheckerTests/imports/import_base.sol index f0ca042be..4ad653357 100644 --- a/test/libsolidity/smtCheckerTests/imports/import_base.sol +++ b/test/libsolidity/smtCheckerTests/imports/import_base.sol @@ -20,4 +20,4 @@ contract Der is Base { // ==== // SMTEngine: all // ---- -// Warning 6328: (der:173-186): CHC: Assertion violation happens here.\nCounterexample:\nx = 3, a = 0\ny = 0\n\nTransaction trace:\nDer.constructor()\nState: x = 0, a = 0\nDer.g(0)\n Base.f() -- internal call +// Warning 6328: (der:173-186): CHC: Assertion violation happens here.\nCounterexample:\nx = 3, a = 0x0\ny = 0\n\nTransaction trace:\nDer.constructor()\nState: x = 0, a = 0x0\nDer.g(0)\n Base.f() -- internal call diff --git a/test/libsolidity/smtCheckerTests/imports/import_free_functions.sol b/test/libsolidity/smtCheckerTests/imports/import_free_functions.sol index 4eec2c76a..6e9621b30 100644 --- a/test/libsolidity/smtCheckerTests/imports/import_free_functions.sol +++ b/test/libsolidity/smtCheckerTests/imports/import_free_functions.sol @@ -20,4 +20,4 @@ contract ERC20 { // ==== // SMTEngine: all // ---- -// Warning 3944: (ERC20.sol:121-126): CHC: Underflow (resulting value less than 0) happens here.\nCounterexample:\n\namount = 1\n\nTransaction trace:\nERC20.constructor()\nERC20.transferFrom(1)\n ERC20.sol:sub(0, 1) -- internal call +// Warning 3944: (ERC20.sol:121-126): CHC: Underflow (resulting value less than 0) happens here.\nCounterexample:\n\namount = 1\n\nTransaction trace:\nERC20.constructor()\nERC20.transferFrom(1){ msg.sender: 0x52f6 }\n ERC20.sol:sub(0, 1) -- internal call diff --git a/test/libsolidity/smtCheckerTests/imports/import_library_2.sol b/test/libsolidity/smtCheckerTests/imports/import_library_2.sol index d5c42dad6..4d33d4002 100644 --- a/test/libsolidity/smtCheckerTests/imports/import_library_2.sol +++ b/test/libsolidity/smtCheckerTests/imports/import_library_2.sol @@ -25,4 +25,4 @@ contract ERC20 { // ==== // SMTEngine: all // ---- -// Warning 3944: (ERC20.sol:157-162): CHC: Underflow (resulting value less than 0) happens here.\nCounterexample:\n\namount = 1\n\nTransaction trace:\nERC20.constructor()\nERC20.transferFrom(1)\n SafeMath.sub(0, 1) -- internal call +// Warning 3944: (ERC20.sol:157-162): CHC: Underflow (resulting value less than 0) happens here.\nCounterexample:\n\namount = 1\n\nTransaction trace:\nERC20.constructor()\nERC20.transferFrom(1){ msg.sender: 0x52f6 }\n SafeMath.sub(0, 1) -- internal call diff --git a/test/libsolidity/smtCheckerTests/inheritance/receive_fallback.sol b/test/libsolidity/smtCheckerTests/inheritance/receive_fallback.sol index 9df407cd2..95ae12019 100644 --- a/test/libsolidity/smtCheckerTests/inheritance/receive_fallback.sol +++ b/test/libsolidity/smtCheckerTests/inheritance/receive_fallback.sol @@ -21,6 +21,6 @@ contract B is A { // ==== // SMTEngine: all // ---- -// Warning 6328: (87-101): CHC: Assertion violation happens here.\nCounterexample:\nx = 0\n\nTransaction trace:\nA.constructor()\nState: x = 0\nA.receive(){ value: 2 } +// Warning 6328: (87-101): CHC: Assertion violation happens here.\nCounterexample:\nx = 0\n\nTransaction trace:\nA.constructor()\nState: x = 0\nA.receive(){ msg.value: 2 } // Warning 6328: (136-150): CHC: Assertion violation happens here.\nCounterexample:\nx = 0\n\nTransaction trace:\nA.constructor()\nState: x = 0\nA.g() // Warning 6328: (255-269): CHC: Assertion violation happens here.\nCounterexample:\ny = 0, x = 0\n\nTransaction trace:\nB.constructor()\nState: y = 0, x = 0\nB.fallback() diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment.sol index 8268d8520..f8091f9df 100644 --- a/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment.sol +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment.sol @@ -20,4 +20,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (254-267): CHC: Assertion violation happens here.\nCounterexample:\nx = 0, owner = 0\ny = 1\n\nTransaction trace:\nC.constructor()\nState: x = 0, owner = 0\nC.g(1)\n C.f() -- internal call +// Warning 6328: (254-267): CHC: Assertion violation happens here.\nCounterexample:\nx = 0, owner = 0x0\ny = 1\n\nTransaction trace:\nC.constructor()\nState: x = 0, owner = 0x0\nC.g(1)\n C.f() -- internal call diff --git a/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment_multi_branches.sol b/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment_multi_branches.sol index df6c12cba..9a578cf89 100644 --- a/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment_multi_branches.sol +++ b/test/libsolidity/smtCheckerTests/modifiers/modifier_inside_branch_assignment_multi_branches.sol @@ -34,4 +34,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (540-554): CHC: Assertion violation happens here.\nCounterexample:\nx = 1, owner = 0\ny = 1\n\nTransaction trace:\nC.constructor()\nState: x = 0, owner = 0\nC.g(1) +// Warning 6328: (540-554): CHC: Assertion violation happens here.\nCounterexample:\nx = 1, owner = 0x0\ny = 1\n\nTransaction trace:\nC.constructor()\nState: x = 0, owner = 0x0\nC.g(1){ msg.sender: 0x0 } diff --git a/test/libsolidity/smtCheckerTests/operators/bitwise_not_fixed_bytes.sol b/test/libsolidity/smtCheckerTests/operators/bitwise_not_fixed_bytes.sol index e9e1dea53..6a9d4e90a 100644 --- a/test/libsolidity/smtCheckerTests/operators/bitwise_not_fixed_bytes.sol +++ b/test/libsolidity/smtCheckerTests/operators/bitwise_not_fixed_bytes.sol @@ -9,4 +9,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (100-123): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 65535\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (100-123): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 0xffff\n\nTransaction trace:\nC.constructor()\nC.f() diff --git a/test/libsolidity/smtCheckerTests/operators/bitwise_or_fixed_bytes.sol b/test/libsolidity/smtCheckerTests/operators/bitwise_or_fixed_bytes.sol index 125e54db5..acbe3fa6d 100644 --- a/test/libsolidity/smtCheckerTests/operators/bitwise_or_fixed_bytes.sol +++ b/test/libsolidity/smtCheckerTests/operators/bitwise_or_fixed_bytes.sol @@ -9,4 +9,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (150-175): CHC: Assertion violation happens here.\nCounterexample:\n\n = 0\nb = 255\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (150-175): CHC: Assertion violation happens here.\nCounterexample:\n\n = 0x0\nb = 0xff\n\nTransaction trace:\nC.constructor()\nC.f() diff --git a/test/libsolidity/smtCheckerTests/operators/bytes_new.sol b/test/libsolidity/smtCheckerTests/operators/bytes_new.sol index e41c8740f..b961c53d5 100644 --- a/test/libsolidity/smtCheckerTests/operators/bytes_new.sol +++ b/test/libsolidity/smtCheckerTests/operators/bytes_new.sol @@ -34,5 +34,5 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6368: (468-472): CHC: Out of bounds access happens here.\nCounterexample:\n\nx = [18, 52, 0]\n\nTransaction trace:\nC.constructor()\nC.h() -// Warning 6368: (490-494): CHC: Out of bounds access happens here.\nCounterexample:\n\nx = [18, 52, 0]\n\nTransaction trace:\nC.constructor()\nC.h() +// Warning 6368: (468-472): CHC: Out of bounds access happens here.\nCounterexample:\n\nx = [0x12, 0x34, 0x0]\n\nTransaction trace:\nC.constructor()\nC.h() +// Warning 6368: (490-494): CHC: Out of bounds access happens here.\nCounterexample:\n\nx = [0x12, 0x34, 0x0]\n\nTransaction trace:\nC.constructor()\nC.h() diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_and_fixed_bytes.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_and_fixed_bytes.sol index 03e25854e..b634e8468 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_and_fixed_bytes.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_and_fixed_bytes.sol @@ -13,4 +13,4 @@ contract C { // SMTEngine: all // ---- // Warning 6321: (51-57): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable. -// Warning 6328: (177-191): CHC: Assertion violation happens here.\nCounterexample:\n\n = 0\na = 0\nb = 240\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (177-191): CHC: Assertion violation happens here.\nCounterexample:\n\n = 0x0\na = 0x0\nb = 0xf0\n\nTransaction trace:\nC.constructor()\nC.f() diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_fixed_bytes.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_fixed_bytes.sol index c80c3fb65..edcf3230b 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_fixed_bytes.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_or_fixed_bytes.sol @@ -13,4 +13,4 @@ contract C { // SMTEngine: all // ---- // Warning 6321: (51-57): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable. -// Warning 6328: (177-191): CHC: Assertion violation happens here.\nCounterexample:\n\n = 0\na = 255\nb = 255\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (177-191): CHC: Assertion violation happens here.\nCounterexample:\n\n = 0x0\na = 0xff\nb = 0xff\n\nTransaction trace:\nC.constructor()\nC.f() diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_string_literal_2.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_string_literal_2.sol index e142ee930..59bd6c7b9 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_string_literal_2.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_string_literal_2.sol @@ -14,4 +14,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (147-165): CHC: Assertion violation happens here.\nCounterexample:\n\ny = 6579559\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (147-165): CHC: Assertion violation happens here.\nCounterexample:\n\ny = 0x646567\n\nTransaction trace:\nC.constructor()\nC.f() diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_string_literal_3.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_string_literal_3.sol index 933f15980..3ac248fb2 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_string_literal_3.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_string_literal_3.sol @@ -17,5 +17,5 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (229-276): CHC: Assertion violation happens here.\nCounterexample:\n\ny = 43595849750559157961410616371195012376776328331498503227444818324475146035296\nz = 43595849750559157961410616371195012376776328331498503227444818324475146035296\n\nTransaction trace:\nC.constructor()\nC.f() -// Warning 6328: (394-437): CHC: Assertion violation happens here.\nCounterexample:\n\ny = 44959890247538927454655645290332771782915717053340361485195502024921998844258\nz = 44959890247538927454655645290332771782915717053340361485195502024921998844258\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (229-276): CHC: Assertion violation happens here.\nCounterexample:\n\ny = 0x6062606464666060606260646466606060626064646660606062606464666060\nz = 0x6062606464666060606260646466606060626064646660606062606464666060\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (394-437): CHC: Assertion violation happens here.\nCounterexample:\n\ny = 0x63666566676e616263666566676e616263666566676e616263666566676e6162\nz = 0x63666566676e616263666566676e616263666566676e616263666566676e6162\n\nTransaction trace:\nC.constructor()\nC.f() diff --git a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_xor_fixed_bytes.sol b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_xor_fixed_bytes.sol index 5d53d9132..6856f72e0 100644 --- a/test/libsolidity/smtCheckerTests/operators/compound_bitwise_xor_fixed_bytes.sol +++ b/test/libsolidity/smtCheckerTests/operators/compound_bitwise_xor_fixed_bytes.sol @@ -13,4 +13,4 @@ contract C { // SMTEngine: all // ---- // Warning 6321: (51-57): Unnamed return variable can remain unassigned. Add an explicit return with value to all non-reverting code paths or name the variable. -// Warning 6328: (178-195): CHC: Assertion violation happens here.\nCounterexample:\n\n = 0\na = 255\nb = 240\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (178-195): CHC: Assertion violation happens here.\nCounterexample:\n\n = 0x0\na = 0xff\nb = 0xf0\n\nTransaction trace:\nC.constructor()\nC.f() diff --git a/test/libsolidity/smtCheckerTests/operators/index_access_for_bytes.sol b/test/libsolidity/smtCheckerTests/operators/index_access_for_bytes.sol index 8a27f6f63..4cb34c49e 100644 --- a/test/libsolidity/smtCheckerTests/operators/index_access_for_bytes.sol +++ b/test/libsolidity/smtCheckerTests/operators/index_access_for_bytes.sol @@ -9,4 +9,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (152-173): CHC: Assertion violation happens here.\nCounterexample:\n\nx = [0, 17, 34, 51]\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (152-173): CHC: Assertion violation happens here.\nCounterexample:\n\nx = [0x0, 0x11, 0x22, 0x33]\n\nTransaction trace:\nC.constructor()\nC.f() diff --git a/test/libsolidity/smtCheckerTests/out_of_bounds/fixed_bytes_2.sol b/test/libsolidity/smtCheckerTests/out_of_bounds/fixed_bytes_2.sol index ab1275ab2..f4e90ddb7 100644 --- a/test/libsolidity/smtCheckerTests/out_of_bounds/fixed_bytes_2.sol +++ b/test/libsolidity/smtCheckerTests/out_of_bounds/fixed_bytes_2.sol @@ -6,4 +6,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6368: (83-87): CHC: Out of bounds access happens here.\nCounterexample:\n\nx = 0\ny = 4\n = 0\n\nTransaction trace:\nC.constructor()\nC.r(0, 4) +// Warning 6368: (83-87): CHC: Out of bounds access happens here.\nCounterexample:\n\nx = 0x0\ny = 4\n = 0x0\n\nTransaction trace:\nC.constructor()\nC.r(0x0, 4) diff --git a/test/libsolidity/smtCheckerTests/special/abi_decode_simple.sol b/test/libsolidity/smtCheckerTests/special/abi_decode_simple.sol index bb82c659e..618f76276 100644 --- a/test/libsolidity/smtCheckerTests/special/abi_decode_simple.sol +++ b/test/libsolidity/smtCheckerTests/special/abi_decode_simple.sol @@ -13,4 +13,4 @@ contract C { // Warning 2072: (82-86): Unused local variable. // Warning 2072: (140-150): Unused local variable. // Warning 2072: (152-156): Unused local variable. -// Warning 6328: (220-236): CHC: Assertion violation happens here.\nCounterexample:\n\na1 = 2437\nb1 = 10\nc1 = 9\na2 = 2437\nb2 = 10\nc2 = 9\n\nTransaction trace:\nC.constructor()\nC.f(data) +// Warning 6328: (220-236): CHC: Assertion violation happens here.\nCounterexample:\n\na1 = 2437\nb1 = 0x0a\nc1 = 9\na2 = 2437\nb2 = 0x0a\nc2 = 9\n\nTransaction trace:\nC.constructor()\nC.f(data) diff --git a/test/libsolidity/smtCheckerTests/special/block_vars_chc_internal.sol b/test/libsolidity/smtCheckerTests/special/block_vars_chc_internal.sol index ca4873d67..2ebf4d326 100644 --- a/test/libsolidity/smtCheckerTests/special/block_vars_chc_internal.sol +++ b/test/libsolidity/smtCheckerTests/special/block_vars_chc_internal.sol @@ -25,8 +25,11 @@ contract C { assert(gas == block.gaslimit); // should hold with CHC assert(number == block.number); // should hold with CHC assert(timestamp == block.timestamp); // should hold with CHC + + assert(coin == address(this)); // should fail } } // ==== // SMTEngine: chc // ---- +// Warning 6328: (770-799): CHC: Assertion violation happens here.\nCounterexample:\ncoin = 0x0, dif = 0, gas = 0, number = 0, timestamp = 0\n\nTransaction trace:\nC.constructor()\nState: coin = 0x0, dif = 0, gas = 0, number = 0, timestamp = 0\nC.f(){ block.coinbase: 0x0, block.difficulty: 0, block.gaslimit: 0, block.number: 0, block.timestamp: 0 }\n C.g() -- internal call diff --git a/test/libsolidity/smtCheckerTests/special/msg_parens_1.sol b/test/libsolidity/smtCheckerTests/special/msg_parens_1.sol index 9a1df3724..6eb19e5e8 100644 --- a/test/libsolidity/smtCheckerTests/special/msg_parens_1.sol +++ b/test/libsolidity/smtCheckerTests/special/msg_parens_1.sol @@ -7,6 +7,7 @@ contract C { // ==== // SMTEngine: all // SMTIgnoreOS: macos +// SMTIgnoreCex: yes // ---- -// Warning 6328: (46-71): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f(){ value: 11 } -// Warning 6328: (75-113): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (46-71): CHC: Assertion violation happens here. +// Warning 6328: (75-113): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/special/msg_sig.sol b/test/libsolidity/smtCheckerTests/special/msg_sig.sol index a87dc18b3..cf701f6d0 100644 --- a/test/libsolidity/smtCheckerTests/special/msg_sig.sol +++ b/test/libsolidity/smtCheckerTests/special/msg_sig.sol @@ -25,6 +25,6 @@ contract C // ==== // SMTEngine: all // ---- -// Warning 6328: (43-72): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f() -// Warning 6328: (370-399): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f()\n C.fi() -- internal call\n C.gi() -- internal call -// Warning 6328: (510-539): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.h() +// Warning 6328: (43-72): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f(){ msg.sig: 0x26121ff0 } +// Warning 6328: (370-399): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f(){ msg.sig: 0x26121ff0 }\n C.fi() -- internal call\n C.gi() -- internal call +// Warning 6328: (510-539): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.h(){ msg.sig: 0xb8c9d365 } diff --git a/test/libsolidity/smtCheckerTests/special/msg_value_1.sol b/test/libsolidity/smtCheckerTests/special/msg_value_1.sol index 9888d326d..51e696f56 100644 --- a/test/libsolidity/smtCheckerTests/special/msg_value_1.sol +++ b/test/libsolidity/smtCheckerTests/special/msg_value_1.sol @@ -6,5 +6,5 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 4984: (55-68): CHC: Overflow (resulting value larger than 2**256 - 1) happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f(){ value: 115792089237316195423570985008687907853269984665640564039457584007913129639931 } -// Warning 4984: (55-80): CHC: Overflow (resulting value larger than 2**256 - 1) happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f(){ value: 57896044618658097711785492504343953926634992332820282019728792003956564819966 } +// Warning 4984: (55-68): CHC: Overflow (resulting value larger than 2**256 - 1) happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f(){ msg.value: 115792089237316195423570985008687907853269984665640564039457584007913129639931 } +// Warning 4984: (55-80): CHC: Overflow (resulting value larger than 2**256 - 1) happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f(){ msg.value: 57896044618658097711785492504343953926634992332820282019728792003956564819966 } diff --git a/test/libsolidity/smtCheckerTests/special/msg_value_2.sol b/test/libsolidity/smtCheckerTests/special/msg_value_2.sol index 1c37ce029..acf1b9e5d 100644 --- a/test/libsolidity/smtCheckerTests/special/msg_value_2.sol +++ b/test/libsolidity/smtCheckerTests/special/msg_value_2.sol @@ -6,4 +6,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (46-67): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (46-67): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nC.constructor()\nC.f(){ msg.value: 0 } diff --git a/test/libsolidity/smtCheckerTests/special/msg_value_4.sol b/test/libsolidity/smtCheckerTests/special/msg_value_4.sol index f9bfb0173..82edb4a39 100644 --- a/test/libsolidity/smtCheckerTests/special/msg_value_4.sol +++ b/test/libsolidity/smtCheckerTests/special/msg_value_4.sol @@ -13,4 +13,4 @@ contract B { // ==== // SMTEngine: all // ---- -// Warning 6328: (154-176): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nB.constructor(){ value: 39 } +// Warning 6328: (154-176): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nB.constructor(){ msg.value: 39 } diff --git a/test/libsolidity/smtCheckerTests/special/msg_value_inheritance_1.sol b/test/libsolidity/smtCheckerTests/special/msg_value_inheritance_1.sol index 00e183832..8b69352c2 100644 --- a/test/libsolidity/smtCheckerTests/special/msg_value_inheritance_1.sol +++ b/test/libsolidity/smtCheckerTests/special/msg_value_inheritance_1.sol @@ -14,4 +14,4 @@ contract C is A { // ==== // SMTEngine: all // ---- -// Warning 6328: (68-82): CHC: Assertion violation happens here.\nCounterexample:\nx = 1\n\nTransaction trace:\nA.constructor(){ value: 1 } +// Warning 6328: (68-82): CHC: Assertion violation happens here.\nCounterexample:\nx = 1\n\nTransaction trace:\nA.constructor(){ msg.value: 1 } diff --git a/test/libsolidity/smtCheckerTests/special/msg_value_inheritance_2.sol b/test/libsolidity/smtCheckerTests/special/msg_value_inheritance_2.sol index efc59fcfc..10b8ef0c2 100644 --- a/test/libsolidity/smtCheckerTests/special/msg_value_inheritance_2.sol +++ b/test/libsolidity/smtCheckerTests/special/msg_value_inheritance_2.sol @@ -14,5 +14,5 @@ contract C is A { // ==== // SMTEngine: all // ---- -// Warning 6328: (60-74): CHC: Assertion violation happens here.\nCounterexample:\nv = 0, x = 1\n\nTransaction trace:\nC.constructor(){ value: 1 } -// Warning 6328: (240-254): CHC: Assertion violation happens here.\nCounterexample:\nv = 1, x = 1\n\nTransaction trace:\nC.constructor(){ value: 1 } +// Warning 6328: (60-74): CHC: Assertion violation happens here.\nCounterexample:\nv = 0, x = 1\n\nTransaction trace:\nC.constructor(){ msg.value: 1 } +// Warning 6328: (240-254): CHC: Assertion violation happens here.\nCounterexample:\nv = 1, x = 1\n\nTransaction trace:\nC.constructor(){ msg.value: 1 } diff --git a/test/libsolidity/smtCheckerTests/special/msg_value_inheritance_3.sol b/test/libsolidity/smtCheckerTests/special/msg_value_inheritance_3.sol index 08457c0ec..4e1d2a99f 100644 --- a/test/libsolidity/smtCheckerTests/special/msg_value_inheritance_3.sol +++ b/test/libsolidity/smtCheckerTests/special/msg_value_inheritance_3.sol @@ -19,4 +19,4 @@ contract C is A, B { // ==== // SMTEngine: all // ---- -// Warning 6328: (60-74): CHC: Assertion violation happens here.\nCounterexample:\nx = 1\n\nTransaction trace:\nC.constructor(){ value: 1 } +// Warning 6328: (60-74): CHC: Assertion violation happens here.\nCounterexample:\nx = 1\n\nTransaction trace:\nC.constructor(){ msg.value: 1 } diff --git a/test/libsolidity/smtCheckerTests/special/msg_vars_chc_internal.sol b/test/libsolidity/smtCheckerTests/special/msg_vars_chc_internal.sol index e8190ce3a..b7984d21e 100644 --- a/test/libsolidity/smtCheckerTests/special/msg_vars_chc_internal.sol +++ b/test/libsolidity/smtCheckerTests/special/msg_vars_chc_internal.sol @@ -21,8 +21,11 @@ contract C { assert(sender == msg.sender); // should hold with CHC assert(sig == msg.sig); // should hold with CHC assert(value == msg.value); // should hold with CHC + + assert(msg.value == 10); // should fail } } // ==== // SMTEngine: chc // ---- +// Warning 6328: (621-644): CHC: Assertion violation happens here.\nCounterexample:\ndata = [0x26, 0x12, 0x1f, 0xf0], sender = 0x0, sig = 0x26121ff0, value = 0\n\nTransaction trace:\nC.constructor()\nState: data = [], sender = 0x0, sig = 0x0, value = 0\nC.f(){ msg.data: [0x26, 0x12, 0x1f, 0xf0], msg.sender: 0x0, msg.sig: 0x26121ff0, msg.value: 0 }\n C.g() -- internal call diff --git a/test/libsolidity/smtCheckerTests/special/shadowing_1.sol b/test/libsolidity/smtCheckerTests/special/shadowing_1.sol new file mode 100644 index 000000000..d54548314 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/special/shadowing_1.sol @@ -0,0 +1,24 @@ +contract C { + struct S { + uint value; + address origin; + uint number; + } + function f() public payable { + S memory msg = S(42, address(0), 666); + S memory tx = S(42, address(0), 666); + S memory block = S(42, address(0), 666); + assert(msg.value == 42); // should hold + assert(msg.value == 41); // should fail + assert(tx.origin == address(0)); // should hold + assert(block.number == 666); // should hold + } +} +// ==== +// SMTEngine: all +// SMTIgnoreCex: yes +// ---- +// Warning 2319: (108-120): This declaration shadows a builtin symbol. +// Warning 2319: (149-160): This declaration shadows a builtin symbol. +// Warning 2319: (189-203): This declaration shadows a builtin symbol. +// Warning 6328: (274-297): CHC: Assertion violation happens here. diff --git a/test/libsolidity/smtCheckerTests/special/timestamp_2.sol b/test/libsolidity/smtCheckerTests/special/timestamp_2.sol index 73af1d4da..7173185da 100644 --- a/test/libsolidity/smtCheckerTests/special/timestamp_2.sol +++ b/test/libsolidity/smtCheckerTests/special/timestamp_2.sol @@ -9,4 +9,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 4984: (107-126): CHC: Overflow (resulting value larger than 2**256 - 1) happens here.\nCounterexample:\nx = 115792089237316195423570985008687907853269984665640564039457584007913129639935\n\nTransaction trace:\nC.constructor() +// Warning 4984: (107-126): CHC: Overflow (resulting value larger than 2**256 - 1) happens here.\nCounterexample:\nx = 115792089237316195423570985008687907853269984665640564039457584007913129639935\n\nTransaction trace:\nC.constructor(){ block.timestamp: 115792089237316195423570985008687907853269984665640564039457584007913129639935 } diff --git a/test/libsolidity/smtCheckerTests/special/tx_vars_chc_internal.sol b/test/libsolidity/smtCheckerTests/special/tx_vars_chc_internal.sol index 53ce010aa..ad958fe95 100644 --- a/test/libsolidity/smtCheckerTests/special/tx_vars_chc_internal.sol +++ b/test/libsolidity/smtCheckerTests/special/tx_vars_chc_internal.sol @@ -13,8 +13,11 @@ contract C { assert(gas == tx.gasprice); // should hold with CHC assert(origin == tx.origin); // should hold with CHC + + assert(tx.origin == address(this)); // should fail } } // ==== // SMTEngine: chc // ---- +// Warning 6328: (343-377): CHC: Assertion violation happens here.\nCounterexample:\ngas = 0, origin = 0x0\n\nTransaction trace:\nC.constructor()\nState: gas = 0, origin = 0x0\nC.f(){ tx.gasprice: 0, tx.origin: 0x0 }\n C.g() -- internal call diff --git a/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_1.sol b/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_1.sol new file mode 100644 index 000000000..50260aa3d --- /dev/null +++ b/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_1.sol @@ -0,0 +1,16 @@ +interface I { + function f() external; +} + +contract C { + function g(I _i) public payable { + uint x = address(this).balance; + _i.f(); + assert(x == address(this).balance); // should fail + } +} +// ==== +// SMTEngine: all +// SMTIgnoreOS: macos +// ---- +// Warning 6328: (135-169): CHC: Assertion violation happens here.\nCounterexample:\n\n_i = 0\nx = 841\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: 0 } -- 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 new file mode 100644 index 000000000..aaddec5b5 --- /dev/null +++ b/test/libsolidity/smtCheckerTests/special/tx_vars_reentrancy_2.sol @@ -0,0 +1,16 @@ +interface I { + function f() external payable; +} + +contract C { + function g(I _i) public payable { + uint x = address(this).balance; + _i.f{ value: 100 }(); + assert(x == address(this).balance); // should fail + } +} +// ==== +// SMTEngine: all +// SMTIgnoreOS: macos +// ---- +// Warning 6328: (157-191): CHC: Assertion violation happens here.\nCounterexample:\n\n_i = 0\nx = 2537\n\nTransaction trace:\nC.constructor()\nC.g(0){ msg.value: 38 }\n _i.f{ value: 100 }() -- untrusted external call diff --git a/test/libsolidity/smtCheckerTests/typecast/address_literal.sol b/test/libsolidity/smtCheckerTests/typecast/address_literal.sol index c37c36ded..d56275fed 100644 --- a/test/libsolidity/smtCheckerTests/typecast/address_literal.sol +++ b/test/libsolidity/smtCheckerTests/typecast/address_literal.sol @@ -22,4 +22,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (454-468): CHC: Assertion violation happens here.\nCounterexample:\nx = 0\na = 0\nb = 1\nc = 0\nd = 0\ne = 305419896\n\nTransaction trace:\nC.constructor()\nState: x = 0\nC.g() +// Warning 6328: (454-468): CHC: Assertion violation happens here.\nCounterexample:\nx = 0x0\na = 0x0\nb = 0x01\nc = 0x0\nd = 0x0\ne = 0x12345678\n\nTransaction trace:\nC.constructor()\nState: x = 0x0\nC.g() diff --git a/test/libsolidity/smtCheckerTests/typecast/bytes_to_fixed_bytes_1.sol b/test/libsolidity/smtCheckerTests/typecast/bytes_to_fixed_bytes_1.sol index 6f2dd33a4..91166baa8 100644 --- a/test/libsolidity/smtCheckerTests/typecast/bytes_to_fixed_bytes_1.sol +++ b/test/libsolidity/smtCheckerTests/typecast/bytes_to_fixed_bytes_1.sol @@ -16,7 +16,7 @@ contract C { } } // ---- -// Warning 6328: (225-256): CHC: Assertion violation happens here.\nCounterexample:\n\nc = 283686952306183\nd = 0\ne = 0\ng = 0\n\nTransaction trace:\nC.constructor()\nC.f() -// Warning 6328: (352-399): CHC: Assertion violation happens here.\nCounterexample:\n\nc = 283686952306183\nd = 5233100606242806050944357496980485\ne = 0\ng = 0\n\nTransaction trace:\nC.constructor()\nC.f() -// Warning 6328: (526-589): CHC: Assertion violation happens here.\nCounterexample:\n\nc = 283686952306183\nd = 5233100606242806050944357496980485\ne = 96533667595335344310996525432040024692804347064549891\ng = 0\n\nTransaction trace:\nC.constructor()\nC.f() -// Warning 6328: (732-811): CHC: Assertion violation happens here.\nCounterexample:\n\nc = 283686952306183\nd = 5233100606242806050944357496980485\ne = 96533667595335344310996525432040024692804347064549891\ng = 1780731860627700044956966451854862080991451332659079878538166652776284161\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (225-256): CHC: Assertion violation happens here.\nCounterexample:\n\nc = 0x01020304050607\nd = 0x0\ne = 0x0\ng = 0x0\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (352-399): CHC: Assertion violation happens here.\nCounterexample:\n\nc = 0x01020304050607\nd = 0x010203040506070809000102030405\ne = 0x0\ng = 0x0\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (526-589): CHC: Assertion violation happens here.\nCounterexample:\n\nc = 0x01020304050607\nd = 0x010203040506070809000102030405\ne = 0x0102030405060708090001020304050607080900010203\ng = 0x0\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (732-811): CHC: Assertion violation happens here.\nCounterexample:\n\nc = 0x01020304050607\nd = 0x010203040506070809000102030405\ne = 0x0102030405060708090001020304050607080900010203\ng = 0x01020304050607080900010203040506070809000102030405060708090001\n\nTransaction trace:\nC.constructor()\nC.f() diff --git a/test/libsolidity/smtCheckerTests/typecast/cast_larger_3.sol b/test/libsolidity/smtCheckerTests/typecast/cast_larger_3.sol index b8a69f946..3a14cbb24 100644 --- a/test/libsolidity/smtCheckerTests/typecast/cast_larger_3.sol +++ b/test/libsolidity/smtCheckerTests/typecast/cast_larger_3.sol @@ -12,4 +12,4 @@ contract C // ==== // SMTEngine: all // ---- -// Warning 6328: (240-254): CHC: Assertion violation happens here.\nCounterexample:\n\na = 4660\nb = 305397760\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (240-254): CHC: Assertion violation happens here.\nCounterexample:\n\na = 0x1234\nb = 0x12340000\n\nTransaction trace:\nC.constructor()\nC.f() diff --git a/test/libsolidity/smtCheckerTests/typecast/implicit_cast_string_literal_byte.sol b/test/libsolidity/smtCheckerTests/typecast/implicit_cast_string_literal_byte.sol index 6acb0d16f..093a20d7f 100644 --- a/test/libsolidity/smtCheckerTests/typecast/implicit_cast_string_literal_byte.sol +++ b/test/libsolidity/smtCheckerTests/typecast/implicit_cast_string_literal_byte.sol @@ -13,4 +13,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (153-174): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 2\nb = 0\n\nTransaction trace:\nC.constructor()\nC.f()\n C.g(0) -- internal call +// Warning 6328: (153-174): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 2\nb = 0x0\n\nTransaction trace:\nC.constructor()\nC.f()\n C.g(0x0) -- internal call diff --git a/test/libsolidity/smtCheckerTests/typecast/string_literal_to_dynamic_bytes.sol b/test/libsolidity/smtCheckerTests/typecast/string_literal_to_dynamic_bytes.sol index 04d973b99..db54c9035 100644 --- a/test/libsolidity/smtCheckerTests/typecast/string_literal_to_dynamic_bytes.sol +++ b/test/libsolidity/smtCheckerTests/typecast/string_literal_to_dynamic_bytes.sol @@ -9,4 +9,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (173-207): CHC: Assertion violation happens here.\nCounterexample:\n\nb = [255, 255]\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (173-207): CHC: Assertion violation happens here.\nCounterexample:\n\nb = [0xff, 0xff]\n\nTransaction trace:\nC.constructor()\nC.f() diff --git a/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_modifier.sol b/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_modifier.sol index 4d1d832f9..c3fda61b8 100644 --- a/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_modifier.sol +++ b/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_modifier.sol @@ -9,4 +9,4 @@ contract B { // ==== // SMTEngine: all // ---- -// Warning 6328: (120-142): CHC: Assertion violation happens here.\nCounterexample:\n\na = 13564890559296822\n\nTransaction trace:\nB.constructor()\nB.f() +// Warning 6328: (120-142): CHC: Assertion violation happens here.\nCounterexample:\n\na = 0x30313233343536\n\nTransaction trace:\nB.constructor()\nB.f() diff --git a/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_return_multi.sol b/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_return_multi.sol index c869fca05..e443beb43 100644 --- a/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_return_multi.sol +++ b/test/libsolidity/smtCheckerTests/typecast/string_literal_to_fixed_bytes_return_multi.sol @@ -13,4 +13,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (410-429): CHC: Assertion violation happens here.\nCounterexample:\n\nv1 = 44048180597813453602326562734351324025098966208897425494240603688123167145984\nv2 = 6579558\n\nTransaction trace:\nC.constructor()\nC.a()\n C.f2() -- internal call\n C.h() -- internal call +// Warning 6328: (410-429): CHC: Assertion violation happens here.\nCounterexample:\n\nv1 = 0x6162630000000000000000000000000000000000000000000000000000000000\nv2 = 0x646566\n\nTransaction trace:\nC.constructor()\nC.a()\n C.f2() -- internal call\n C.h() -- internal call diff --git a/test/libsolidity/smtCheckerTests/typecast/string_to_bytes_push_1.sol b/test/libsolidity/smtCheckerTests/typecast/string_to_bytes_push_1.sol index 1b571c9f2..4910c417e 100644 --- a/test/libsolidity/smtCheckerTests/typecast/string_to_bytes_push_1.sol +++ b/test/libsolidity/smtCheckerTests/typecast/string_to_bytes_push_1.sol @@ -11,4 +11,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (132-160): CHC: Assertion violation happens here.\nCounterexample:\nx = [97, 98, 99, 97]\n\nTransaction trace:\nC.constructor()\nState: x = []\nC.s() +// Warning 6328: (132-160): CHC: Assertion violation happens here.\nCounterexample:\nx = [0x61, 0x62, 0x63, 0x61]\n\nTransaction trace:\nC.constructor()\nState: x = []\nC.s() diff --git a/test/libsolidity/smtCheckerTests/types/address_transfer.sol b/test/libsolidity/smtCheckerTests/types/address_transfer.sol index 1715a8773..654c24969 100644 --- a/test/libsolidity/smtCheckerTests/types/address_transfer.sol +++ b/test/libsolidity/smtCheckerTests/types/address_transfer.sol @@ -11,5 +11,5 @@ contract C // ==== // SMTEngine: all // ---- -// Warning 6328: (162-186): CHC: Assertion violation happens here.\nCounterexample:\n\na = 0\nx = 100\n\nTransaction trace:\nC.constructor()\nC.f(0) +// Warning 6328: (162-186): CHC: Assertion violation happens here.\nCounterexample:\n\na = 0x0\nx = 100\n\nTransaction trace:\nC.constructor()\nC.f(0x0) // Warning 1236: (98-113): BMC: Insufficient funds happens here. diff --git a/test/libsolidity/smtCheckerTests/types/address_transfer_insufficient.sol b/test/libsolidity/smtCheckerTests/types/address_transfer_insufficient.sol index 3cfaabb23..4b55c3241 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 = 8855\nb = 8855\n\nTransaction trace:\nC.constructor()\nC.f(8855, 8855) +// 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 1236: (101-116): BMC: Insufficient funds happens here. // Warning 1236: (120-136): BMC: Insufficient funds happens here. diff --git a/test/libsolidity/smtCheckerTests/types/fixed_bytes_2.sol b/test/libsolidity/smtCheckerTests/types/fixed_bytes_2.sol index cb8caa3c7..187689b88 100644 --- a/test/libsolidity/smtCheckerTests/types/fixed_bytes_2.sol +++ b/test/libsolidity/smtCheckerTests/types/fixed_bytes_2.sol @@ -12,4 +12,4 @@ contract C // ==== // SMTEngine: all // ---- -// Warning 6328: (83-97): CHC: Assertion violation happens here.\nCounterexample:\nx = 0\ny = 0\n\nTransaction trace:\nC.constructor()\nState: x = 0\nC.f(0)\n C.g() -- internal call +// Warning 6328: (83-97): CHC: Assertion violation happens here.\nCounterexample:\nx = 0x0\ny = 0x0\n\nTransaction trace:\nC.constructor()\nState: x = 0x0\nC.f(0x0)\n C.g() -- internal call diff --git a/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_4.sol b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_4.sol index ed675ce60..ae3bbf9ce 100644 --- a/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_4.sol +++ b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_4.sol @@ -12,4 +12,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (231-252): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 450552876409790643671482431940419874915447411150352389258589821042463539455\nz = 0\no = 255\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (231-252): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 0xff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff\nz = 0x0\no = 0xff\n\nTransaction trace:\nC.constructor()\nC.f() diff --git a/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_5.sol b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_5.sol index d2d4956f2..cb3cd1e0f 100644 --- a/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_5.sol +++ b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_5.sol @@ -11,6 +11,6 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (87-104): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 16909060\nb = 2\n\nTransaction trace:\nC.constructor()\nC.f() -// Warning 6328: (138-155): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 16909060\nb = 2\n\nTransaction trace:\nC.constructor()\nC.f() -// Warning 6328: (168-185): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 16909060\nb = 2\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (87-104): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 0x01020304\nb = 0x02\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (138-155): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 0x01020304\nb = 0x02\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (168-185): CHC: Assertion violation happens here.\nCounterexample:\n\nx = 0x01020304\nb = 0x02\n\nTransaction trace:\nC.constructor()\nC.f() diff --git a/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_7.sol b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_7.sol index e264cf713..b97ffbe24 100644 --- a/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_7.sol +++ b/test/libsolidity/smtCheckerTests/types/fixed_bytes_access_7.sol @@ -8,5 +8,5 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6368: (99-103): CHC: Out of bounds access happens here.\nCounterexample:\n\ni = 4\nx = 16909060\n\nTransaction trace:\nC.constructor()\nC.f(4) -// Warning 6328: (92-112): CHC: Assertion violation happens here.\nCounterexample:\n\ni = 4\nx = 16909060\n\nTransaction trace:\nC.constructor()\nC.f(4) +// Warning 6368: (99-103): CHC: Out of bounds access happens here.\nCounterexample:\n\ni = 4\nx = 0x01020304\n\nTransaction trace:\nC.constructor()\nC.f(4) +// Warning 6328: (92-112): CHC: Assertion violation happens here.\nCounterexample:\n\ni = 4\nx = 0x01020304\n\nTransaction trace:\nC.constructor()\nC.f(4) diff --git a/test/libsolidity/smtCheckerTests/types/mapping_5.sol b/test/libsolidity/smtCheckerTests/types/mapping_5.sol index 04bec4948..632191a67 100644 --- a/test/libsolidity/smtCheckerTests/types/mapping_5.sol +++ b/test/libsolidity/smtCheckerTests/types/mapping_5.sol @@ -8,4 +8,4 @@ contract C // ==== // SMTEngine: all // ---- -// Warning 6328: (92-111): CHC: Assertion violation happens here.\nCounterexample:\n\na = 0\nx = 0\n\nTransaction trace:\nC.constructor()\nC.f(0, 0) +// Warning 6328: (92-111): CHC: Assertion violation happens here.\nCounterexample:\n\na = 0x0\nx = 0\n\nTransaction trace:\nC.constructor()\nC.f(0x0, 0) diff --git a/test/libsolidity/smtCheckerTests/types/static_array_length_1.sol b/test/libsolidity/smtCheckerTests/types/static_array_length_1.sol index dd7b8abd5..e8b6f1a32 100644 --- a/test/libsolidity/smtCheckerTests/types/static_array_length_1.sol +++ b/test/libsolidity/smtCheckerTests/types/static_array_length_1.sol @@ -8,5 +8,5 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (102-122): CHC: Assertion violation happens here.\nCounterexample:\n\na = [9, 9]\n\nTransaction trace:\nC.constructor()\nC.f([9, 9]) -// Warning 6328: (141-161): CHC: Assertion violation happens here.\nCounterexample:\n\na = [9, 9]\n\nTransaction trace:\nC.constructor()\nC.f([9, 9]) +// 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]) diff --git a/test/libsolidity/smtCheckerTests/types/static_array_length_2.sol b/test/libsolidity/smtCheckerTests/types/static_array_length_2.sol index 11ba621d2..f1128583b 100644 --- a/test/libsolidity/smtCheckerTests/types/static_array_length_2.sol +++ b/test/libsolidity/smtCheckerTests/types/static_array_length_2.sol @@ -8,5 +8,5 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (113-133): CHC: Assertion violation happens here.\nCounterexample:\n\na = [0, 0]\n\nTransaction trace:\nC.constructor()\nC.f() -// Warning 6328: (152-172): CHC: Assertion violation happens here.\nCounterexample:\n\na = [0, 0]\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (113-133): CHC: Assertion violation happens here.\nCounterexample:\n\na = [0x0, 0x0]\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (152-172): CHC: Assertion violation happens here.\nCounterexample:\n\na = [0x0, 0x0]\n\nTransaction trace:\nC.constructor()\nC.f() diff --git a/test/libsolidity/smtCheckerTests/types/static_array_length_3.sol b/test/libsolidity/smtCheckerTests/types/static_array_length_3.sol index b5f47414c..691c25843 100644 --- a/test/libsolidity/smtCheckerTests/types/static_array_length_3.sol +++ b/test/libsolidity/smtCheckerTests/types/static_array_length_3.sol @@ -9,5 +9,5 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (106-126): CHC: Assertion violation happens here.\nCounterexample:\n\na = [0, 0]\n\nTransaction trace:\nC.constructor()\nC.f() -// Warning 6328: (145-165): CHC: Assertion violation happens here.\nCounterexample:\n\na = [0, 0]\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (106-126): CHC: Assertion violation happens here.\nCounterexample:\n\na = [0x0, 0x0]\n\nTransaction trace:\nC.constructor()\nC.f() +// Warning 6328: (145-165): CHC: Assertion violation happens here.\nCounterexample:\n\na = [0x0, 0x0]\n\nTransaction trace:\nC.constructor()\nC.f() diff --git a/test/libsolidity/smtCheckerTests/types/storage_value_vars_1.sol b/test/libsolidity/smtCheckerTests/types/storage_value_vars_1.sol index acdaf3ae0..e1523a380 100644 --- a/test/libsolidity/smtCheckerTests/types/storage_value_vars_1.sol +++ b/test/libsolidity/smtCheckerTests/types/storage_value_vars_1.sol @@ -20,4 +20,4 @@ contract C // ==== // SMTEngine: all // ---- -// Warning 6328: (330-389): CHC: Assertion violation happens here.\nCounterexample:\na = 512, b = false, c = 0\nx = 1\n\nTransaction trace:\nC.constructor()\nState: a = 0, b = false, c = 0\nC.f(1) +// Warning 6328: (330-389): CHC: Assertion violation happens here.\nCounterexample:\na = 0x0200, b = false, c = 0\nx = 1\n\nTransaction trace:\nC.constructor()\nState: a = 0x0, b = false, c = 0\nC.f(1) diff --git a/test/libsolidity/smtCheckerTests/types/storage_value_vars_2.sol b/test/libsolidity/smtCheckerTests/types/storage_value_vars_2.sol index 77ef26488..6bda2d66b 100644 --- a/test/libsolidity/smtCheckerTests/types/storage_value_vars_2.sol +++ b/test/libsolidity/smtCheckerTests/types/storage_value_vars_2.sol @@ -10,4 +10,4 @@ contract C // ==== // SMTEngine: all // ---- -// Warning 6328: (91-104): CHC: Assertion violation happens here.\nCounterexample:\na = 0, b = false, c = 0\n\nTransaction trace:\nC.constructor()\nState: a = 0, b = false, c = 0\nC.f() +// Warning 6328: (91-104): CHC: Assertion violation happens here.\nCounterexample:\na = 0x0, b = false, c = 0\n\nTransaction trace:\nC.constructor()\nState: a = 0x0, b = false, c = 0\nC.f() diff --git a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_1.sol b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_1.sol index 8015d2a1e..c568b2267 100644 --- a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_1.sol +++ b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_1.sol @@ -10,4 +10,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (142-157): CHC: Assertion violation happens here.\nCounterexample:\n\n_x = 52647538817385212172903286807934654968315727694643370704309751478220717293568\ny = 52647538817385212172903286807934654968315727694643370704309751478220717293568\nz = 154717211199090701642289212291190620160\n\nTransaction trace:\nC.constructor()\nC.f(52647538817385212172903286807934654968315727694643370704309751478220717293568) +// Warning 6328: (142-157): CHC: Assertion violation happens here.\nCounterexample:\n\n_x = 0x7465737400000000000000000000000000000000000000000000000000000000\ny = 0x7465737400000000000000000000000000000000000000000000000000000000\nz = 0x746573747a0000000000000000000000\n\nTransaction trace:\nC.constructor()\nC.f(0x7465737400000000000000000000000000000000000000000000000000000000) diff --git a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_2.sol b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_2.sol index c534ce93b..fc68b7958 100644 --- a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_2.sol +++ b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_2.sol @@ -9,4 +9,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (143-158): CHC: Assertion violation happens here.\nCounterexample:\n\n_x = 52647538817385212172903286807934654968315727694643370704309751478220717293568\ny = 52647538817385212172903286807934654968315727694643370704309751478220717293568\nz = 154717211199090701642289212291190620160\n\nTransaction trace:\nC.constructor()\nC.f(52647538817385212172903286807934654968315727694643370704309751478220717293568) +// Warning 6328: (143-158): CHC: Assertion violation happens here.\nCounterexample:\n\n_x = 0x7465737400000000000000000000000000000000000000000000000000000000\ny = 0x7465737400000000000000000000000000000000000000000000000000000000\nz = 0x746573747a0000000000000000000000\n\nTransaction trace:\nC.constructor()\nC.f(0x7465737400000000000000000000000000000000000000000000000000000000) diff --git a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_3.sol b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_3.sol index b6fe29658..7219e15bd 100644 --- a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_3.sol +++ b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_3.sol @@ -11,4 +11,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (153-168): CHC: Assertion violation happens here.\nCounterexample:\n\n_x = 52647538817385212172903286807934654968315727694643370704309751478220717293568\ny = 52647538817385212172903286807934654968315727694643370704309751478220717293568\nz = 154717211199090701642289212291190620160\n\nTransaction trace:\nC.constructor()\nC.f(52647538817385212172903286807934654968315727694643370704309751478220717293568) +// Warning 6328: (153-168): CHC: Assertion violation happens here.\nCounterexample:\n\n_x = 0x7465737400000000000000000000000000000000000000000000000000000000\ny = 0x7465737400000000000000000000000000000000000000000000000000000000\nz = 0x746573747a0000000000000000000000\n\nTransaction trace:\nC.constructor()\nC.f(0x7465737400000000000000000000000000000000000000000000000000000000) diff --git a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_4.sol b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_4.sol index 8514d785d..954aee7f4 100644 --- a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_4.sol +++ b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_4.sol @@ -15,4 +15,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (228-243): CHC: Assertion violation happens here.\nCounterexample:\n\n_x = 52647538817385212172903286807934654968315727694643370704309751478220717293568\ny = 52647538817385212172903286807934654968315727694643370704309751478220717293568\nz = 154717211199090701642289212291190620160\n\nTransaction trace:\nC.constructor()\nC.f(52647538817385212172903286807934654968315727694643370704309751478220717293568)\n C.g() -- internal call +// Warning 6328: (228-243): CHC: Assertion violation happens here.\nCounterexample:\n\n_x = 0x7465737400000000000000000000000000000000000000000000000000000000\ny = 0x7465737400000000000000000000000000000000000000000000000000000000\nz = 0x746573747a0000000000000000000000\n\nTransaction trace:\nC.constructor()\nC.f(0x7465737400000000000000000000000000000000000000000000000000000000)\n C.g() -- internal call diff --git a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_5.sol b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_5.sol index 9586b7b3e..71e331122 100644 --- a/test/libsolidity/smtCheckerTests/types/string_literal_assignment_5.sol +++ b/test/libsolidity/smtCheckerTests/types/string_literal_assignment_5.sol @@ -13,4 +13,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (218-233): CHC: Assertion violation happens here.\nCounterexample:\n\n_x = 52647538817385212172903286807934654968315727694643370704309751478220717293568\ny = 52647538817385212172903286807934654968315727694643370704309751478220717293568\nz = 154717211199090701642289212291190620160\n\nTransaction trace:\nC.constructor()\nC.f(52647538817385212172903286807934654968315727694643370704309751478220717293568)\n C.g() -- internal call +// Warning 6328: (218-233): CHC: Assertion violation happens here.\nCounterexample:\n\n_x = 0x7465737400000000000000000000000000000000000000000000000000000000\ny = 0x7465737400000000000000000000000000000000000000000000000000000000\nz = 0x746573747a0000000000000000000000\n\nTransaction trace:\nC.constructor()\nC.f(0x7465737400000000000000000000000000000000000000000000000000000000)\n C.g() -- internal call diff --git a/test/libsolidity/smtCheckerTests/types/string_literal_comparison_1.sol b/test/libsolidity/smtCheckerTests/types/string_literal_comparison_1.sol index 72c4b500d..3c5742e65 100644 --- a/test/libsolidity/smtCheckerTests/types/string_literal_comparison_1.sol +++ b/test/libsolidity/smtCheckerTests/types/string_literal_comparison_1.sol @@ -10,4 +10,4 @@ contract C { // ==== // SMTEngine: all // ---- -// Warning 6328: (137-157): CHC: Assertion violation happens here.\nCounterexample:\n\n_x = 52647538817385212172903286807934654968315727694643370704309751478220717293568\ny = 52647538817385212172903286807934654968315727694643370704309751478220717293568\nz = 52647538817385212172903286807934654968315727694643370704309751478220717293568\n\nTransaction trace:\nC.constructor()\nC.f(52647538817385212172903286807934654968315727694643370704309751478220717293568) +// Warning 6328: (137-157): CHC: Assertion violation happens here.\nCounterexample:\n\n_x = 0x7465737400000000000000000000000000000000000000000000000000000000\ny = 0x7465737400000000000000000000000000000000000000000000000000000000\nz = 0x7465737400000000000000000000000000000000000000000000000000000000\n\nTransaction trace:\nC.constructor()\nC.f(0x7465737400000000000000000000000000000000000000000000000000000000) diff --git a/test/libsolidity/smtCheckerTests/unchecked/check_var_init.sol b/test/libsolidity/smtCheckerTests/unchecked/check_var_init.sol index 805409c01..b7d19c0bd 100644 --- a/test/libsolidity/smtCheckerTests/unchecked/check_var_init.sol +++ b/test/libsolidity/smtCheckerTests/unchecked/check_var_init.sol @@ -16,5 +16,5 @@ contract D { // ==== // SMTEngine: all // ---- -// Warning 3944: (33-47): CHC: Underflow (resulting value less than 0) happens here.\nCounterexample:\nx = 0\n\nTransaction trace:\nC.constructor() +// Warning 3944: (33-47): CHC: Underflow (resulting value less than 0) happens here.\nCounterexample:\nx = 0\n\nTransaction trace:\nC.constructor(){ msg.value: 0 } // Warning 3944: (160-174): CHC: Underflow (resulting value less than 0) happens here.\nCounterexample:\n\n\nTransaction trace:\nD.constructor()\nD.f()\n D.h() -- internal call diff --git a/test/libsolidity/smtCheckerTests/userTypes/multisource.sol b/test/libsolidity/smtCheckerTests/userTypes/multisource.sol index fef83a8ee..23fbef98a 100644 --- a/test/libsolidity/smtCheckerTests/userTypes/multisource.sol +++ b/test/libsolidity/smtCheckerTests/userTypes/multisource.sol @@ -18,4 +18,4 @@ contract A { // SMTEngine: all // ---- // Warning 6328: (B:296-332): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nA.constructor()\nA.g()\n A.f(5) -- internal call\n A.f(5) -- internal call -// Warning 6328: (B:409-463): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nA.constructor()\nA.g()\n A.f(5) -- internal call\n A.f(5) -- internal call\n A.f(5) -- internal call\n A.f(5) -- internal call +// Warning 6328: (B:409-463): CHC: Assertion violation happens here.\nCounterexample:\n\n\nTransaction trace:\nA.constructor()\nA.g()\n A.f(5) -- internal call\n A.f(5) -- internal call\n A.f(0x05) -- internal call\n A.f(0x05) -- internal call From 020ecc2131874b06883c4f250ce1f0b78fee235d Mon Sep 17 00:00:00 2001 From: TerranCivilian <63529094+TerranCivilian@users.noreply.github.com> Date: Sat, 3 Jul 2021 13:30:44 -0400 Subject: [PATCH 232/232] Preserve original newlines in solidity::util::readUntilEnd() --- Changelog.md | 1 + libsolutil/CommonIO.cpp | 13 +++---------- test/libsolutil/CommonIO.cpp | 24 ++++++++++++++++++++++++ test/solc/CommandLineInterface.cpp | 4 ++-- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/Changelog.md b/Changelog.md index 1b7e87642..32a5dbe5c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -9,6 +9,7 @@ Compiler Features: Bugfixes: + * Commandline Interface: Fix extra newline character being appended to sources passed through standard input, affecting their hashes. * SMTChecker: Fix internal error in magic type access (``block``, ``msg``, ``tx``). diff --git a/libsolutil/CommonIO.cpp b/libsolutil/CommonIO.cpp index 30552b6ad..9da5b2422 100644 --- a/libsolutil/CommonIO.cpp +++ b/libsolutil/CommonIO.cpp @@ -74,16 +74,9 @@ string solidity::util::readFileAsString(boost::filesystem::path const& _file) string solidity::util::readUntilEnd(istream& _stdin) { - string ret; - while (!_stdin.eof()) - { - string tmp; - // NOTE: this will read until EOF or NL - getline(_stdin, tmp); - ret.append(tmp); - ret.append("\n"); - } - return ret; + ostringstream ss; + ss << _stdin.rdbuf(); + return ss.str(); } #if defined(_WIN32) diff --git a/test/libsolutil/CommonIO.cpp b/test/libsolutil/CommonIO.cpp index 12b99df7b..ce1a24a41 100644 --- a/test/libsolutil/CommonIO.cpp +++ b/test/libsolutil/CommonIO.cpp @@ -66,6 +66,30 @@ BOOST_AUTO_TEST_CASE(readFileAsString_symlink) BOOST_TEST(readFileAsString(tempDir.path() / "symlink.txt") == "ABC\ndef\n"); } +BOOST_AUTO_TEST_CASE(readUntilEnd_no_ending_newline) +{ + istringstream inputStream("ABC\ndef"); + BOOST_TEST(readUntilEnd(inputStream) == "ABC\ndef"); +} + +BOOST_AUTO_TEST_CASE(readUntilEnd_with_ending_newline) +{ + istringstream inputStream("ABC\ndef\n"); + BOOST_TEST(readUntilEnd(inputStream) == "ABC\ndef\n"); +} + +BOOST_AUTO_TEST_CASE(readUntilEnd_cr_lf_newline) +{ + istringstream inputStream("ABC\r\ndef"); + BOOST_TEST(readUntilEnd(inputStream) == "ABC\r\ndef"); +} + +BOOST_AUTO_TEST_CASE(readUntilEnd_empty) +{ + istringstream inputStream(""); + BOOST_TEST(readUntilEnd(inputStream) == ""); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace solidity::util::test diff --git a/test/solc/CommandLineInterface.cpp b/test/solc/CommandLineInterface.cpp index 126a1cd09..3d1fce7d2 100644 --- a/test/solc/CommandLineInterface.cpp +++ b/test/solc/CommandLineInterface.cpp @@ -153,7 +153,7 @@ BOOST_AUTO_TEST_CASE(cli_input) {"a", "b", "c/d/e/"}, }; map expectedSources = { - {"", "\n"}, + {"", ""}, {(expectedDir1 / "input1.sol").generic_string(), ""}, {(expectedDir2 / "input2.sol").generic_string(), ""}, }; @@ -854,7 +854,7 @@ BOOST_AUTO_TEST_CASE(cli_paths_to_source_unit_names_base_path_and_stdin) expectedOptions.modelChecker.initialize = true; map expectedSources = { - {"", "\n"}, + {"", ""}, }; FileReader::FileSystemPathSet expectedAllowedDirectories = {};