Merge branch 'develop' of github.com:tfire/solidity into fix/remove-namespace-ast-annotations

This commit is contained in:
Tyler
2022-03-09 18:55:22 -05:00
119 changed files with 1744 additions and 253 deletions
+2
View File
@@ -83,6 +83,8 @@ set(libsolidity_sources
libsolidity/InlineAssembly.cpp
libsolidity/LibSolc.cpp
libsolidity/Metadata.cpp
libsolidity/MemoryGuardTest.cpp
libsolidity/MemoryGuardTest.h
libsolidity/SemanticTest.cpp
libsolidity/SemanticTest.h
libsolidity/SemVerMatcher.cpp
+7 -6
View File
@@ -29,7 +29,6 @@
using namespace std;
using namespace solidity;
using namespace solidity::util;
using namespace solidity::util::formatting;
using namespace solidity::langutil;
using namespace solidity::frontend;
@@ -43,10 +42,11 @@ namespace
int parseUnsignedInteger(string::iterator& _it, string::iterator _end)
{
if (_it == _end || !isdigit(*_it))
auto isDigit = [](char _c) -> bool {return isdigit(_c, std::locale::classic());};
if (_it == _end || !isDigit(*_it))
BOOST_THROW_EXCEPTION(runtime_error("Invalid test expectation. Source location expected."));
int result = 0;
while (_it != _end && isdigit(*_it))
while (_it != _end && isDigit(*_it))
{
result *= 10;
result += *_it - '0';
@@ -195,6 +195,7 @@ string CommonSyntaxTest::errorMessage(Exception const& _e)
vector<SyntaxTestError> CommonSyntaxTest::parseExpectations(istream& _stream)
{
auto isDigit = [](char _c) -> bool {return isdigit(_c, std::locale::classic());};
vector<SyntaxTestError> expectations;
string line;
while (getline(_stream, line))
@@ -207,14 +208,14 @@ vector<SyntaxTestError> CommonSyntaxTest::parseExpectations(istream& _stream)
if (it == line.end()) continue;
auto typeBegin = it;
while (it != line.end() && isalpha(*it))
while (it != line.end() && isalpha(*it, locale::classic()))
++it;
string errorType(typeBegin, it);
skipWhitespace(it, line.end());
optional<ErrorId> errorId;
if (it != line.end() && isdigit(*it))
if (it != line.end() && isDigit(*it))
errorId = ErrorId{static_cast<unsigned long long>(parseUnsignedInteger(it, line.end()))};
expect(it, line.end(), ':');
@@ -227,7 +228,7 @@ vector<SyntaxTestError> CommonSyntaxTest::parseExpectations(istream& _stream)
if (it != line.end() && *it == '(')
{
++it;
if (it != line.end() && !isdigit(*it))
if (it != line.end() && !isDigit(*it))
{
auto sourceNameStart = it;
while (it != line.end() && *it != ':')
+2
View File
@@ -22,6 +22,7 @@
#include <test/libsolidity/ABIJsonTest.h>
#include <test/libsolidity/ASTJSONTest.h>
#include <test/libsolidity/GasTest.h>
#include <test/libsolidity/MemoryGuardTest.h>
#include <test/libsolidity/SyntaxTest.h>
#include <test/libsolidity/SemanticTest.h>
#include <test/libsolidity/SMTCheckerTest.h>
@@ -74,6 +75,7 @@ Testsuite const g_interactiveTestsuites[] = {
{"JSON ABI", "libsolidity", "ABIJson", false, false, &ABIJsonTest::create},
{"SMT Checker", "libsolidity", "smtCheckerTests", true, false, &SMTCheckerTest::create},
{"Gas Estimates", "libsolidity", "gasTests", false, false, &GasTest::create},
{"Memory Guard Tests", "libsolidity", "memoryGuardTests", false, false, &MemoryGuardTest::create},
{"Ewasm Translation", "libyul", "ewasmTranslationTests", false, false, &yul::test::EwasmTranslationTest::create}
};
+1 -1
View File
@@ -118,7 +118,7 @@ EVMVersionRestrictedTestCase::EVMVersionRestrictedTestCase(string const& _filena
string comparator;
size_t versionBegin = 0;
for (auto character: versionString)
if (!isalpha(character))
if (!isalpha(character, locale::classic()))
{
comparator += character;
versionBegin++;
+1 -1
View File
@@ -90,7 +90,7 @@ protected:
template<typename IteratorType>
static void skipWhitespace(IteratorType& _it, IteratorType _end)
{
while (_it != _end && isspace(*_it))
while (_it != _end && std::isspace<char>(*_it, std::locale::classic()))
++_it;
}
@@ -11,14 +11,15 @@ object "C_12" {
code {
{
/// @src 0:61:418 "contract C {..."
mstore(64, 128)
let _1 := memoryguard(0x80)
mstore(64, _1)
if callvalue() { revert(0, 0) }
/// @src 0:103:238 "assembly {..."
sstore(0, shl(180, 1))
/// @src 0:61:418 "contract C {..."
let _1 := datasize("C_12_deployed")
codecopy(128, dataoffset("C_12_deployed"), _1)
return(128, _1)
let _2 := datasize("C_12_deployed")
codecopy(_1, dataoffset("C_12_deployed"), _2)
return(_1, _2)
}
}
/// @use-src 0:"constant_optimizer_yul/input.sol"
@@ -26,7 +27,7 @@ object "C_12" {
code {
{
/// @src 0:61:418 "contract C {..."
mstore(64, 128)
mstore(64, memoryguard(0x80))
if callvalue() { revert(0, 0) }
/// @src 0:279:410 "assembly {..."
sstore(0, 0x1000000000000000000000000000000000000000000000)
@@ -3,6 +3,6 @@ pragma solidity >=0.0.0;
pragma abicoder v2;
contract D {
constructor() { assembly {}}
constructor() { assembly { mstore(0,0) } }
function f() public pure {}
}
@@ -10,9 +10,12 @@ Optimized IR:
object "D_12" {
code {
{
/// @src 0:82:161 "contract D {..."
/// @src 0:82:175 "contract D {..."
mstore(64, 128)
if callvalue() { revert(0, 0) }
/// @src 0:115:139 "assembly { mstore(0,0) }"
mstore(0, 0)
/// @src 0:82:175 "contract D {..."
let _1 := datasize("D_12_deployed")
codecopy(128, dataoffset("D_12_deployed"), _1)
return(128, _1)
@@ -22,7 +25,7 @@ object "D_12" {
object "D_12_deployed" {
code {
{
/// @src 0:82:161 "contract D {..."
/// @src 0:82:175 "contract D {..."
let _1 := memoryguard(0x80)
mstore(64, _1)
if iszero(lt(calldatasize(), 4))
@@ -4,6 +4,6 @@ pragma abicoder v2;
contract D {
function f() public pure {
assembly {}
assembly { mstore(0,0) }
}
}
@@ -10,7 +10,7 @@ Optimized IR:
object "D_8" {
code {
{
/// @src 0:82:153 "contract D {..."
/// @src 0:82:166 "contract D {..."
let _1 := memoryguard(0x80)
mstore(64, _1)
if callvalue() { revert(0, 0) }
@@ -23,7 +23,7 @@ object "D_8" {
object "D_8_deployed" {
code {
{
/// @src 0:82:153 "contract D {..."
/// @src 0:82:166 "contract D {..."
mstore(64, 128)
if iszero(lt(calldatasize(), 4))
{
@@ -32,6 +32,8 @@ object "D_8" {
{
if callvalue() { revert(_1, _1) }
if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) }
/// @src 0:134:158 "assembly { mstore(0,0) }"
mstore(/** @src 0:82:166 "contract D {..." */ _1, _1)
return(128, _1)
}
}
@@ -0,0 +1 @@
--experimental-via-ir --optimize --asm
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >0.0.0;
contract C {
constructor(uint x) {
// In earlier versions of the compiler, the resulting assembly pushed the constant
// 0xFFFFFFFFFFFFFFFF42 directly in the subassembly of D, while it was optimized to
// ``sub(shl(0x48, 0x01), 0xbe)`` when C was compiled in isolation.
// Now the assembly is expected to contain two instances of ``sub(shl(0x48, 0x01), 0xbe)``,
// one in the creation code of ``C`` directly, one in a subassembly of ``D``.
// The constant 0xFFFFFFFFFFFFFFFF42 should not occur in the assembly output at all.
if (x == 0xFFFFFFFFFFFFFFFF42)
revert();
}
}
contract D {
function f() public pure returns (bytes memory) {
return type(C).creationCode;
}
}
@@ -0,0 +1,379 @@
======= viair_subobject_optimization/input.sol:C =======
EVM assembly:
/* "viair_subobject_optimization/input.sol":61:668 contract C {... */
0x80
dup1
0x40
mstore
jumpi(tag_6, callvalue)
0x1f
bytecodeSize
codesize
dup2
swap1
sub
swap2
dup3
add
not(0x1f)
and
dup4
add
swap2
sub(shl(0x40, 0x01), 0x01)
dup4
gt
dup5
dup5
lt
or
tag_4
jumpi
dup1
dup5
swap3
0x20
swap5
0x40
mstore
dup4
codecopy
dup2
add
sub
slt
tag_6
jumpi
tag_8
swap1
mload
tag_1
jump // in
tag_8:
mload(0x40)
dataSize(sub_0)
swap1
dup2
dataOffset(sub_0)
dup3
codecopy
return
tag_6:
pop
0x00
dup1
revert
tag_4:
pop
pop
pop
pop
mstore(0x00, shl(0xe0, 0x4e487b71))
mstore(0x04, 0x41)
revert(0x00, 0x24)
/* "viair_subobject_optimization/input.sol":76:666 constructor(uint x) {... */
tag_1:
sub(shl(0x48, 0x01), 0xbe)
/* "viair_subobject_optimization/input.sol":620:645 x == 0xFFFFFFFFFFFFFFFF42 */
eq
/* "viair_subobject_optimization/input.sol":616:661 if (x == 0xFFFFFFFFFFFFFFFF42)... */
tag_6
jumpi
/* "viair_subobject_optimization/input.sol":76:666 constructor(uint x) {... */
jump // out
stop
sub_0: assembly {
/* "viair_subobject_optimization/input.sol":61:668 contract C {... */
mstore(0x40, 0x80)
0x00
dup1
revert
auxdata: <AUXDATA REMOVED>
}
======= viair_subobject_optimization/input.sol:D =======
EVM assembly:
/* "viair_subobject_optimization/input.sol":669:772 contract D {... */
0x80
dup1
0x40
mstore
jumpi(tag_1, callvalue)
dataSize(sub_0)
swap1
dup2
dataOffset(sub_0)
dup3
codecopy
return
tag_1:
pop
0x00
dup1
revert
stop
sub_0: assembly {
/* "viair_subobject_optimization/input.sol":669:772 contract D {... */
0x80
dup1
0x40
mstore
jumpi(tag_2, iszero(lt(calldatasize, 0x04)))
tag_3:
pop
0x00
dup1
revert
tag_2:
0x00
swap1
dup2
calldataload
0xe0
shr
0x26121ff0
eq
tag_4
jumpi
pop
jump(tag_3)
tag_4:
jumpi(tag_8, callvalue)
dup2
add(calldatasize, not(0x03))
slt
tag_8
jumpi
/* "viair_subobject_optimization/input.sol":745:765 type(C).creationCode */
dataSize(sub_0)
/* "viair_subobject_optimization/input.sol":669:772 contract D {... */
0x3f
dup2
add
not(0x1f)
and
dup3
add
0xffffffffffffffff
dup2
gt
dup4
dup3
lt
or
tag_10
jumpi
tag_12
swap4
pop
0x40
mstore
/* "viair_subobject_optimization/input.sol":745:765 type(C).creationCode */
dup1
dup3
mstore
dataOffset(sub_0)
0x20
dup4
add
codecopy
/* "viair_subobject_optimization/input.sol":669:772 contract D {... */
mload(0x40)
swap2
dup3
swap2
dup3
tag_1
jump // in
tag_12:
sub
swap1
return
tag_10:
pop
pop
shl(0xe0, 0x4e487b71)
dup3
mstore
pop
mstore(0x04, 0x41)
0x24
swap1
revert
tag_8:
pop
dup1
revert
tag_1:
swap2
swap1
swap2
0x20
dup1
dup3
mstore
dup4
mload
swap1
dup2
dup2
dup5
add
mstore
0x00
swap5
tag_13:
dup3
dup7
lt
tag_14
jumpi
pop
pop
dup1
0x40
swap4
swap5
gt
tag_16
jumpi
tag_17:
0x1f
add
not(0x1f)
and
add
add
swap1
jump // out
tag_16:
0x00
dup4
dup3
dup5
add
add
mstore
jump(tag_17)
tag_14:
dup6
dup2
add
dup3
add
mload
dup5
dup8
add
0x40
add
mstore
swap5
dup2
add
swap5
jump(tag_13)
stop
sub_0: assembly {
/* "viair_subobject_optimization/input.sol":61:668 contract C {... */
0x80
dup1
0x40
mstore
jumpi(tag_6, callvalue)
0x1f
bytecodeSize
codesize
dup2
swap1
sub
swap2
dup3
add
not(0x1f)
and
dup4
add
swap2
sub(shl(0x40, 0x01), 0x01)
dup4
gt
dup5
dup5
lt
or
tag_4
jumpi
dup1
dup5
swap3
0x20
swap5
0x40
mstore
dup4
codecopy
dup2
add
sub
slt
tag_6
jumpi
tag_8
swap1
mload
tag_1
jump // in
tag_8:
mload(0x40)
dataSize(sub_0)
swap1
dup2
dataOffset(sub_0)
dup3
codecopy
return
tag_6:
pop
0x00
dup1
revert
tag_4:
pop
pop
pop
pop
mstore(0x00, shl(0xe0, 0x4e487b71))
mstore(0x04, 0x41)
revert(0x00, 0x24)
/* "viair_subobject_optimization/input.sol":76:666 constructor(uint x) {... */
tag_1:
sub(shl(0x48, 0x01), 0xbe)
/* "viair_subobject_optimization/input.sol":620:645 x == 0xFFFFFFFFFFFFFFFF42 */
eq
/* "viair_subobject_optimization/input.sol":616:661 if (x == 0xFFFFFFFFFFFFFFFF42)... */
tag_6
jumpi
/* "viair_subobject_optimization/input.sol":76:666 constructor(uint x) {... */
jump // out
stop
sub_0: assembly {
/* "viair_subobject_optimization/input.sol":61:668 contract C {... */
mstore(0x40, 0x80)
0x00
dup1
revert
auxdata: <AUXDATA REMOVED>
}
}
auxdata: <AUXDATA REMOVED>
}
@@ -1,10 +1,10 @@
object "RunsTest1" {
code {
// Deploy the contract
datacopy(0, dataoffset("Runtime"), datasize("Runtime"))
return(0, datasize("Runtime"))
datacopy(0, dataoffset("Runtime_deployed"), datasize("Runtime_deployed"))
return(0, datasize("Runtime_deployed"))
}
object "Runtime" {
object "Runtime_deployed" {
code {
let funcSel := shl(224, 0xabc12345)
sstore(0, funcSel)
+11 -11
View File
@@ -5,12 +5,12 @@ Pretty printed source:
object "RunsTest1" {
code {
{
let _1 := datasize("Runtime")
datacopy(0, dataoffset("Runtime"), _1)
let _1 := datasize("Runtime_deployed")
datacopy(0, dataoffset("Runtime_deployed"), _1)
return(0, _1)
}
}
object "Runtime" {
object "Runtime_deployed" {
code {
{
sstore(0, 0xabc1234500000000000000000000000000000000000000000000000000000000)
@@ -24,28 +24,28 @@ Binary representation:
602580600c6000396000f3fe7fabc123450000000000000000000000000000000000000000000000000000000060005500
Text representation:
/* "yul_optimize_runs/input.yul":106:125 */
/* "yul_optimize_runs/input.yul":115:143 */
dataSize(sub_0)
/* "yul_optimize_runs/input.yul":83:104 */
/* "yul_optimize_runs/input.yul":83:113 */
dup1
dataOffset(sub_0)
/* "yul_optimize_runs/input.yul":80:81 */
0x00
/* "yul_optimize_runs/input.yul":71:126 */
/* "yul_optimize_runs/input.yul":71:144 */
codecopy
/* "yul_optimize_runs/input.yul":80:81 */
0x00
/* "yul_optimize_runs/input.yul":135:165 */
/* "yul_optimize_runs/input.yul":153:192 */
return
stop
sub_0: assembly {
/* "yul_optimize_runs/input.yul":237:257 */
/* "yul_optimize_runs/input.yul":273:293 */
0xabc1234500000000000000000000000000000000000000000000000000000000
/* "yul_optimize_runs/input.yul":277:278 */
/* "yul_optimize_runs/input.yul":313:314 */
0x00
/* "yul_optimize_runs/input.yul":270:288 */
/* "yul_optimize_runs/input.yul":306:324 */
sstore
/* "yul_optimize_runs/input.yul":208:298 */
/* "yul_optimize_runs/input.yul":244:334 */
stop
}
+6
View File
@@ -89,6 +89,12 @@ function elementfi_test
# TODO: Remove when https://github.com/element-fi/elf-contracts/issues/243 is fixed.
sed -i 's|^\s*require(_expiration - block\.timestamp < _unitSeconds);\s*$||g' contracts/ConvergentCurvePool.sol
# This test file is very flaky. There's one particular cases that fails randomly (see
# https://github.com/element-fi/elf-contracts/issues/240) but some others also depends on an external
# service which makes tests time out when that service is down.
# "ProviderError: Too Many Requests error received from eth-mainnet.alchemyapi.io"
rm test/mockERC20YearnVaultTest.ts
# Several tests fail unless we use the exact versions hard-coded in package-lock.json
#neutralize_package_lock
+3 -1
View File
@@ -48,7 +48,7 @@ function ens_test
"${compile_only_presets[@]}"
#ir-no-optimize # Compilation fails with "YulException: Variable var__945 is 1 slot(s) too deep inside the stack."
#ir-optimize-evm-only # Compilation fails with "YulException: Variable var__945 is 1 slot(s) too deep inside the stack."
#ir-optimize-evm+yul # Compilation fails with "YulException: Variable _5 is 1 too deep in the stack [ _5 usr$i usr$h _7 usr$scratch usr$k usr$f _4 usr$len usr$j_2 RET _2 _1 var_data_mpos usr$totallen usr$x _12 ]"
ir-optimize-evm+yul # Needs memory-safe inline assembly patch
legacy-optimize-evm-only
legacy-optimize-evm+yul
)
@@ -68,6 +68,8 @@ function ens_test
replace_version_pragmas
neutralize_packaged_contracts
find . -name "*.sol" -exec sed -i -e 's/^\(\s*\)\(assembly\)/\1\/\/\/ @solidity memory-safe-assembly\n\1\2/' '{}' \;
for preset in $SELECTED_PRESETS; do
hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn
store_benchmark_report hardhat ens "$repo" "$preset"
+2 -1
View File
@@ -56,7 +56,7 @@ function trident_test
"${compile_only_presets[@]}"
#ir-no-optimize # Compilation fails with: "YulException: Variable var_amount_165 is 9 slot(s) too deep inside the stack."
#ir-optimize-evm-only # Compilation fails with: "YulException: Variable var_amount_165 is 9 slot(s) too deep inside the stack."
#ir-optimize-evm+yul # Compilation fails with: "YulException: Cannot swap Variable var_nearestTick with Variable _4: too deep in the stack by 4 slots"
ir-optimize-evm+yul # Needs memory-safe inline assembly patch
legacy-no-optimize
legacy-optimize-evm-only
legacy-optimize-evm+yul
@@ -87,6 +87,7 @@ function trident_test
sed -i 's|uint32(-1)|type(uint32).max|g' contracts/flat/BentoBoxV1Flat.sol
sed -i 's|IERC20(0)|IERC20(address(0))|g' contracts/flat/BentoBoxV1Flat.sol
sed -i 's|IStrategy(0)|IStrategy(address(0))|g' contracts/flat/BentoBoxV1Flat.sol
find contracts -name "*.sol" -exec sed -i -e 's/^\(\s*\)\(assembly\)/\1\/\/\/ @solidity memory-safe-assembly\n\1\2/' '{}' \;
# @sushiswap/core package contains contracts that get built with 0.6.12 and fail our compiler
# version check. It's not used by tests so we can remove it.
+9 -9
View File
@@ -58,11 +58,11 @@ BOOST_AUTO_TEST_CASE(all_assembly_items)
{ "root.asm", 0 },
{ "sub.asm", 1 }
};
Assembly _assembly;
Assembly _assembly{false, {}};
auto root_asm = make_shared<string>("root.asm");
_assembly.setSourceLocation({1, 3, root_asm});
Assembly _subAsm;
Assembly _subAsm{false, {}};
auto sub_asm = make_shared<string>("sub.asm");
_subAsm.setSourceLocation({6, 8, sub_asm});
// PushImmutable
@@ -197,7 +197,7 @@ BOOST_AUTO_TEST_CASE(immutables_and_its_source_maps)
{ *subName, 1 }
};
auto subAsm = make_shared<Assembly>();
auto subAsm = make_shared<Assembly>(false, string{});
for (char i = 0; i < numImmutables; ++i)
{
for (int r = 0; r < numActualRefs; ++r)
@@ -207,7 +207,7 @@ BOOST_AUTO_TEST_CASE(immutables_and_its_source_maps)
}
}
Assembly assembly;
Assembly assembly{true, {}};
for (char i = 1; i <= numImmutables; ++i)
{
assembly.setSourceLocation({10*i, 10*i + 3+i, assemblyName});
@@ -256,11 +256,11 @@ BOOST_AUTO_TEST_CASE(immutable)
{ "root.asm", 0 },
{ "sub.asm", 1 }
};
Assembly _assembly;
Assembly _assembly{true, {}};
auto root_asm = make_shared<string>("root.asm");
_assembly.setSourceLocation({1, 3, root_asm});
Assembly _subAsm;
Assembly _subAsm{false, {}};
auto sub_asm = make_shared<string>("sub.asm");
_subAsm.setSourceLocation({6, 8, sub_asm});
_subAsm.appendImmutable("someImmutable");
@@ -349,10 +349,10 @@ BOOST_AUTO_TEST_CASE(immutable)
BOOST_AUTO_TEST_CASE(subobject_encode_decode)
{
Assembly assembly;
Assembly assembly{true, {}};
shared_ptr<Assembly> subAsmPtr = make_shared<Assembly>();
shared_ptr<Assembly> subSubAsmPtr = make_shared<Assembly>();
shared_ptr<Assembly> subAsmPtr = make_shared<Assembly>(false, string{});
shared_ptr<Assembly> subSubAsmPtr = make_shared<Assembly>(false, string{});
assembly.appendSubroutine(subAsmPtr);
subAsmPtr->appendSubroutine(subSubAsmPtr);
+3 -4
View File
@@ -1250,8 +1250,8 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies)
// tag unifications (due to block deduplication) is also
// visible at the super-assembly.
Assembly main;
AssemblyPointer sub = make_shared<Assembly>();
Assembly main{false, {}};
AssemblyPointer sub = make_shared<Assembly>(true, string{});
sub->append(u256(1));
auto t1 = sub->newTag();
@@ -1278,7 +1278,6 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies)
main.append(u256(8));
Assembly::OptimiserSettings settings;
settings.isCreation = false;
settings.runInliner = false;
settings.runJumpdestRemover = true;
settings.runPeephole = true;
@@ -1287,7 +1286,7 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies)
settings.runConstantOptimiser = true;
settings.evmVersion = solidity::test::CommonOptions::get().evmVersion();
settings.expectedExecutionsPerDeployment = OptimiserSettings{}.expectedExecutionsPerDeployment;
;
main.optimise(settings);
AssemblyItems expectationMain{
+78
View File
@@ -0,0 +1,78 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
#include <test/libsolidity/MemoryGuardTest.h>
#include <test/libyul/Common.h>
#include <libsolidity/codegen/ir/Common.h>
#include <libsolutil/Algorithms.h>
#include <libyul/Object.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <libyul/optimiser/FunctionCallFinder.h>
#include <fstream>
#include <memory>
#include <stdexcept>
using namespace std;
using namespace solidity;
using namespace solidity::util;
using namespace solidity::util::formatting;
using namespace solidity::langutil;
using namespace solidity::frontend;
using namespace solidity::frontend::test;
using namespace yul;
TestCase::TestResult MemoryGuardTest::run(ostream& _stream, string const& _linePrefix, bool _formatted)
{
compiler().reset();
compiler().setSources(StringMap{{"", m_source}});
compiler().setViaIR(true);
compiler().setOptimiserSettings(OptimiserSettings::none());
if (!compiler().compile())
return TestResult::FatalError;
m_obtainedResult.clear();
for (string contractName: compiler().contractNames())
{
ErrorList errors;
auto [object, analysisInfo] = yul::test::parse(
compiler().yulIR(contractName),
EVMDialect::strictAssemblyForEVMObjects({}),
errors
);
if (!object || !analysisInfo || Error::containsErrors(errors))
{
AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing IR." << endl;
return TestResult::FatalError;
}
auto handleObject = [&](std::string const& _kind, Object const& _object) {
m_obtainedResult += contractName + "(" + _kind + ") " + (FunctionCallFinder::run(
*_object.code,
"memoryguard"_yulstring
).empty() ? "false" : "true") + "\n";
};
handleObject("creation", *object);
size_t deployedIndex = object->subIndexByName.at(
YulString(IRNames::deployedObject(compiler().contractDefinition(contractName)))
);
handleObject("runtime", dynamic_cast<Object const&>(*object->subObjects[deployedIndex]));
}
return checkResult(_stream, _linePrefix, _formatted);
}
+53
View File
@@ -0,0 +1,53 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
#pragma once
#include <test/libsolidity/AnalysisFramework.h>
#include <test/TestCase.h>
#include <test/CommonSyntaxTest.h>
#include <liblangutil/Exceptions.h>
#include <libsolutil/AnsiColorized.h>
#include <iosfwd>
#include <string>
#include <vector>
#include <utility>
namespace solidity::frontend::test
{
using solidity::test::SyntaxTestError;
class MemoryGuardTest: public AnalysisFramework, public TestCase
{
public:
static std::unique_ptr<TestCase> create(Config const& _config)
{
return std::make_unique<MemoryGuardTest>(_config.filename);
}
MemoryGuardTest(std::string const& _filename): TestCase(_filename)
{
m_source = m_reader.source();
m_expectation = m_reader.simpleExpectations();
}
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false) override;
};
}
+28
View File
@@ -84,6 +84,34 @@ struct SolidityEndToEndTestExecutionFramework: public SolidityExecutionFramework
BOOST_FIXTURE_TEST_SUITE(SolidityEndToEndTest, SolidityEndToEndTestExecutionFramework)
BOOST_AUTO_TEST_CASE(creation_code_optimizer)
{
string codeC = R"(
contract C {
constructor(uint x) {
if (x == 0xFFFFFFFFFFFFFFFF42)
revert();
}
}
)";
string codeD = R"(
contract D {
function f() public pure returns (bytes memory) {
return type(C).creationCode;
}
}
)";
m_metadataHash = CompilerStack::MetadataHash::None;
ALSO_VIA_YUL({
bytes bytecodeC = compileContract(codeC);
reset();
compileAndRun(codeC + codeD);
ABI_CHECK(callContractFunction("f()"), encodeArgs(0x20, bytecodeC.size()) + encode(bytecodeC, false));
m_doEwasmTestrun = false;
})
}
unsigned constexpr roundTo32(unsigned _num)
{
return (_num + 31) / 32 * 32;
@@ -62,6 +62,7 @@ bytes SolidityExecutionFramework::multiSourceCompileContract(
m_compiler.enableEvmBytecodeGeneration(!m_compileViaYul);
m_compiler.enableIRGeneration(m_compileViaYul);
m_compiler.setRevertStringBehaviour(m_revertStrings);
m_compiler.setMetadataHash(m_metadataHash);
if (!m_compiler.compile())
{
// The testing framework expects an exception for
@@ -75,11 +75,12 @@ public:
/// the latter only if it is forced.
static std::string addPreamble(std::string const& _sourceCode);
protected:
solidity::frontend::CompilerStack m_compiler;
using CompilerStack = solidity::frontend::CompilerStack;
CompilerStack m_compiler;
bool m_compileViaYul = false;
bool m_compileToEwasm = false;
bool m_showMetadata = false;
CompilerStack::MetadataHash m_metadataHash = CompilerStack::MetadataHash::IPFS;
RevertStrings m_revertStrings = RevertStrings::Default;
};
@@ -0,0 +1,17 @@
contract C {
constructor() {
uint256 x;
assembly { x := 0 }
f();
}
function f() internal pure {
/// @solidity memory-safe-assembly
assembly { mstore(0, 0) }
}
function g() public pure {
assembly { mstore(0, 0) }
}
}
// ----
// :C(creation) true
// :C(runtime) false
@@ -0,0 +1,17 @@
contract C {
constructor() {
uint256 x;
assembly { x := 0 }
f();
}
function f() internal pure {
assembly { mstore(0, 0) }
}
function g() public pure {
/// @solidity memory-safe-assembly
assembly { mstore(0, 0) }
}
}
// ----
// :C(creation) false
// :C(runtime) true
@@ -0,0 +1,29 @@
function safe() pure returns (uint256 x) {
assembly { x := 42 }
/// @solidity memory-safe-assembly
assembly { mstore(0, 0) }
}
function unsafe() pure returns (uint256 x) {
assembly { pop(mload(0)) }
}
contract C {
constructor() {
unsafe();
}
function f() public pure {
safe();
}
}
contract D {
constructor() {
safe();
}
function f() public pure {
unsafe();
}
}
// ----
// :C(creation) false
// :C(runtime) true
// :D(creation) true
// :D(runtime) false
@@ -0,0 +1,17 @@
contract C {
constructor() {
/// @solidity memory-safe-assembly a memory-safe-assembly
assembly { mstore(0, 0) }
}
function f() internal pure {
/// @solidity a memory-safe-assembly
assembly { mstore(0, 0) }
/// @solidity a
/// memory-safe-assembly
/// b
assembly { mstore(0, 0) }
}
}
// ----
// :C(creation) true
// :C(runtime) true
@@ -0,0 +1,25 @@
contract C {
constructor(uint256 x) {
assembly { x := 4 }
/// @solidity memory-safe-assembly
assembly { mstore(0, 0) }
}
function f() public pure {
assembly { mstore(0,0) }
}
}
contract D {
constructor() {
assembly { mstore(0,0) }
}
function f(uint256 x) public pure {
assembly { x := 4 }
/// @solidity memory-safe-assembly
assembly { mstore(0, 0) }
}
}
// ----
// :C(creation) true
// :C(runtime) false
// :D(creation) false
// :D(runtime) true
@@ -0,0 +1,10 @@
contract C {
function f() external pure {
/// @solidity memory-safe-assembly
assembly {}
assembly {}
}
}
// ----
// :C(creation) true
// :C(runtime) true
@@ -0,0 +1,10 @@
contract C {
function f() external pure {
/// @solidity memory-safe-assembly
assembly {}
assembly { mstore(0,0) }
}
}
// ----
// :C(creation) true
// :C(runtime) false
@@ -0,0 +1,17 @@
contract C {
constructor() {
uint256 x;
assembly { x := 0 }
f();
}
function f() internal pure {
assembly "evmasm" ("memory-safe") { mstore(0, 0) }
assembly ("memory-safe") { mstore(0, 0) }
}
function g() public pure {
assembly { mstore(0, 0) }
}
}
// ----
// :C(creation) true
// :C(runtime) false
@@ -0,0 +1,16 @@
contract C {
constructor() {
uint256 x;
assembly { x := 0 }
f();
}
function f() internal pure {
assembly { mstore(0, 0) }
}
function g() public pure {
assembly "evmasm" ("memory-safe") { mstore(0, 0) }
}
}
// ----
// :C(creation) false
// :C(runtime) true
@@ -0,0 +1,28 @@
function safe() pure returns (uint256 x) {
assembly { x := 42 }
assembly "evmasm" ("memory-safe") { mstore(0, 0) }
}
function unsafe() pure returns (uint256 x) {
assembly { pop(mload(0)) }
}
contract C {
constructor() {
unsafe();
}
function f() public pure {
safe();
}
}
contract D {
constructor() {
safe();
}
function f() public pure {
unsafe();
}
}
// ----
// :C(creation) false
// :C(runtime) true
// :D(creation) true
// :D(runtime) false
@@ -0,0 +1,23 @@
contract C {
constructor(uint256 x) {
assembly { x := 4 }
assembly "evmasm" ("memory-safe") { mstore(0, 0) }
}
function f() public pure {
assembly { mstore(0,0) }
}
}
contract D {
constructor() {
assembly { mstore(0,0) }
}
function f(uint256 x) public pure {
assembly { x := 4 }
assembly ("memory-safe") { mstore(0, 0) }
}
}
// ----
// :C(creation) true
// :C(runtime) false
// :D(creation) false
// :D(runtime) true
@@ -0,0 +1,9 @@
contract C {
function f() external pure {
assembly "evmasm" ("memory-safe") {}
assembly {}
}
}
// ----
// :C(creation) true
// :C(runtime) true
@@ -0,0 +1,9 @@
contract C {
function f() external pure {
assembly "evmasm" ("memory-safe") {}
assembly { mstore(0,0) }
}
}
// ----
// :C(creation) true
// :C(runtime) false
@@ -0,0 +1,4 @@
contract C {}
// ----
// :C(creation) true
// :C(runtime) true
@@ -0,0 +1,4 @@
contract C {}
// ----
// :C(creation) true
// :C(runtime) true
@@ -0,0 +1,8 @@
contract C {
function f(uint256 x, uint256 y) public pure returns (uint256 z){
assembly { z := add(x, y) }
}
}
// ----
// :C(creation) true
// :C(runtime) true
@@ -0,0 +1,8 @@
contract C {
function f() public pure {
assembly { mstore(0,0) }
}
}
// ----
// :C(creation) true
// :C(runtime) false
@@ -0,0 +1,11 @@
contract C {
function f() public pure {
bytes memory x;
assembly {
x := 0
}
}
}
// ----
// :C(creation) true
// :C(runtime) false
@@ -26,6 +26,6 @@ contract Main {
// compileViaYul: also
// ----
// f(uint256): 0x34 -> 0x46bddb1178e94d7f2892ff5f366840eb658911794f2c3a44c450aa2c505186c1
// gas irOptimized: 113598
// gas irOptimized: 113613
// gas legacy: 126596
// gas legacyOptimized: 113823
@@ -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: 443960
// gas irOptimized: 443989
// gas legacy: 590683
// gas legacyOptimized: 448326
@@ -26,6 +26,6 @@ contract Creator {
// compileViaYul: also
// ----
// f(uint256,bytes): 7, 0x40, 78, "abcdefghijklmnopqrstuvwxyzabcdef", "ghijklmnopqrstuvwxyzabcdefghijkl", "mnopqrstuvwxyz" -> 7, "h"
// gas irOptimized: 300804
// gas irOptimized: 300837
// gas legacy: 428917
// gas legacyOptimized: 298128
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Provides a set of functions to operate with Base64 strings.
*/
library InlineAsmBase64 {
/**
* @dev Base64 Encoding/Decoding Table
*/
string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* @dev Converts a `bytes` to its Bytes64 `string` representation.
*/
function encode(bytes memory data) internal pure returns (string memory) {
/**
* Inspired by OpenZepplin Base64 implementation
* https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2884/commits/157c32b65a15cb0b58257543643cafa1cebf883a
*/
if (data.length == 0) return "";
// Loads the table into memory
string memory table = _TABLE;
// Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
// and split into 4 numbers of 6 bits.
// The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
// - `data.length + 2` -> Round up
// - `/ 3` -> Number of 3-bytes chunks
// - `4 *` -> 4 characters for each chunk
uint256 encodedLen = 4 * ((data.length + 2) / 3);
// Add some extra buffer at the end required for the writing
string memory result = new string(encodedLen);
assembly {
// Store the actual result length in memory
mstore(result, encodedLen)
// Prepare the lookup table
let tablePtr := add(table, 1)
// Prepare input pointer
let dataPtr := data
let endPtr := add(dataPtr, mload(data))
// Prepare result pointer, jump over length
let resultPtr := add(result, 32)
// Run over the input, 3 bytes at a time
for {
} lt(dataPtr, endPtr) {
} {
// Advance 3 bytes
dataPtr := add(dataPtr, 3)
let input := mload(dataPtr)
// To write each character, shift the 3 bytes (24 bits) chunk 4
// times in blocks of 6 bits for each character (18, 12, 6, 0)
// and apply logical AND with 0x3F to extract the 6-bit group.
// Add the 6-bit group with the table ptr to index into the
// table and acquire the character to write. Finally, write
// the character to the result pointer.
mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
resultPtr := add(resultPtr, 1) // Advance
}
// When data `bytes` is not exactly 3 bytes long
// it is padded with `=` characters at the end
switch mod(mload(data), 3)
case 1 {
mstore8(sub(resultPtr, 1), 0x3d)
mstore8(sub(resultPtr, 2), 0x3d)
}
case 2 {
mstore8(sub(resultPtr, 1), 0x3d)
}
}
return result;
}
}
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Provides a set of functions to operate with Base64 strings.
*/
library NoAsmBase64 {
bytes private constant TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
function encode(bytes memory data) internal pure returns (string memory) {
if (data.length == 0) return "";
bytes memory table = TABLE;
bytes memory result = new bytes(4 * ((data.length + 2) / 3));
uint256 resultPtr = 0;
for (uint256 dataPtr = 0; dataPtr < data.length; dataPtr += 3) {
uint24 chunk = ( (uint24(uint8(data[dataPtr + 0])) << 16))
+ (dataPtr + 1 < data.length ? (uint24(uint8(data[dataPtr + 1])) << 8) : 0)
+ (dataPtr + 2 < data.length ? (uint24(uint8(data[dataPtr + 2])) ) : 0);
result[resultPtr++] = table[uint8(chunk >> 18) & 0x3f];
result[resultPtr++] = table[uint8(chunk >> 12) & 0x3f];
result[resultPtr++] = table[uint8(chunk >> 6) & 0x3f];
result[resultPtr++] = table[uint8(chunk ) & 0x3f];
}
if (data.length % 3 == 1) {
result[--resultPtr] = 0x3d;
result[--resultPtr] = 0x3d;
}
else if (data.length % 3 == 2) {
result[--resultPtr] = 0x3d;
}
return (string(result));
}
}
@@ -0,0 +1,61 @@
==== ExternalSource: _base64/base64_inline_asm.sol ====
==== ExternalSource: _base64/base64_no_inline_asm.sol ====
==== Source: base64.sol ====
import "_base64/base64_inline_asm.sol";
import "_base64/base64_no_inline_asm.sol";
contract test {
function encode_inline_asm(bytes memory data) external pure returns (string memory) {
return InlineAsmBase64.encode(data);
}
function encode_no_asm(bytes memory data) external pure returns (string memory) {
return NoAsmBase64.encode(data);
}
function encode_inline_asm_large() external {
for (uint i = 0; i < 1000; i++) {
InlineAsmBase64.encode("foo");
}
}
function encode_no_asm_large() external {
for (uint i = 0; i < 1000; i++) {
NoAsmBase64.encode("foo");
}
}
}
// Test cases derived from Base64 specification: RFC4648
// https://datatracker.ietf.org/doc/html/rfc4648#section-10
//
// ====
// EVMVersion: >=constantinople
// compileViaYul: also
// ----
// constructor()
// gas irOptimized: 450044
// gas legacy: 766936
// gas legacyOptimized: 543094
// encode_inline_asm(bytes): 0x20, 0 -> 0x20, 0
// encode_inline_asm(bytes): 0x20, 1, "f" -> 0x20, 4, "Zg=="
// encode_inline_asm(bytes): 0x20, 2, "fo" -> 0x20, 4, "Zm8="
// encode_inline_asm(bytes): 0x20, 3, "foo" -> 0x20, 4, "Zm9v"
// encode_inline_asm(bytes): 0x20, 4, "foob" -> 0x20, 8, "Zm9vYg=="
// encode_inline_asm(bytes): 0x20, 5, "fooba" -> 0x20, 8, "Zm9vYmE="
// encode_inline_asm(bytes): 0x20, 6, "foobar" -> 0x20, 8, "Zm9vYmFy"
// encode_no_asm(bytes): 0x20, 0 -> 0x20, 0
// encode_no_asm(bytes): 0x20, 1, "f" -> 0x20, 4, "Zg=="
// encode_no_asm(bytes): 0x20, 2, "fo" -> 0x20, 4, "Zm8="
// encode_no_asm(bytes): 0x20, 3, "foo" -> 0x20, 4, "Zm9v"
// encode_no_asm(bytes): 0x20, 4, "foob" -> 0x20, 8, "Zm9vYg=="
// encode_no_asm(bytes): 0x20, 5, "fooba" -> 0x20, 8, "Zm9vYmE="
// encode_no_asm(bytes): 0x20, 6, "foobar" -> 0x20, 8, "Zm9vYmFy"
// encode_inline_asm_large()
// gas irOptimized: 1385047
// gas legacy: 1658033
// gas legacyOptimized: 1210033
// encode_no_asm_large()
// gas irOptimized: 3335101
// gas legacy: 4801077
// gas legacyOptimized: 2929077
@@ -50,7 +50,7 @@ contract test {
// compileViaYul: also
// ----
// constructor()
// gas irOptimized: 1790188
// gas irOptimized: 1792108
// gas legacy: 2250130
// gas legacyOptimized: 1746528
// div(uint256,uint256): 3141592653589793238, 88714123 -> 35412542528203691288251815328
@@ -17,7 +17,7 @@ contract D {
// compileViaYul: also
// ----
// constructor(): 2 ->
// gas irOptimized: 203967
// gas irOptimized: 203982
// gas legacy: 245842
// gas legacyOptimized: 195676
// f() -> 2
@@ -18,7 +18,7 @@ contract D {
// compileViaYul: also
// ----
// constructor(): 2 ->
// gas irOptimized: 204130
// gas irOptimized: 204145
// gas legacy: 246202
// gas legacyOptimized: 195914
// f() -> 2
@@ -42,7 +42,7 @@ contract Main {
// compileViaYul: also
// ----
// constructor(), 22 wei ->
// gas irOptimized: 284287
// gas irOptimized: 284321
// gas legacy: 402045
// gas legacyOptimized: 266772
// getFlag() -> true
@@ -22,6 +22,6 @@ contract A {
// compileViaYul: also
// ----
// f(), 10 ether -> 3007, 3008, 3009
// gas irOptimized: 272413
// gas irOptimized: 272467
// gas legacy: 422501
// gas legacyOptimized: 287472
@@ -0,0 +1,5 @@
function f() pure {
assembly "evmasm" ("memory-safe", "memory-safe") {}
}
// ----
// SyntaxError 7026: (24-75): Inline assembly marked memory-safe multiple times.
@@ -0,0 +1,8 @@
function f() pure {
assembly "evmasm" ("a", "b", "c", "c") {}
}
// ----
// Warning 4430: (24-65): Unknown inline assembly flag: "a"
// Warning 4430: (24-65): Unknown inline assembly flag: "b"
// Warning 4430: (24-65): Unknown inline assembly flag: "c"
// Warning 4430: (24-65): Unknown inline assembly flag: "c"
@@ -0,0 +1,5 @@
function f() pure {
assembly " evmasm" {}
}
// ----
// ParserError 4531: (33-42): Only "evmasm" supported.
@@ -0,0 +1,5 @@
function f() pure {
assembly ("memory-safe", "memory-safe") {}
}
// ----
// SyntaxError 7026: (24-66): Inline assembly marked memory-safe multiple times.
@@ -0,0 +1,5 @@
function f() pure {
assembly () {}
}
// ----
// ParserError 2314: (34-35): Expected 'StringLiteral' but got ')'
@@ -0,0 +1,5 @@
function f() pure {
assembly "evmasm" () {}
}
// ----
// ParserError 2314: (43-44): Expected 'StringLiteral' but got ')'
@@ -0,0 +1,5 @@
function f() pure {
assembly ("a" "b") {}
}
// ----
// ParserError 2314: (35-38): Expected ')' but got 'StringLiteral'
@@ -0,0 +1,8 @@
function f() pure {
assembly ("a", "b", "c", "c") {}
}
// ----
// Warning 4430: (24-56): Unknown inline assembly flag: "a"
// Warning 4430: (24-56): Unknown inline assembly flag: "b"
// Warning 4430: (24-56): Unknown inline assembly flag: "c"
// Warning 4430: (24-56): Unknown inline assembly flag: "c"
@@ -0,0 +1,14 @@
contract C {
function f() public pure {
/// @test test
assembly {}
/// @solidity test
assembly {}
/// @param
assembly {}
}
}
// ----
// Warning 6269: (60-71): Unexpected NatSpec tag "test" with value "test" in inline assembly.
// Warning 8787: (95-106): Unexpected value for @solidity tag in inline assembly: test
// Warning 7828: (122-133): Inline assembly has invalid NatSpec documentation.
@@ -0,0 +1,7 @@
function f() pure {
/// @solidity memory-safe-assembly
assembly "evmasm" ("memory-safe") {
}
}
// ----
// Warning 8544: (63-104): Inline assembly marked as memory safe using both a NatSpec tag and an assembly flag. If you are not concerned with backwards compatibility, only use the assembly flag, otherwise only use the NatSpec tag.
@@ -0,0 +1,3 @@
function f() pure {
assembly "evmasm" ("memory-safe") {}
}
@@ -0,0 +1,6 @@
contract C {
function f() public pure {
// @solidity memory-safe-assembly
assembly {}
}
}
@@ -0,0 +1,23 @@
function f() pure {
/// @unrelated bogus-value
/// @before bogus-value
///
/// @solidity a memory-safe-assembly b c
/// d
/// @after bogus-value
assembly {}
/// @solidity memory-safe-assembly a a a
/// memory-safe-assembly
assembly {}
}
// ----
// Warning 6269: (189-200): Unexpected NatSpec tag "after" with value "bogus-value" in inline assembly.
// Warning 6269: (189-200): Unexpected NatSpec tag "before" with value "bogus-value" in inline assembly.
// Warning 8787: (189-200): Unexpected value for @solidity tag in inline assembly: a
// Warning 8787: (189-200): Unexpected value for @solidity tag in inline assembly: b
// Warning 8787: (189-200): Unexpected value for @solidity tag in inline assembly: c
// Warning 8787: (189-200): Unexpected value for @solidity tag in inline assembly: d
// Warning 8787: (289-300): Unexpected value for @solidity tag in inline assembly: a
// Warning 4377: (289-300): Value for @solidity tag in inline assembly specified multiple times: a
// Warning 4377: (289-300): Value for @solidity tag in inline assembly specified multiple times: memory-safe-assembly
@@ -0,0 +1,19 @@
function f() pure {
/// @unrelated bogus-value
/// @before
///
/// @solidity a memory-safe-assembly b c
/// d
/// @after bogus-value
assembly {}
/// @solidity memory-safe-assembly a a a
/// memory-safe-assembly
assembly {}
}
// ----
// Warning 6269: (177-188): Unexpected NatSpec tag "after" with value "bogus-value" in inline assembly.
// Warning 6269: (177-188): Unexpected NatSpec tag "before" with value "@solidity a memory-safe-assembly b c d" in inline assembly.
// Warning 8787: (277-288): Unexpected value for @solidity tag in inline assembly: a
// Warning 4377: (277-288): Value for @solidity tag in inline assembly specified multiple times: a
// Warning 4377: (277-288): Value for @solidity tag in inline assembly specified multiple times: memory-safe-assembly
+2 -1
View File
@@ -22,6 +22,7 @@
#include <libsolutil/CommonData.h>
#include <libsolutil/CommonIO.h>
#include <libsolutil/StringUtils.h>
#include <boost/algorithm/string.hpp>
@@ -216,7 +217,7 @@ string BytesUtils::formatString(bytes const& _bytes, size_t _cutOff)
os << "\\n";
break;
default:
if (isprint(v))
if (isPrint(static_cast<char>(v)))
os << v;
else
os << "\\x" << util::toHex(v, HexCase::Lower);
+9 -6
View File
@@ -762,13 +762,16 @@ string TestFileParser::Scanner::scanString()
// TODO: use fromHex() from CommonData
char TestFileParser::Scanner::scanHexPart()
{
auto toLower = [](char _c) -> char { return tolower(_c, locale::classic()); };
auto isDigit = [](char _c) -> bool { return isdigit(_c, locale::classic()); };
advance(); // skip 'x'
int value{};
if (isdigit(current()))
if (isDigit(current()))
value = current() - '0';
else if (tolower(current()) >= 'a' && tolower(current()) <= 'f')
value = tolower(current()) - 'a' + 10;
else if (toLower(current()) >= 'a' && toLower(current()) <= 'f')
value = toLower(current()) - 'a' + 10;
else
BOOST_THROW_EXCEPTION(TestParserError("\\x used with no following hex digits."));
@@ -777,10 +780,10 @@ char TestFileParser::Scanner::scanHexPart()
return static_cast<char>(value);
value <<= 4;
if (isdigit(current()))
if (isDigit(current()))
value |= current() - '0';
else if (tolower(current()) >= 'a' && tolower(current()) <= 'f')
value |= tolower(current()) - 'a' + 10;
else if (toLower(current()) >= 'a' && toLower(current()) <= 'f')
value |= toLower(current()) - 'a' + 10;
advance();
+1 -1
View File
@@ -65,7 +65,7 @@ TestCase::TestResult EVMCodeTransformTest::run(ostream& _stream, string const& _
return TestResult::FatalError;
}
evmasm::Assembly assembly;
evmasm::Assembly assembly{false, {}};
EthAssemblyAdapter adapter(assembly);
EVMObjectCompiler::compile(
*stack.parserResult(),
+1
View File
@@ -23,6 +23,7 @@ add_executable(isoltest
../libsolidity/util/TestFileParser.cpp
../libsolidity/util/TestFunctionCall.cpp
../libsolidity/GasTest.cpp
../libsolidity/MemoryGuardTest.cpp
../libsolidity/SyntaxTest.cpp
../libsolidity/SemanticTest.cpp
../libsolidity/AnalysisFramework.cpp
+13 -11
View File
@@ -185,25 +185,27 @@ void FuzzerUtil::testConstantOptimizer(string const& _input, bool _quiet)
if (!_quiet)
cout << "Got " << numbers.size() << " inputs:" << endl;
Assembly assembly;
for (u256 const& n: numbers)
{
if (!_quiet)
cout << n << endl;
assembly.append(n);
}
for (bool isCreation: {false, true})
{
Assembly assembly{isCreation, {}};
for (u256 const& n: numbers)
{
if (!_quiet)
cout << n << endl;
assembly.append(n);
}
for (unsigned runs: {1u, 2u, 3u, 20u, 40u, 100u, 200u, 400u, 1000u})
{
// Make a copy here so that each time we start with the original state.
Assembly tmp = assembly;
ConstantOptimisationMethod::optimiseConstants(
isCreation,
runs,
langutil::EVMVersion{},
tmp
isCreation,
runs,
langutil::EVMVersion{},
tmp
);
}
}
}
void FuzzerUtil::testStandardCompiler(string const& _input, bool _quiet)
@@ -28,6 +28,7 @@
#include <libsolutil/CommonIO.h>
#include <libsolutil/CommonData.h>
#include <libsolutil/StringUtils.h>
#include <test/tools/ossfuzz/yulFuzzerCommon.h>
@@ -53,7 +54,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size)
string input(reinterpret_cast<char const*>(_data), _size);
if (std::any_of(input.begin(), input.end(), [](char c) {
return ((static_cast<unsigned char>(c) > 127) || !(std::isprint(c) || (c == '\n') || (c == '\t')));
return ((static_cast<unsigned char>(c) > 127) || !(isPrint(c) || (c == '\n') || (c == '\t')));
}))
return 0;
+2 -1
View File
@@ -21,6 +21,7 @@
#include <libsolutil/CommonIO.h>
#include <libsolutil/Exceptions.h>
#include <libsolutil/StringUtils.h>
#include <liblangutil/ErrorReporter.h>
#include <libyul/AsmAnalysis.h>
#include <libyul/AsmAnalysisInfo.h>
@@ -155,7 +156,7 @@ public:
return (
!boost::algorithm::iequals(get<1>(_a), get<1>(_b)) ?
boost::algorithm::lexicographical_compare(get<1>(_a), get<1>(_b), boost::algorithm::is_iless()) :
tolower(get<0>(_a)) < tolower(get<0>(_b))
toLower(get<0>(_a)) < toLower(get<0>(_b))
);
});