Fixes #10299 - Common function for library address validation

This commit is contained in:
David Bar-On 2023-06-07 10:10:27 +03:00
parent 09038ce4cb
commit f3e8dfdaca
9 changed files with 251 additions and 57 deletions

View File

@ -31,6 +31,7 @@
#include <libevmasm/Disassemble.h>
#include <libsolutil/Address.h>
#include <libsmtutil/Exceptions.h>
#include <liblangutil/SourceReferenceFormatter.h>
@ -888,31 +889,11 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
{
if (!jsonSourceName[library].isString())
return formatFatalError(Error::Type::JSONError, "Library address must be a string.");
string address = jsonSourceName[library].asString();
if (!boost::starts_with(address, "0x"))
return formatFatalError(
Error::Type::JSONError,
"Library address is not prefixed with \"0x\"."
);
if (address.length() != 42)
return formatFatalError(
Error::Type::JSONError,
"Library address is of invalid length."
);
try
{
ret.libraries[sourceName + ":" + library] = util::h160(address);
}
catch (util::BadHexCharacter const&)
{
return formatFatalError(
Error::Type::JSONError,
"Invalid library address (\"" + address + "\") supplied."
);
}
std::string addrString = jsonSourceName[library].asString();
util::Result<util::h160> addrResult = util::validateAddress(addrString);
if (!addrResult.message().empty())
return formatFatalError(Error::Type::JSONError, addrResult.message());
ret.libraries[sourceName + ":" + library] = addrResult.get();
}
}

73
libsolutil/Address.cpp Normal file
View File

