mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #10289 from ethereum/fix-standard-json-crash-on-linker-references-without-colon
Fix standard JSON crash on linker references without a colon
This commit is contained in:
commit
81b3a13333
@ -323,10 +323,12 @@ Json::Value formatLinkReferences(std::map<size_t, std::string> const& linkRefere
|
|||||||
for (auto const& ref: linkReferences)
|
for (auto const& ref: linkReferences)
|
||||||
{
|
{
|
||||||
string const& fullname = ref.second;
|
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(':');
|
size_t colon = fullname.rfind(':');
|
||||||
solAssert(colon != string::npos, "");
|
string file = (colon != string::npos ? fullname.substr(0, colon) : "");
|
||||||
string file = fullname.substr(0, colon);
|
string name = (colon != string::npos ? fullname.substr(colon + 1) : fullname);
|
||||||
string name = fullname.substr(colon + 1);
|
|
||||||
|
|
||||||
Json::Value fileObject = ret.get(file, Json::objectValue);
|
Json::Value fileObject = ret.get(file, Json::objectValue);
|
||||||
Json::Value libraryArray = fileObject.get(name, Json::arrayValue);
|
Json::Value libraryArray = fileObject.get(name, Json::arrayValue);
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
--strict-assembly --libraries L:0x1234567890123456789012345678901234567890
|
@ -0,0 +1 @@
|
|||||||
|
Warning: Yul is still experimental. Please use the output with care.
|
@ -0,0 +1,5 @@
|
|||||||
|
object "a" {
|
||||||
|
code {
|
||||||
|
let addr := linkersymbol("L")
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
@ -86,6 +86,48 @@ Json::Value getContractResult(Json::Value const& _compilerResult, string const&
|
|||||||
return _compilerResult["contracts"][_file][_name];
|
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<int>(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<string, set<string>> 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)
|
Json::Value compile(string _input)
|
||||||
{
|
{
|
||||||
StandardCompiler compiler;
|
StandardCompiler compiler;
|
||||||
@ -710,11 +752,7 @@ BOOST_AUTO_TEST_CASE(library_filename_with_colon)
|
|||||||
BOOST_CHECK(containsAtMostWarnings(result));
|
BOOST_CHECK(containsAtMostWarnings(result));
|
||||||
Json::Value contract = getContractResult(result, "fileA", "A");
|
Json::Value contract = getContractResult(result, "fileA", "A");
|
||||||
BOOST_CHECK(contract.isObject());
|
BOOST_CHECK(contract.isObject());
|
||||||
BOOST_CHECK(contract["evm"]["bytecode"].isObject());
|
expectLinkReferences(contract, {{"git:library.sol", {"L"}}});
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(libraries_invalid_top_level)
|
BOOST_AUTO_TEST_CASE(libraries_invalid_top_level)
|
||||||
@ -860,15 +898,73 @@ BOOST_AUTO_TEST_CASE(library_linking)
|
|||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
Json::Value result = compile(input);
|
Json::Value result = compile(input);
|
||||||
BOOST_CHECK(containsAtMostWarnings(result));
|
BOOST_TEST(containsAtMostWarnings(result));
|
||||||
Json::Value contract = getContractResult(result, "fileA", "A");
|
Json::Value contractResult = getContractResult(result, "fileA", "A");
|
||||||
BOOST_CHECK(contract.isObject());
|
expectLinkReferences(contractResult, {{"library2.sol", {"L2"}}});
|
||||||
BOOST_CHECK(contract["evm"]["bytecode"].isObject());
|
}
|
||||||
BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"].isObject());
|
|
||||||
BOOST_CHECK(!contract["evm"]["bytecode"]["linkReferences"]["library.sol"].isObject());
|
BOOST_AUTO_TEST_CASE(linking_yul_empty_link_reference)
|
||||||
BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["library2.sol"].isObject());
|
{
|
||||||
BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["library2.sol"]["L2"].isArray());
|
char const* input = R"(
|
||||||
BOOST_CHECK(contract["evm"]["bytecode"]["linkReferences"]["library2.sol"]["L2"][0].isObject());
|
{
|
||||||
|
"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)
|
BOOST_AUTO_TEST_CASE(evm_version)
|
||||||
|
Loading…
Reference in New Issue
Block a user