diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index ea960bb70..2da69cd86 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -71,6 +71,7 @@ public: IRGenerationContext( langutil::EVMVersion _evmVersion, + std::optional _eofVersion, ExecutionContext _executionContext, RevertStrings _revertStrings, OptimiserSettings _optimiserSettings, @@ -79,6 +80,7 @@ public: langutil::CharStreamProvider const* _soliditySourceProvider ): m_evmVersion(_evmVersion), + m_eofVersion(_eofVersion), m_executionContext(_executionContext), m_revertStrings(_revertStrings), m_optimiserSettings(std::move(_optimiserSettings)), @@ -149,6 +151,7 @@ public: YulUtilFunctions utils(); langutil::EVMVersion evmVersion() const { return m_evmVersion; } + std::optional eofVersion() const { return m_eofVersion; } ExecutionContext executionContext() const { return m_executionContext; } void setArithmetic(Arithmetic _value) { m_arithmetic = _value; } @@ -182,6 +185,7 @@ public: private: langutil::EVMVersion m_evmVersion; + std::optional m_eofVersion; ExecutionContext m_executionContext; RevertStrings m_revertStrings; OptimiserSettings m_optimiserSettings; diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 371301804..a4988ea99 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -1110,6 +1110,7 @@ void IRGenerator::resetContext(ContractDefinition const& _contract, ExecutionCon ); IRGenerationContext newContext( m_evmVersion, + m_eofVersion, _context, m_context.revertStrings(), m_optimiserSettings, diff --git a/libsolidity/codegen/ir/IRGenerator.h b/libsolidity/codegen/ir/IRGenerator.h index 00387842e..b8bf7a1d6 100644 --- a/libsolidity/codegen/ir/IRGenerator.h +++ b/libsolidity/codegen/ir/IRGenerator.h @@ -58,6 +58,7 @@ public: m_optimiserSettings(_optimiserSettings), m_context( _evmVersion, + _eofVersion, ExecutionContext::Creation, _revertStrings, std::move(_optimiserSettings), diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 1ec64b548..2a48e8ff6 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -1483,10 +1483,21 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) m_context.subObjectsCreated().insert(contract); Whiskers t(R"(let := () - let := add(, datasize("")) - if or(gt(, 0xffffffffffffffff), lt(, )) { () } + let := add(, datasize("")) + if or(gt(, 0xffffffffffffffff), lt(, )) { () } datacopy(, dataoffset(""), datasize("")) - := () + let := () + + // TODO: this is horrible and hopefully avoided at the spec level + let := sub(, ) + let := shr(240, mload(add(, 7))) + let := add(, add(10, mul(, 2))) + let := mload() + let := shr(240, ) + := add(, ) + if gt(, 0xFFFF) { () } + mstore(, or(shr(16, shl(16, )), shl(240, ))) + let
:= create2(, , sub(, ), ) @@ -1498,7 +1509,17 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall) if iszero(
) { () } )"); + t("eof", m_context.eofVersion().has_value()); + if (m_context.eofVersion().has_value()) + { + t("argSize", m_context.newYulVariable()); + t("numCodeSections", m_context.newYulVariable()); + t("dataSectionOffset", m_context.newYulVariable()); + t("dataSectionSize", m_context.newYulVariable()); + t("tmp", m_context.newYulVariable()); + } t("memPos", m_context.newYulVariable()); + t("argPos", m_context.newYulVariable()); t("memEnd", m_context.newYulVariable()); t("allocateUnbounded", m_utils.allocateUnboundedFunction()); t("object", IRNames::creationObject(*contract)); diff --git a/test/libsolidity/semanticTests/salted_create/prediction_example.sol b/test/libsolidity/semanticTests/salted_create/prediction_example.sol index 1b138bdbb..fa24e3d50 100644 --- a/test/libsolidity/semanticTests/salted_create/prediction_example.sol +++ b/test/libsolidity/semanticTests/salted_create/prediction_example.sol @@ -5,14 +5,31 @@ contract D { } } +// TODO: this is horrible and hopefully avoided at the spec level +function adjustContractCodeForArgSize(bytes memory x, uint16 argSize) +{ + assembly { + let memPos := add(x, 32) + let numCodeSections := shr(240, mload(add(memPos, 7))) + let dataSectionSizeOffset := add(memPos, add(10, mul(numCodeSections, 2))) + let tmp := mload(dataSectionSizeOffset) + let dataSectionSize := shr(240, tmp) + dataSectionSize := add(dataSectionSize, argSize) + if gt(dataSectionSize, 0xFFFF) { revert(0,0) } + mstore(dataSectionSizeOffset, or(shr(16, shl(16, tmp)), shl(240, dataSectionSize))) + } +} + contract C { function createDSalted(bytes32 salt, uint arg) public { + bytes memory creationCode = type(D).creationCode; + adjustContractCodeForArgSize(creationCode, 32); address predictedAddress = address(uint160(uint(keccak256(abi.encodePacked( bytes1(0xff), address(this), salt, keccak256(abi.encodePacked( - type(D).creationCode, + creationCode, arg )) )))));