@ -0,0 +1,73 @@
/*
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 <libsolutil/Address.h>
#include <libsolutil/Exceptions.h>
using namespace std;
namespace solidity::util
{
/// @returns a h160 representation of an address string
/// or an error message in case the address string is not a valid address
Result<h160> validateAddress(string _addrString)
{
string message;
h160 address;
if (_addrString.substr(0, 2) != "0x")
message = "Library address \"" + _addrString + "\" is not prefixed with \"0x\".\n"
"Note that the address must be prefixed with \"0x\".";
else
{
string addrString = _addrString.substr(2);
if (addrString.length() != 40)
message =
"Invalid library address length " +
to_string(addrString.length()) +
" instead of 40 characters.";
else
{
try
{
address = util::h160(_addrString);
}
catch (util::BadHexCharacter const&)
{
message = "Invalid library address (\"" + _addrString + "\") supplied.";
}
}
if (message.empty())
{
if (!passesAddressChecksum(addrString, false))
message =
"Invalid checksum for library address \"" + _addrString + "\".\n"
"The correct checksum is \"" + getChecksummedAddress(addrString) + "\".";
}
}
if (!message.empty())
return Result<h160>::err(message);
return address;
}
}

32
libsolutil/Address.h Normal file
View File

@ -0,0 +1,32 @@
/*
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 <libsolutil/Common.h>
#include <libsolutil/Result.h>
#include <libsolutil/FixedHash.h>
namespace solidity::util
{
/// @returns a h160 representation of an address string
/// or an error message in case the address string is not a valid address
Result<h160> validateAddress(std::string _addrString);
}

View File

@ -1,4 +1,6 @@
set(sources
Address.cpp
Address.h
Algorithms.h
AnsiColorized.h
Assertions.h

View File

@ -24,6 +24,8 @@
#include <liblangutil/EVMVersion.h>
#include <libsolutil/Address.h>
#include <boost/algorithm/string.hpp>
#include <range/v3/view/transform.hpp>
@ -417,36 +419,10 @@ void CommandLineParser::parseLibraryOption(string const& _input)
"Note that there should not be any whitespace after the " +
(isSeparatorEqualSign ? "equal sign" : "colon") + "."
);
if (addrString.substr(0, 2) == "0x")
addrString = addrString.substr(2);
else
solThrow(
CommandLineValidationError,
"The address " + addrString + " is not prefixed with \"0x\".\n"
"Note that the address must be prefixed with \"0x\"."
);
if (addrString.length() != 40)
solThrow(
CommandLineValidationError,
"Invalid length for address for library \"" + libName + "\": " +
to_string(addrString.length()) + " instead of 40 characters."
);
if (!util::passesAddressChecksum(addrString, false))
solThrow(
CommandLineValidationError,
"Invalid checksum on address for library \"" + libName + "\": " + addrString + "\n"
"The correct checksum is " + util::getChecksummedAddress(addrString)
);
bytes binAddr = util::fromHex(addrString);
util::h160 address(binAddr, util::h160::AlignRight);
if (binAddr.size() > 20 || address == util::h160())
solThrow(
CommandLineValidationError,
"Invalid address for library \"" + libName + "\": " + addrString
);
m_options.linker.libraries[libName] = address;
util::Result<util::h160> addrResult = util::validateAddress(addrString);
if (!addrResult.message().empty())
solThrow(CommandLineValidationError, "Library \"" + libName + "\": " + addrResult.message());
m_options.linker.libraries[libName] = addrResult.get();
}
}

View File

@ -0,0 +1 @@
--bin --bin-runtime --libraries linking_solidity_wrong_references/input.sol:L=0x12345678901234567890123456789012345678AB linking_solidity_wrong_references/input.sol:L1=0x12345678901234567890123456789012345678Ab linking_solidity_wrong_references/input.sol:L2=0x12345678901234567890123456789012345678A sol:L3=x12345678901234567890123456789012345678AB linking_solidity_wrong_references/input.sol:L4=012345678901234567890123456789012345678AB linking_solidity_wrong_references/input.sol:L5=0x linking_solidity_wrong_references/input.sol:L6=0x0

View File

@ -0,0 +1,42 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.0;
library L {
function f() external {}
}
library L1 {
function f() external {}
}
library L2 {
function f() external {}
}
library L3 {
function f() external {}
}
library L4 {
function f() external {}
}
library L5 {
function f() external {}
}
library L6 {
function f() external {}
}
contract C {
function foo() public {
L.f();
L1.f();
L2.f();
L3.f();
L4.f();
L5.f();
L6.f();
}
}

View File

@ -0,0 +1,62 @@
======= linking_solidity_wrong_references/input.sol:C =======
Binary:
<BYTECODE REMOVED>__$58d585080104a63ea16eac081c26fdeb7d$__<BYTECODE REMOVED>__$1618aeda50b2dcc26f161cca5d8e112b6f$__<BYTECODE REMOVED>__$265f2a239eabe0580e9e3f71486a88d62d$__<BYTECODE REMOVED>__$5c806807d1dd49cf7e0831ce4f7c3e225c$__<BYTECODE REMOVED>__$305390516cf3f93dc14e593f5c3a7ccd6a$__<BYTECODE REMOVED>__$23207ce64f0ebdd09636cf18c59a1ef8a8$__<BYTECODE REMOVED>
// $58d585080104a63ea16eac081c26fdeb7d$ -> linking_solidity_wrong_references/input.sol:L1
// $1618aeda50b2dcc26f161cca5d8e112b6f$ -> linking_solidity_wrong_references/input.sol:L2
// $265f2a239eabe0580e9e3f71486a88d62d$ -> linking_solidity_wrong_references/input.sol:L3
// $5c806807d1dd49cf7e0831ce4f7c3e225c$ -> linking_solidity_wrong_references/input.sol:L4
// $305390516cf3f93dc14e593f5c3a7ccd6a$ -> linking_solidity_wrong_references/input.sol:L5
// $23207ce64f0ebdd09636cf18c59a1ef8a8$ -> linking_solidity_wrong_references/input.sol:L6
Binary of the runtime part:
<BYTECODE REMOVED>__$58d585080104a63ea16eac081c26fdeb7d$__<BYTECODE REMOVED>__$1618aeda50b2dcc26f161cca5d8e112b6f$__<BYTECODE REMOVED>__$265f2a239eabe0580e9e3f71486a88d62d$__<BYTECODE REMOVED>__$5c806807d1dd49cf7e0831ce4f7c3e225c$__<BYTECODE REMOVED>__$305390516cf3f93dc14e593f5c3a7ccd6a$__<BYTECODE REMOVED>__$23207ce64f0ebdd09636cf18c59a1ef8a8$__<BYTECODE REMOVED>
// $58d585080104a63ea16eac081c26fdeb7d$ -> linking_solidity_wrong_references/input.sol:L1
// $1618aeda50b2dcc26f161cca5d8e112b6f$ -> linking_solidity_wrong_references/input.sol:L2
// $265f2a239eabe0580e9e3f71486a88d62d$ -> linking_solidity_wrong_references/input.sol:L3
// $5c806807d1dd49cf7e0831ce4f7c3e225c$ -> linking_solidity_wrong_references/input.sol:L4
// $305390516cf3f93dc14e593f5c3a7ccd6a$ -> linking_solidity_wrong_references/input.sol:L5
// $23207ce64f0ebdd09636cf18c59a1ef8a8$ -> linking_solidity_wrong_references/input.sol:L6
======= linking_solidity_wrong_references/input.sol:L =======
Binary:
<BYTECODE REMOVED>
Binary of the runtime part:
<BYTECODE REMOVED>
======= linking_solidity_wrong_references/input.sol:L1 =======
Binary:
<BYTECODE REMOVED>
Binary of the runtime part:
<BYTECODE REMOVED>
======= linking_solidity_wrong_references/input.sol:L2 =======
Binary:
<BYTECODE REMOVED>
Binary of the runtime part:
<BYTECODE REMOVED>
======= linking_solidity_wrong_references/input.sol:L3 =======
Binary:
<BYTECODE REMOVED>
Binary of the runtime part:
<BYTECODE REMOVED>
======= linking_solidity_wrong_references/input.sol:L4 =======
Binary:
<BYTECODE REMOVED>
Binary of the runtime part:
<BYTECODE REMOVED>
======= linking_solidity_wrong_references/input.sol:L5 =======
Binary:
<BYTECODE REMOVED>
Binary of the runtime part:
<BYTECODE REMOVED>
======= linking_solidity_wrong_references/input.sol:L6 =======
Binary:
<BYTECODE REMOVED>
Binary of the runtime part:
<BYTECODE REMOVED>

View File

@ -853,7 +853,7 @@ BOOST_AUTO_TEST_CASE(libraries_invalid_length)
}
)";
Json::Value result = compile(input);
BOOST_CHECK(containsError(result, "JSONError", "Library address is of invalid length."));
BOOST_CHECK(containsError(result, "JSONError", "Invalid library address length 2 instead of 40 characters."));
}
BOOST_AUTO_TEST_CASE(libraries_missing_hex_prefix)
@ -876,7 +876,32 @@ BOOST_AUTO_TEST_CASE(libraries_missing_hex_prefix)
}
)";
Json::Value result = compile(input);
BOOST_CHECK(containsError(result, "JSONError", "Library address is not prefixed with \"0x\"."));
BOOST_CHECK(containsError(result, "JSONError",
"Library address \"4200000000000000000000000000000000000001\" is not prefixed with \"0x\".\nNote that the address must be prefixed with \"0x\"."));
}
BOOST_AUTO_TEST_CASE(libraries_invalid_ckecsum)
{
char const* input = R"(
{
"language": "Solidity",
"settings": {
"libraries": {
"library.sol": {
"L": "0x42000000000000000000000000000000000000Ab"
}
}
},
"sources": {
"empty": {
"content": ""
}
}
}
)";
Json::Value result = compile(input);
BOOST_CHECK(containsError(result, "JSONError",
"Invalid checksum for library address \"0x42000000000000000000000000000000000000Ab\".\nThe correct checksum is \"0x42000000000000000000000000000000000000AB\"."));
}
BOOST_AUTO_TEST_CASE(library_linking)