diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index f18c618e9..cabddc143 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -31,6 +31,7 @@ #include +#include #include #include @@ -888,31 +889,11 @@ std::variant 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 addrResult = util::validateAddress(addrString); + if (!addrResult.message().empty()) + return formatFatalError(Error::Type::JSONError, addrResult.message()); + ret.libraries[sourceName + ":" + library] = addrResult.get(); } } diff --git a/libsolutil/Address.cpp b/libsolutil/Address.cpp new file mode 100644 index 000000000..d0ddadf90 --- /dev/null +++ b/libsolutil/Address.cpp @@ -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 . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#include +#include + +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 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::err(message); + + return address; +} + +} diff --git a/libsolutil/Address.h b/libsolutil/Address.h new file mode 100644 index 000000000..53028fd6e --- /dev/null +++ b/libsolutil/Address.h @@ -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 . +*/ +// SPDX-License-Identifier: GPL-3.0 + +#pragma once + +#include +#include +#include + +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 validateAddress(std::string _addrString); + +} diff --git a/libsolutil/CMakeLists.txt b/libsolutil/CMakeLists.txt index b368e12f9..c8b406726 100644 --- a/libsolutil/CMakeLists.txt +++ b/libsolutil/CMakeLists.txt @@ -1,4 +1,6 @@ set(sources + Address.cpp + Address.h Algorithms.h AnsiColorized.h Assertions.h diff --git a/solc/CommandLineParser.cpp b/solc/CommandLineParser.cpp index aab6b6710..53974c21f 100644 --- a/solc/CommandLineParser.cpp +++ b/solc/CommandLineParser.cpp @@ -24,6 +24,8 @@ #include +#include + #include #include @@ -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 addrResult = util::validateAddress(addrString); + if (!addrResult.message().empty()) + solThrow(CommandLineValidationError, "Library \"" + libName + "\": " + addrResult.message()); + m_options.linker.libraries[libName] = addrResult.get(); } } diff --git a/test/cmdlineTests/linking_solidity_wrong_references/args b/test/cmdlineTests/linking_solidity_wrong_references/args new file mode 100644 index 000000000..95f13b799 --- /dev/null +++ b/test/cmdlineTests/linking_solidity_wrong_references/args @@ -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 diff --git a/test/cmdlineTests/linking_solidity_wrong_references/input.sol b/test/cmdlineTests/linking_solidity_wrong_references/input.sol new file mode 100644 index 000000000..d8a2f8305 --- /dev/null +++ b/test/cmdlineTests/linking_solidity_wrong_references/input.sol @@ -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(); + } +} diff --git a/test/cmdlineTests/linking_solidity_wrong_references/output b/test/cmdlineTests/linking_solidity_wrong_references/output new file mode 100644 index 000000000..99c0c552c --- /dev/null +++ b/test/cmdlineTests/linking_solidity_wrong_references/output @@ -0,0 +1,62 @@ + +======= linking_solidity_wrong_references/input.sol:C ======= +Binary: +__$58d585080104a63ea16eac081c26fdeb7d$____$1618aeda50b2dcc26f161cca5d8e112b6f$____$265f2a239eabe0580e9e3f71486a88d62d$____$5c806807d1dd49cf7e0831ce4f7c3e225c$____$305390516cf3f93dc14e593f5c3a7ccd6a$____$23207ce64f0ebdd09636cf18c59a1ef8a8$__ + +// $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: +__$58d585080104a63ea16eac081c26fdeb7d$____$1618aeda50b2dcc26f161cca5d8e112b6f$____$265f2a239eabe0580e9e3f71486a88d62d$____$5c806807d1dd49cf7e0831ce4f7c3e225c$____$305390516cf3f93dc14e593f5c3a7ccd6a$____$23207ce64f0ebdd09636cf18c59a1ef8a8$__ + +// $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: + +Binary of the runtime part: + + +======= linking_solidity_wrong_references/input.sol:L1 ======= +Binary: + +Binary of the runtime part: + + +======= linking_solidity_wrong_references/input.sol:L2 ======= +Binary: + +Binary of the runtime part: + + +======= linking_solidity_wrong_references/input.sol:L3 ======= +Binary: + +Binary of the runtime part: + + +======= linking_solidity_wrong_references/input.sol:L4 ======= +Binary: + +Binary of the runtime part: + + +======= linking_solidity_wrong_references/input.sol:L5 ======= +Binary: + +Binary of the runtime part: + + +======= linking_solidity_wrong_references/input.sol:L6 ======= +Binary: + +Binary of the runtime part: + diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index 785f14284..ff0ad3952 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -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)