diff options
-rw-r--r-- | libsolidity/Compiler.cpp | 11 | ||||
-rw-r--r-- | libsolidity/Compiler.h | 2 | ||||
-rw-r--r-- | libsolidity/CompilerUtils.cpp | 5 | ||||
-rw-r--r-- | libsolidity/CompilerUtils.h | 5 | ||||
-rw-r--r-- | libsolidity/ReferencesResolver.cpp | 54 | ||||
-rw-r--r-- | libsolidity/Types.cpp | 8 | ||||
-rw-r--r-- | libsolidity/Types.h | 3 |
7 files changed, 50 insertions, 38 deletions
diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 21eab230..1ef63bbf 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -252,7 +252,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) eth::AssemblyItem returnTag = m_context.pushNewTag(); fallback->accept(*this); m_context << returnTag; - appendReturnValuePacker(FunctionType(*fallback).returnParameterTypes()); + appendReturnValuePacker(FunctionType(*fallback).returnParameterTypes(), _contract.isLibrary()); } else m_context << eth::Instruction::STOP; // function not found @@ -268,7 +268,7 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) appendCalldataUnpacker(functionType->parameterTypes()); m_context.appendJumpTo(m_context.functionEntryLabel(functionType->declaration())); m_context << returnTag; - appendReturnValuePacker(functionType->returnParameterTypes()); + appendReturnValuePacker(functionType->returnParameterTypes(), _contract.isLibrary()); } } @@ -283,7 +283,7 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool for (TypePointer const& parameterType: _typeParameters) { // stack: v1 v2 ... v(k-1) base_offset current_offset - TypePointer type = parameterType->encodingType(); + TypePointer type = parameterType->decodingType(); if (type->category() == Type::Category::Array) { auto const& arrayType = dynamic_cast<ArrayType const&>(*type); @@ -340,7 +340,6 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool CompilerUtils(m_context).moveToStackTop(1 + arrayType.sizeOnStack()); m_context << eth::Instruction::SWAP1; } - break; } else { @@ -354,7 +353,7 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool m_context << eth::Instruction::POP << eth::Instruction::POP; } -void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters) +void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary) { CompilerUtils utils(m_context); if (_typeParameters.empty()) @@ -364,7 +363,7 @@ void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters) utils.fetchFreeMemoryPointer(); //@todo optimization: if we return a single memory array, there should be enough space before // its data to add the needed parts and we avoid a memory copy. - utils.encodeToMemory(_typeParameters, _typeParameters); + utils.encodeToMemory(_typeParameters, _typeParameters, true, false, _isLibrary); utils.toSizeAfterFreeMemoryPointer(); m_context << eth::Instruction::RETURN; } diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index c3bb838a..3cf1004a 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -87,7 +87,7 @@ private: /// From memory if @a _fromMemory is true, otherwise from call data. /// Expects source offset on the stack, which is removed. void appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory = false); - void appendReturnValuePacker(TypePointers const& _typeParameters); + void appendReturnValuePacker(TypePointers const& _typeParameters, bool _isLibrary); void registerStateVariables(ContractDefinition const& _contract); void initializeStateVariables(ContractDefinition const& _contract); diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index 31000f0b..583d267a 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -153,14 +153,15 @@ void CompilerUtils::encodeToMemory( TypePointers const& _givenTypes, TypePointers const& _targetTypes, bool _padToWordBoundaries, - bool _copyDynamicDataInPlace + bool _copyDynamicDataInPlace, + bool _encodeAsLibraryTypes ) { // stack: <v1> <v2> ... <vn> <mem> TypePointers targetTypes = _targetTypes.empty() ? _givenTypes : _targetTypes; solAssert(targetTypes.size() == _givenTypes.size(), ""); for (TypePointer& t: targetTypes) - t = t->mobileType()->encodingType(); + t = t->mobileType()->interfaceType(_encodeAsLibraryTypes)->encodingType(); // Stack during operation: // <v1> <v2> ... <vn> <mem_start> <dyn_head_1> ... <dyn_head_r> <end_of_mem> diff --git a/libsolidity/CompilerUtils.h b/libsolidity/CompilerUtils.h index 568a6307..f335eed5 100644 --- a/libsolidity/CompilerUtils.h +++ b/libsolidity/CompilerUtils.h @@ -91,13 +91,16 @@ public: /// @param _padToWordBoundaries if false, all values are concatenated without padding. /// @param _copyDynamicDataInPlace if true, dynamic types is stored (without length) /// together with fixed-length data. + /// @param _encodeAsLibraryTypes if true, encodes for a library function, e.g. does not + /// convert storage pointer types to memory types. /// @note the locations of target reference types are ignored, because it will always be /// memory. void encodeToMemory( TypePointers const& _givenTypes = {}, TypePointers const& _targetTypes = {}, bool _padToWordBoundaries = true, - bool _copyDynamicDataInPlace = false + bool _copyDynamicDataInPlace = false, + bool _encodeAsLibraryTypes = false ); /// Uses a CALL to the identity contract to perform a memory-to-memory copy. diff --git a/libsolidity/ReferencesResolver.cpp b/libsolidity/ReferencesResolver.cpp index cb34c47e..f60ca1af 100644 --- a/libsolidity/ReferencesResolver.cpp +++ b/libsolidity/ReferencesResolver.cpp @@ -109,42 +109,40 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable) // As an exception, "storage" is allowed for library functions. if (auto ref = dynamic_cast<ReferenceType const*>(type.get())) { - if (_variable.isCallableParameter()) + if (_variable.isExternalCallableParameter()) { auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope()); - if (_variable.isExternalCallableParameter()) + if (contract.isLibrary()) { - if (contract.isLibrary()) - { - if (loc == Location::Memory) - BOOST_THROW_EXCEPTION(_variable.createTypeError( - "Location has to be calldata or storage for external " - "library functions (remove the \"memory\" keyword)." - )); - } - else - { - // force location of external function parameters (not return) to calldata - if (loc != Location::Default) - BOOST_THROW_EXCEPTION(_variable.createTypeError( - "Location has to be calldata for external functions " - "(remove the \"memory\" or \"storage\" keyword)." - )); - } - if (loc == Location::Default) - type = ref->copyForLocation(DataLocation::CallData, true); + if (loc == Location::Memory) + BOOST_THROW_EXCEPTION(_variable.createTypeError( + "Location has to be calldata or storage for external " + "library functions (remove the \"memory\" keyword)." + )); } - else if (_variable.isCallableParameter() && _variable.scope()->isPublic()) + else { - // force locations of public or external function (return) parameters to memory - if (loc == Location::Storage && !contract.isLibrary()) + // force location of external function parameters (not return) to calldata + if (loc != Location::Default) BOOST_THROW_EXCEPTION(_variable.createTypeError( - "Location has to be memory for publicly visible functions " - "(remove the \"storage\" keyword)." + "Location has to be calldata for external functions " + "(remove the \"memory\" or \"storage\" keyword)." )); - if (loc == Location::Default) - type = ref->copyForLocation(DataLocation::Memory, true); } + if (loc == Location::Default) + type = ref->copyForLocation(DataLocation::CallData, true); + } + else if (_variable.isCallableParameter() && _variable.scope()->isPublic()) + { + auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope()); + // force locations of public or external function (return) parameters to memory + if (loc == Location::Storage && !contract.isLibrary()) + BOOST_THROW_EXCEPTION(_variable.createTypeError( + "Location has to be memory for publicly visible functions " + "(remove the \"storage\" keyword)." + )); + if (loc == Location::Default || !contract.isLibrary()) + type = ref->copyForLocation(DataLocation::Memory, true); } else { diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index f7e67696..faac2447 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -847,6 +847,14 @@ TypePointer ArrayType::encodingType() const return this->copyForLocation(DataLocation::Memory, true); } +TypePointer ArrayType::decodingType() const +{ + if (location() == DataLocation::Storage) + return make_shared<IntegerType>(256); + else + return shared_from_this(); +} + TypePointer ArrayType::interfaceType(bool _inLibrary) const { if (_inLibrary && location() == DataLocation::Storage) diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 972876e9..09654bfe 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -230,6 +230,8 @@ public: /// This for example returns address for contract types. /// If there is no such type, returns an empty shared pointer. virtual TypePointer encodingType() const { return TypePointer(); } + /// @returns a (simpler) type that is used when decoding this type in calldata. + virtual TypePointer decodingType() const { return encodingType(); } /// @returns a type that will be used outside of Solidity for e.g. function signatures. /// This for example returns address for contract types. /// If there is no such type, returns an empty shared pointer. @@ -504,6 +506,7 @@ public: return isString() ? EmptyMemberList : s_arrayTypeMemberList; } virtual TypePointer encodingType() const override; + virtual TypePointer decodingType() const override; virtual TypePointer interfaceType(bool _inLibrary) const override; /// @returns true if this is a byte array or a string |