From 543f804226aee2189d9ab23bf2823cb4949d1e66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 13 Nov 2020 21:52:17 +0100 Subject: [PATCH 1/2] StandardCompiler: Add helpers to streamline comparing link references in tests --- test/libsolidity/StandardCompiler.cpp | 60 ++++++++++++++++++++------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index 37539d712..c2dfcb45d 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -86,6 +86,48 @@ Json::Value getContractResult(Json::Value const& _compilerResult, string const& return _compilerResult["contracts"][_file][_name]; } +void checkLinkReferencesSchema(Json::Value const& _contractResult) +{ + BOOST_TEST_REQUIRE(_contractResult.isObject()); + BOOST_TEST_REQUIRE(_contractResult["evm"]["bytecode"].isObject()); + + Json::Value const& linkReferenceResult = _contractResult["evm"]["bytecode"]["linkReferences"]; + BOOST_TEST_REQUIRE(linkReferenceResult.isObject()); + + for (string const& fileName: linkReferenceResult.getMemberNames()) + { + BOOST_TEST_REQUIRE(linkReferenceResult[fileName].isObject()); + for (string const& libraryName: linkReferenceResult[fileName].getMemberNames()) + { + BOOST_TEST_REQUIRE(linkReferenceResult[fileName][libraryName].isArray()); + BOOST_TEST_REQUIRE(!linkReferenceResult[fileName][libraryName].empty()); + for (int i = 0; i < static_cast(linkReferenceResult.size()); ++i) + { + BOOST_TEST_REQUIRE(linkReferenceResult[fileName][libraryName][i].isObject()); + BOOST_TEST_REQUIRE(linkReferenceResult[fileName][libraryName][i].size() == 2); + BOOST_TEST_REQUIRE(linkReferenceResult[fileName][libraryName][i]["length"].isUInt()); + BOOST_TEST_REQUIRE(linkReferenceResult[fileName][libraryName][i]["start"].isUInt()); + } + } + } +} + +void expectLinkReferences(Json::Value const& _contractResult, map> const& _expectedLinkReferences) +{ + checkLinkReferencesSchema(_contractResult); + + Json::Value const& linkReferenceResult = _contractResult["evm"]["bytecode"]["linkReferences"]; + BOOST_TEST(linkReferenceResult.size() == _expectedLinkReferences.size()); + + for (auto const& [fileName, libraries]: _expectedLinkReferences) + { + BOOST_TEST(linkReferenceResult.isMember(fileName)); + BOOST_TEST(linkReferenceResult[fileName].size() == libraries.size()); + for (string const& libraryName: libraries) + BOOST_TEST(linkReferenceResult[fileName].isMember(libraryName)); + } +} + Json::Value compile(string _input) { StandardCompiler compiler; @@ -710,11 +752,7 @@ BOOST_AUTO_TEST_CASE(library_filename_with_colon) BOOST_CHECK(containsAtMostWarnings(result)); Json::Value contract = getContractResult(result, "fileA", "A"); BOOST_CHECK(contract.isObject()); - BOOST_CHECK(contract["evm"]["bytecode"].isObject()); - BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"].isObject()); - BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["git:library.sol"].isObject()); - BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["git:library.sol"]["L"].isArray()); - BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["git:library.sol"]["L"][0].isObject()); + expectLinkReferences(contract, {{"git:library.sol", {"L"}}}); } BOOST_AUTO_TEST_CASE(libraries_invalid_top_level) @@ -860,15 +898,9 @@ BOOST_AUTO_TEST_CASE(library_linking) } )"; Json::Value result = compile(input); - BOOST_CHECK(containsAtMostWarnings(result)); - Json::Value contract = getContractResult(result, "fileA", "A"); - BOOST_CHECK(contract.isObject()); - BOOST_CHECK(contract["evm"]["bytecode"].isObject()); - BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"].isObject()); - BOOST_CHECK(!contract["evm"]["bytecode"]["linkReferences"]["library.sol"].isObject()); - BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["library2.sol"].isObject()); - BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["library2.sol"]["L2"].isArray()); - BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["library2.sol"]["L2"][0].isObject()); + BOOST_TEST(containsAtMostWarnings(result)); + Json::Value contractResult = getContractResult(result, "fileA", "A"); + expectLinkReferences(contractResult, {{"library2.sol", {"L2"}}}); } BOOST_AUTO_TEST_CASE(evm_version) From b97c6c55adf6e86c59383c0fcad73bf04951e0ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 13 Nov 2020 14:15:59 +0100 Subject: [PATCH 2/2] StandardCompiler: Don't assume that link reference always contains a colon --- libsolidity/interface/StandardCompiler.cpp | 8 ++- .../args | 1 + .../err | 1 + .../input.yul | 5 ++ .../output | 16 +++++ test/libsolidity/StandardCompiler.cpp | 64 +++++++++++++++++++ 6 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 test/cmdlineTests/linking_strict_assembly_no_file_name_in_link_reference/args create mode 100644 test/cmdlineTests/linking_strict_assembly_no_file_name_in_link_reference/err create mode 100644 test/cmdlineTests/linking_strict_assembly_no_file_name_in_link_reference/input.yul create mode 100644 test/cmdlineTests/linking_strict_assembly_no_file_name_in_link_reference/output diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 5758c4994..86587839d 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -323,10 +323,12 @@ Json::Value formatLinkReferences(std::map const& linkRefere for (auto const& ref: linkReferences) { string const& fullname = ref.second; + + // If the link reference does not contain a colon, assume that the file name is missing and + // the whole string represents the library name. size_t colon = fullname.rfind(':'); - solAssert(colon != string::npos, ""); - string file = fullname.substr(0, colon); - string name = fullname.substr(colon + 1); + string file = (colon != string::npos ? fullname.substr(0, colon) : ""); + string name = (colon != string::npos ? fullname.substr(colon + 1) : fullname); Json::Value fileObject = ret.get(file, Json::objectValue); Json::Value libraryArray = fileObject.get(name, Json::arrayValue); diff --git a/test/cmdlineTests/linking_strict_assembly_no_file_name_in_link_reference/args b/test/cmdlineTests/linking_strict_assembly_no_file_name_in_link_reference/args new file mode 100644 index 000000000..57ee5078b --- /dev/null +++ b/test/cmdlineTests/linking_strict_assembly_no_file_name_in_link_reference/args @@ -0,0 +1 @@ +--strict-assembly --libraries L:0x1234567890123456789012345678901234567890 diff --git a/test/cmdlineTests/linking_strict_assembly_no_file_name_in_link_reference/err b/test/cmdlineTests/linking_strict_assembly_no_file_name_in_link_reference/err new file mode 100644 index 000000000..014a1178f --- /dev/null +++ b/test/cmdlineTests/linking_strict_assembly_no_file_name_in_link_reference/err @@ -0,0 +1 @@ +Warning: Yul is still experimental. Please use the output with care. diff --git a/test/cmdlineTests/linking_strict_assembly_no_file_name_in_link_reference/input.yul b/test/cmdlineTests/linking_strict_assembly_no_file_name_in_link_reference/input.yul new file mode 100644 index 000000000..b4dbc3cbc --- /dev/null +++ b/test/cmdlineTests/linking_strict_assembly_no_file_name_in_link_reference/input.yul @@ -0,0 +1,5 @@ +object "a" { + code { + let addr := linkersymbol("L") + } +} diff --git a/test/cmdlineTests/linking_strict_assembly_no_file_name_in_link_reference/output b/test/cmdlineTests/linking_strict_assembly_no_file_name_in_link_reference/output new file mode 100644 index 000000000..c7a9339b6 --- /dev/null +++ b/test/cmdlineTests/linking_strict_assembly_no_file_name_in_link_reference/output @@ -0,0 +1,16 @@ + +======= linking_strict_assembly_no_file_name_in_link_reference/input.yul (EVM) ======= + +Pretty printed source: +object "a" { + code { let addr := linkersymbol("L") } +} + + +Binary representation: +73123456789012345678901234567890123456789050 + +Text representation: + linkerSymbol("8aa64f937099b65a4febc243a5ae0f2d6416bb9e473c30dd29c1ee498fb7c5a8") + /* "linking_strict_assembly_no_file_name_in_link_reference/input.yul":22:67 */ + pop diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index c2dfcb45d..270295c3c 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -903,6 +903,70 @@ BOOST_AUTO_TEST_CASE(library_linking) expectLinkReferences(contractResult, {{"library2.sol", {"L2"}}}); } +BOOST_AUTO_TEST_CASE(linking_yul_empty_link_reference) +{ + char const* input = R"( + { + "language": "Yul", + "settings": { + "libraries": { + "": { + "": "0x4200000000000000000000000000000000000001" + } + }, + "outputSelection": { + "fileA": { + "*": [ + "evm.bytecode.linkReferences" + ] + } + } + }, + "sources": { + "fileA": { + "content": "object \"a\" { code { let addr := linkersymbol(\"\") } }" + } + } + } + )"; + Json::Value result = compile(input); + BOOST_TEST(containsAtMostWarnings(result)); + Json::Value contractResult = getContractResult(result, "fileA", "a"); + expectLinkReferences(contractResult, {}); +} + +BOOST_AUTO_TEST_CASE(linking_yul_no_filename_in_link_reference) +{ + char const* input = R"( + { + "language": "Yul", + "settings": { + "libraries": { + "": { + "L": "0x4200000000000000000000000000000000000001" + } + }, + "outputSelection": { + "fileA": { + "*": [ + "evm.bytecode.linkReferences" + ] + } + } + }, + "sources": { + "fileA": { + "content": "object \"a\" { code { let addr := linkersymbol(\"L\") } }" + } + } + } + )"; + Json::Value result = compile(input); + BOOST_TEST(containsAtMostWarnings(result)); + Json::Value contractResult = getContractResult(result, "fileA", "a"); + expectLinkReferences(contractResult, {}); +} + BOOST_AUTO_TEST_CASE(evm_version) { auto inputForVersion = [](string const& _version)