Use hash for library placeholders.

This commit is contained in:
chriseth 2018-10-04 14:55:02 +02:00
parent 5f5dc8956d
commit 6daeb39ecc
7 changed files with 69 additions and 9 deletions

View File

@ -17,6 +17,7 @@ Breaking Changes:
* Commandline interface: Remove obsolete ``--formal`` option. * Commandline interface: Remove obsolete ``--formal`` option.
* Commandline interface: Rename the ``--julia`` option to ``--yul``. * Commandline interface: Rename the ``--julia`` option to ``--yul``.
* Commandline interface: Require ``-`` if standard input is used as source. * Commandline interface: Require ``-`` if standard input is used as source.
* Commandline interface: Use hash of library name for link placeholder instead of name itself.
* Compiler interface: Disallow remappings with empty prefix. * Compiler interface: Disallow remappings with empty prefix.
* Control Flow Analyzer: Consider mappings as well when checking for uninitialized return values. * Control Flow Analyzer: Consider mappings as well when checking for uninitialized return values.
* Control Flow Analyzer: Turn warning about returning uninitialized storage pointers into an error. * Control Flow Analyzer: Turn warning about returning uninitialized storage pointers into an error.

View File

@ -21,6 +21,7 @@
#include <libevmasm/LinkerObject.h> #include <libevmasm/LinkerObject.h>
#include <libdevcore/CommonData.h> #include <libdevcore/CommonData.h>
#include <libdevcore/SHA3.h>
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
@ -50,14 +51,19 @@ string LinkerObject::toHex() const
for (auto const& ref: linkReferences) for (auto const& ref: linkReferences)
{ {
size_t pos = ref.first * 2; size_t pos = ref.first * 2;
string const& name = ref.second; string hash = libraryPlaceholder(ref.second);
hex[pos] = hex[pos + 1] = hex[pos + 38] = hex[pos + 39] = '_'; hex[pos] = hex[pos + 1] = hex[pos + 38] = hex[pos + 39] = '_';
for (size_t i = 0; i < 36; ++i) for (size_t i = 0; i < 36; ++i)
hex[pos + 2 + i] = i < name.size() ? name[i] : '_'; hex[pos + 2 + i] = hash.at(i);
} }
return hex; return hex;
} }
string LinkerObject::libraryPlaceholder(string const& _libraryName)
{
return keccak256(_libraryName).hex().substr(0, 36);
}
h160 const* h160 const*
LinkerObject::matchLibrary( LinkerObject::matchLibrary(
string const& _linkRefName, string const& _linkRefName,

View File

@ -50,6 +50,11 @@ struct LinkerObject
/// addresses by placeholders. /// addresses by placeholders.
std::string toHex() const; std::string toHex() const;
/// @returns a 36 character string that is used as a placeholder for the library
/// address (enclosed by `__` on both sides). The placeholder is the hex representation
/// of the first 18 bytes of the keccak-256 hash of @a _libraryName.
static std::string libraryPlaceholder(std::string const& _libraryName);
private: private:
static h160 const* matchLibrary( static h160 const* matchLibrary(
std::string const& _linkRefName, std::string const& _linkRefName,

View File

@ -226,21 +226,21 @@ void CommandLineInterface::handleBinary(string const& _contract)
if (m_args.count(g_argBinary)) if (m_args.count(g_argBinary))
{ {
if (m_args.count(g_argOutputDir)) if (m_args.count(g_argOutputDir))
createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin", m_compiler->object(_contract).toHex()); createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin", objectWithLinkRefsHex(m_compiler->object(_contract)));
else else
{ {
cout << "Binary: " << endl; cout << "Binary: " << endl;
cout << m_compiler->object(_contract).toHex() << endl; cout << objectWithLinkRefsHex(m_compiler->object(_contract)) << endl;
} }
} }
if (m_args.count(g_argBinaryRuntime)) if (m_args.count(g_argBinaryRuntime))
{ {
if (m_args.count(g_argOutputDir)) if (m_args.count(g_argOutputDir))
createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin-runtime", m_compiler->runtimeObject(_contract).toHex()); createFile(m_compiler->filesystemFriendlyName(_contract) + ".bin-runtime", objectWithLinkRefsHex(m_compiler->runtimeObject(_contract)));
else else
{ {
cout << "Binary of the runtime part: " << endl; cout << "Binary of the runtime part: " << endl;
cout << m_compiler->runtimeObject(_contract).toHex() << endl; cout << objectWithLinkRefsHex(m_compiler->runtimeObject(_contract)) << endl;
} }
} }
} }
@ -1056,8 +1056,12 @@ bool CommandLineInterface::link()
{ {
string const& name = library.first; string const& name = library.first;
// Library placeholders are 40 hex digits (20 bytes) that start and end with '__'. // Library placeholders are 40 hex digits (20 bytes) that start and end with '__'.
// This leaves 36 characters for the library name, while too short library names are // This leaves 36 characters for the library identifier. The identifier used to
// padded on the right with '_' and too long names are truncated. // be just the cropped or '_'-padded library name, but this changed to
// the cropped hex representation of the hash of the library name.
// We support both ways of linking here.
librariesReplacements["__" + eth::LinkerObject::libraryPlaceholder(name) + "__"] = library.second;
string replacement = "__"; string replacement = "__";
for (size_t i = 0; i < placeholderSize - 4; ++i) for (size_t i = 0; i < placeholderSize - 4; ++i)
replacement.push_back(i < name.size() ? name[i] : '_'); replacement.push_back(i < name.size() ? name[i] : '_');
@ -1087,6 +1091,11 @@ bool CommandLineInterface::link()
cerr << "Reference \"" << name << "\" in file \"" << src.first << "\" still unresolved." << endl; cerr << "Reference \"" << name << "\" in file \"" << src.first << "\" still unresolved." << endl;
it += placeholderSize; it += placeholderSize;
} }
// Remove hints for resolved libraries.
for (auto const& library: m_libraries)
boost::algorithm::erase_all(src.second, "\n" + libraryPlaceholderHint(library.first));
while (!src.second.empty() && *prev(src.second.end()) == '\n')
src.second.resize(src.second.size() - 1);
} }
return true; return true;
} }
@ -1100,6 +1109,23 @@ void CommandLineInterface::writeLinkedFiles()
writeFile(src.first, src.second); writeFile(src.first, src.second);
} }
string CommandLineInterface::libraryPlaceholderHint(string const& _libraryName)
{
return "// " + eth::LinkerObject::libraryPlaceholder(_libraryName) + " -> " + _libraryName;
}
string CommandLineInterface::objectWithLinkRefsHex(eth::LinkerObject const& _obj)
{
string out = _obj.toHex();
if (!_obj.linkReferences.empty())
{
out += "\n";
for (auto const& linkRef: _obj.linkReferences)
out += "\n" + libraryPlaceholderHint(linkRef.second);
}
return out;
}
bool CommandLineInterface::assemble( bool CommandLineInterface::assemble(
AssemblyStack::Language _language, AssemblyStack::Language _language,
AssemblyStack::Machine _targetMachine AssemblyStack::Machine _targetMachine

View File

@ -54,6 +54,10 @@ public:
private: private:
bool link(); bool link();
void writeLinkedFiles(); void writeLinkedFiles();
/// @returns the ``// <identifier> -> name`` hint for library placeholders.
static std::string libraryPlaceholderHint(std::string const& _libraryName);
/// @returns the full object with library placeholder hints in hex.
static std::string objectWithLinkRefsHex(eth::LinkerObject const& _obj);
bool assemble(AssemblyStack::Language _language, AssemblyStack::Machine _targetMachine); bool assemble(AssemblyStack::Language _language, AssemblyStack::Machine _targetMachine);

View File

@ -233,6 +233,24 @@ echo '' | "$SOLC" - --link --libraries a:0x90f20564390eAe531E810af625A22f51385Cd
printTask "Testing long library names..." printTask "Testing long library names..."
echo '' | "$SOLC" - --link --libraries aveeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeerylonglibraryname:0x90f20564390eAe531E810af625A22f51385Cd222 >/dev/null echo '' | "$SOLC" - --link --libraries aveeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeerylonglibraryname:0x90f20564390eAe531E810af625A22f51385Cd222 >/dev/null
printTask "Testing linking itself..."
SOLTMPDIR=$(mktemp -d)
(
cd "$SOLTMPDIR"
set -e
echo 'library L { function f() public pure {} } contract C { function f() public pure { L.f(); } }' > x.sol
"$SOLC" --bin -o . x.sol 2>/dev/null
# Explanation and placeholder should be there
grep -q '//' C.bin && grep -q '__' C.bin
# But not in library file.
grep -q -v '[/_]' L.bin
# Now link
"$SOLC" --link --libraries x.sol:L:0x90f20564390eAe531E810af625A22f51385Cd222 C.bin
# Now the placeholder and explanation should be gone.
grep -q -v '[/_]' C.bin
)
rm -rf "$SOLTMPDIR"
printTask "Testing overwriting files..." printTask "Testing overwriting files..."
SOLTMPDIR=$(mktemp -d) SOLTMPDIR=$(mktemp -d)
( (

View File

@ -94,7 +94,7 @@ BOOST_AUTO_TEST_CASE(all_assembly_items)
BOOST_CHECK_EQUAL( BOOST_CHECK_EQUAL(
_assembly.assemble().toHex(), _assembly.assemble().toHex(),
"5b6001600220606773__someLibrary___________________________" "5b6001600220606773__bf005014d9d0f534b8fcb268bd84c491a238__"
"6000567f556e75736564206665617475726520666f722070757368696e" "6000567f556e75736564206665617475726520666f722070757368696e"
"6720737472696e605f6001605e73000000000000000000000000000000000000000000fe" "6720737472696e605f6001605e73000000000000000000000000000000000000000000fe"
"fe010203044266eeaa" "fe010203044266eeaa"