From 8c1d928c944b70cf7318d8277cdfbf2ef0421857 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 3 Feb 2015 14:02:58 +0100 Subject: [PATCH 1/8] Solidity SHA3 can now take multiple arguments --- AST.cpp | 19 ++++++++++++++++--- ExpressionCompiler.cpp | 23 ++++++++++++++++++----- ExpressionCompiler.h | 8 +++++--- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/AST.cpp b/AST.cpp index d1c7d5371..c4fd7e2dd 100644 --- a/AST.cpp +++ b/AST.cpp @@ -487,14 +487,27 @@ void FunctionCall::checkTypeRequirements() // and then ask if that is implicitly convertible to the struct represented by the // function parameters TypePointers const& parameterTypes = functionType->getParameterTypes(); - if (parameterTypes.size() != m_arguments.size()) + if (functionType->getLocation() !=FunctionType::Location::SHA3 && parameterTypes.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); - if (m_names.empty()) + if (m_names.empty()) // LTODO: Totally ignoring sha3 case for named arguments for now just for the rebase to work { for (size_t i = 0; i < m_arguments.size(); ++i) - if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) + { + if (functionType->getLocation() == FunctionType::Location::SHA3) + { +#if 0 // are we sure we want that? Literal constant nums can't live outside storage and so sha3(42) will fail + if (!m_arguments[i]->getType()->canLiveOutsideStorage()) + BOOST_THROW_EXCEPTION(createTypeError("SHA3 called with argument that can't live outside storage")); +#endif + if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[0])) + BOOST_THROW_EXCEPTION(createTypeError(std::string("SHA3 argument ") + + boost::lexical_cast(i) + + std::string("can't be converted to hash"))); + + } else if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call.")); + } } else { diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 875e00bc2..8672611a4 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -206,7 +206,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) TypePointers const& parameterTypes = function.getParameterTypes(); vector> const& callArguments = _functionCall.getArguments(); vector> const& callArgumentNames = _functionCall.getNames(); - solAssert(callArguments.size() == parameterTypes.size(), ""); + if (function.getLocation() != Location::SHA3) + solAssert(callArguments.size() == parameterTypes.size(), ""); vector> arguments; if (callArgumentNames.empty()) @@ -325,9 +326,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << eth::Instruction::SUICIDE; break; case Location::SHA3: - appendExpressionCopyToMemory(*function.getParameterTypes().front(), *arguments.front()); - m_context << u256(32) << u256(0) << eth::Instruction::SHA3; + { + unsigned length = appendSameTypeArgumentsCopyToMemory(function.getParameterTypes().front(), arguments, 0); + m_context << u256(length) << u256(0) << eth::Instruction::SHA3; break; + } case Location::LOG0: case Location::LOG1: case Location::LOG2: @@ -843,8 +846,18 @@ unsigned ExpressionCompiler::appendArgumentCopyToMemory(TypePointers const& _typ return length; } -unsigned ExpressionCompiler::appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, - Location const& _location, unsigned _memoryOffset) +unsigned ExpressionCompiler::appendSameTypeArgumentsCopyToMemory(TypePointer const& _type, + vector> const& _arguments, + unsigned _memoryOffset) +{ + unsigned length = 0; + for (unsigned i = 0; i < _arguments.size(); ++i) + length += appendExpressionCopyToMemory(*_type, *_arguments[i], _memoryOffset + length); + return length; +} + +unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, + Expression const& _expression, unsigned _memoryOffset) { appendTypeConversion(_type, _expectedType, true); unsigned const c_numBytes = CompilerUtils::getPaddedSize(_expectedType.getCalldataEncodedSize()); diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index 7de577e6c..b977657b1 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -97,10 +97,12 @@ private: unsigned appendArgumentCopyToMemory(TypePointers const& _types, std::vector> const& _arguments, unsigned _memoryOffset = 0); - /// Appends code that copies a type to memory. + /// Appends code that copies the given arguments that should all have the + /// same @a _type to memory (with optional offset). /// @returns the number of bytes copied to memory - unsigned appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, - Location const& _location, unsigned _memoryOffset = 0); + unsigned appendSameTypeArgumentsCopyToMemory(TypePointer const& _type, + std::vector> const& _arguments, + unsigned _memoryOffset = 0); /// Appends code that evaluates a single expression and copies it to memory (with optional offset). /// @returns the number of bytes copied to memory unsigned appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression, From f09c6fffc9f55b5208560d6550134bf854970db8 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Tue, 3 Feb 2015 14:21:08 +0100 Subject: [PATCH 2/8] Renaming a function for clarity --- AST.cpp | 2 +- ExpressionCompiler.cpp | 10 +++++----- ExpressionCompiler.h | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/AST.cpp b/AST.cpp index c4fd7e2dd..39ba10f32 100644 --- a/AST.cpp +++ b/AST.cpp @@ -502,7 +502,7 @@ void FunctionCall::checkTypeRequirements() #endif if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[0])) BOOST_THROW_EXCEPTION(createTypeError(std::string("SHA3 argument ") + - boost::lexical_cast(i) + + boost::lexical_cast(i + 1) + std::string("can't be converted to hash"))); } else if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 8672611a4..0acc9c9ed 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -275,7 +275,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << u256(0) << eth::Instruction::CODECOPY; unsigned length = bytecode.size(); - length += appendArgumentCopyToMemory(function.getParameterTypes(), arguments, length); + length += appendArgumentsCopyToMemory(function.getParameterTypes(), arguments, length); // size, offset, endowment m_context << u256(length) << u256(0); if (function.valueSet()) @@ -800,7 +800,7 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio // reserve space for the function identifier unsigned dataOffset = bare ? 0 : CompilerUtils::dataStartOffset; - dataOffset += appendArgumentCopyToMemory(_functionType.getParameterTypes(), _arguments, dataOffset); + dataOffset += appendArgumentsCopyToMemory(_functionType.getParameterTypes(), _arguments, dataOffset); //@todo only return the first return value for now Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr : @@ -836,9 +836,9 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio } } -unsigned ExpressionCompiler::appendArgumentCopyToMemory(TypePointers const& _types, - vector> const& _arguments, - unsigned _memoryOffset) +unsigned ExpressionCompiler::appendArgumentsCopyToMemory(TypePointers const& _types, + vector> const& _arguments, + unsigned _memoryOffset) { unsigned length = 0; for (unsigned i = 0; i < _arguments.size(); ++i) diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index b977657b1..1f42d8225 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -94,9 +94,9 @@ private: bool bare = false); /// Appends code that copies the given arguments to memory (with optional offset). /// @returns the number of bytes copied to memory - unsigned appendArgumentCopyToMemory(TypePointers const& _types, - std::vector> const& _arguments, - unsigned _memoryOffset = 0); + unsigned appendArgumentsCopyToMemory(TypePointers const& _types, + std::vector> const& _arguments, + unsigned _memoryOffset = 0); /// Appends code that copies the given arguments that should all have the /// same @a _type to memory (with optional offset). /// @returns the number of bytes copied to memory From 337b952f53d4eb24e6ae28386f26b4f69a33d935 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 5 Feb 2015 15:05:58 +0100 Subject: [PATCH 3/8] Fixes after rebase --- AST.cpp | 2 +- ExpressionCompiler.cpp | 4 ++-- ExpressionCompiler.h | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/AST.cpp b/AST.cpp index 39ba10f32..f2fbc5284 100644 --- a/AST.cpp +++ b/AST.cpp @@ -487,7 +487,7 @@ void FunctionCall::checkTypeRequirements() // and then ask if that is implicitly convertible to the struct represented by the // function parameters TypePointers const& parameterTypes = functionType->getParameterTypes(); - if (functionType->getLocation() !=FunctionType::Location::SHA3 && parameterTypes.size() != m_arguments.size()) + if (functionType->getLocation() != FunctionType::Location::SHA3 && parameterTypes.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); if (m_names.empty()) // LTODO: Totally ignoring sha3 case for named arguments for now just for the rebase to work diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 0acc9c9ed..e2c632a3c 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -856,8 +856,8 @@ unsigned ExpressionCompiler::appendSameTypeArgumentsCopyToMemory(TypePointer con return length; } -unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, - Expression const& _expression, unsigned _memoryOffset) +unsigned ExpressionCompiler::appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, + Location const& _location, unsigned _memoryOffset) { appendTypeConversion(_type, _expectedType, true); unsigned const c_numBytes = CompilerUtils::getPaddedSize(_expectedType.getCalldataEncodedSize()); diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index 1f42d8225..90a60afc7 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -97,6 +97,10 @@ private: unsigned appendArgumentsCopyToMemory(TypePointers const& _types, std::vector> const& _arguments, unsigned _memoryOffset = 0); + /// Appends code that copies a type to memory. + /// @returns the number of bytes copied to memory + unsigned appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, + Location const& _location, unsigned _memoryOffset = 0); /// Appends code that copies the given arguments that should all have the /// same @a _type to memory (with optional offset). /// @returns the number of bytes copied to memory From 76c9f13626495e173ddf3fde301c526097f08651 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 6 Feb 2015 10:42:24 +0100 Subject: [PATCH 4/8] appendArgumentsCopyToMemory() has more complicated logic now - Plus other fixes. --- AST.cpp | 8 +++---- ExpressionCompiler.cpp | 48 ++++++++++++++++++++++++------------------ ExpressionCompiler.h | 11 ++++------ 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/AST.cpp b/AST.cpp index f2fbc5284..c0a120b82 100644 --- a/AST.cpp +++ b/AST.cpp @@ -490,7 +490,7 @@ void FunctionCall::checkTypeRequirements() if (functionType->getLocation() != FunctionType::Location::SHA3 && parameterTypes.size() != m_arguments.size()) BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); - if (m_names.empty()) // LTODO: Totally ignoring sha3 case for named arguments for now just for the rebase to work + if (m_names.empty()) { for (size_t i = 0; i < m_arguments.size(); ++i) { @@ -501,14 +501,14 @@ void FunctionCall::checkTypeRequirements() BOOST_THROW_EXCEPTION(createTypeError("SHA3 called with argument that can't live outside storage")); #endif if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[0])) - BOOST_THROW_EXCEPTION(createTypeError(std::string("SHA3 argument ") + - boost::lexical_cast(i + 1) + - std::string("can't be converted to hash"))); + BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError("SHA3 argument can't be converted to hash")); } else if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call.")); } } + else if (functionType->getLocation() == FunctionType::Location::SHA3) + BOOST_THROW_EXCEPTION(createTypeError("Named arguments can't be used for SHA3.")); else { auto const& parameterNames = functionType->getParameterNames(); diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index e2c632a3c..fbf5cbcfd 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -275,7 +275,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) m_context << u256(0) << eth::Instruction::CODECOPY; unsigned length = bytecode.size(); - length += appendArgumentsCopyToMemory(function.getParameterTypes(), arguments, length); + length += appendArgumentsCopyToMemory(arguments, function.getParameterTypes(), length); // size, offset, endowment m_context << u256(length) << u256(0); if (function.valueSet()) @@ -327,7 +327,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) break; case Location::SHA3: { - unsigned length = appendSameTypeArgumentsCopyToMemory(function.getParameterTypes().front(), arguments, 0); + unsigned length = appendArgumentsCopyToMemory(arguments); m_context << u256(length) << u256(0) << eth::Instruction::SHA3; break; } @@ -800,7 +800,7 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio // reserve space for the function identifier unsigned dataOffset = bare ? 0 : CompilerUtils::dataStartOffset; - dataOffset += appendArgumentsCopyToMemory(_functionType.getParameterTypes(), _arguments, dataOffset); + dataOffset += appendArgumentsCopyToMemory(_arguments, _functionType.getParameterTypes(), dataOffset); //@todo only return the first return value for now Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr : @@ -836,38 +836,44 @@ void ExpressionCompiler::appendExternalFunctionCall(FunctionType const& _functio } } -unsigned ExpressionCompiler::appendArgumentsCopyToMemory(TypePointers const& _types, - vector> const& _arguments, +unsigned ExpressionCompiler::appendArgumentsCopyToMemory(vector> const& _arguments, + TypePointers const& _types, unsigned _memoryOffset) { unsigned length = 0; + if (!_types.empty()) + { + for (unsigned i = 0; i < _arguments.size(); ++i) + length += appendExpressionCopyToMemory(*_types[i], *_arguments[i], _memoryOffset + length); + return length; + } + + // without type conversion for (unsigned i = 0; i < _arguments.size(); ++i) - length += appendExpressionCopyToMemory(*_types[i], *_arguments[i], _memoryOffset + length); + { + _arguments[i]->accept(*this); + length += moveTypeToMemory(*_arguments[i]->getType(), _arguments[i]->getLocation(), _memoryOffset + length); + } return length; } -unsigned ExpressionCompiler::appendSameTypeArgumentsCopyToMemory(TypePointer const& _type, - vector> const& _arguments, - unsigned _memoryOffset) +unsigned ExpressionCompiler::moveTypeToMemory(Type const& _type, Location const& _location, unsigned _memoryOffset) { - unsigned length = 0; - for (unsigned i = 0; i < _arguments.size(); ++i) - length += appendExpressionCopyToMemory(*_type, *_arguments[i], _memoryOffset + length); - return length; + unsigned const c_numBytes = CompilerUtils::getPaddedSize(_type.getCalldataEncodedSize()); + if (c_numBytes == 0 || c_numBytes > 32) + BOOST_THROW_EXCEPTION(CompilerError() + << errinfo_sourceLocation(_location) + << errinfo_comment("Type " + _type.toString() + " not yet supported.")); + bool const c_leftAligned = _type.getCategory() == Type::Category::STRING; + bool const c_padToWords = true; + return CompilerUtils(m_context).storeInMemory(_memoryOffset, c_numBytes, c_leftAligned, c_padToWords); } unsigned ExpressionCompiler::appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, Location const& _location, unsigned _memoryOffset) { appendTypeConversion(_type, _expectedType, true); - unsigned const c_numBytes = CompilerUtils::getPaddedSize(_expectedType.getCalldataEncodedSize()); - if (c_numBytes == 0 || c_numBytes > 32) - BOOST_THROW_EXCEPTION(CompilerError() - << errinfo_sourceLocation(_location) - << errinfo_comment("Type " + _expectedType.toString() + " not yet supported.")); - bool const c_leftAligned = _expectedType.getCategory() == Type::Category::STRING; - bool const c_padToWords = true; - return CompilerUtils(m_context).storeInMemory(_memoryOffset, c_numBytes, c_leftAligned, c_padToWords); + return moveTypeToMemory(_expectedType, _location, _memoryOffset); } unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedType, diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index 90a60afc7..70cc2426b 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -94,19 +94,16 @@ private: bool bare = false); /// Appends code that copies the given arguments to memory (with optional offset). /// @returns the number of bytes copied to memory - unsigned appendArgumentsCopyToMemory(TypePointers const& _types, - std::vector> const& _arguments, + unsigned appendArgumentsCopyToMemory(std::vector> const& _arguments, + TypePointers const& _types = {}, unsigned _memoryOffset = 0); /// Appends code that copies a type to memory. /// @returns the number of bytes copied to memory unsigned appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, Location const& _location, unsigned _memoryOffset = 0); - /// Appends code that copies the given arguments that should all have the - /// same @a _type to memory (with optional offset). + /// Appends code that moves a type to memory /// @returns the number of bytes copied to memory - unsigned appendSameTypeArgumentsCopyToMemory(TypePointer const& _type, - std::vector> const& _arguments, - unsigned _memoryOffset = 0); + unsigned moveTypeToMemory(Type const& _type, Location const& _location, unsigned _memoryOffset); /// Appends code that evaluates a single expression and copies it to memory (with optional offset). /// @returns the number of bytes copied to memory unsigned appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression, From 2c9ff4747d81a34125e976a65d6eca8cb5349c9d Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 6 Feb 2015 13:42:51 +0100 Subject: [PATCH 5/8] getRealType() introduced --- ExpressionCompiler.cpp | 2 +- Types.cpp | 8 ++++++++ Types.h | 6 +++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index fbf5cbcfd..39593a6ed 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -852,7 +852,7 @@ unsigned ExpressionCompiler::appendArgumentsCopyToMemory(vectoraccept(*this); - length += moveTypeToMemory(*_arguments[i]->getType(), _arguments[i]->getLocation(), _memoryOffset + length); + length += moveTypeToMemory(*_arguments[i]->getType()->getRealType(), _arguments[i]->getLocation(), _memoryOffset + length); } return length; } diff --git a/Types.cpp b/Types.cpp index 648cf9cb2..a9051a2ca 100644 --- a/Types.cpp +++ b/Types.cpp @@ -361,6 +361,14 @@ u256 IntegerConstantType::literalValue(Literal const* _literal) const return value; } +TypePointer IntegerConstantType::getRealType() const +{ + auto intType = getIntegerType(); + if (!intType) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("getRealType called with invalid integer constant" + toString())); + return intType; +} + shared_ptr IntegerConstantType::getIntegerType() const { bigint value = m_value; diff --git a/Types.h b/Types.h index 1f4d27a25..18a53f9a5 100644 --- a/Types.h +++ b/Types.h @@ -130,6 +130,8 @@ public: /// i.e. it behaves differently in lvalue context and in value context. virtual bool isValueType() const { return false; } virtual unsigned getSizeOnStack() const { return 1; } + /// @returns the real type of some types, like e.g: IntegerConstant + virtual TypePointer getRealType() const { return TypePointer(); } /// Returns the list of all members of this type. Default implementation: no members. virtual MemberList const& getMembers() const { return EmptyMemberList; } @@ -140,7 +142,7 @@ public: virtual u256 literalValue(Literal const*) const { BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Literal value requested " - "for type without literals.")); + "for type without literals.")); } protected: @@ -175,6 +177,7 @@ public: virtual MemberList const& getMembers() const { return isAddress() ? AddressMemberList : EmptyMemberList; } virtual std::string toString() const override; + virtual TypePointer getRealType() const { return std::make_shared(m_bits, m_modifier); } int getNumBits() const { return m_bits; } bool isHash() const { return m_modifier == Modifier::HASH || m_modifier == Modifier::ADDRESS; } @@ -214,6 +217,7 @@ public: virtual std::string toString() const override; virtual u256 literalValue(Literal const* _literal) const override; + virtual TypePointer getRealType() const override; /// @returns the smallest integer type that can hold the value or an empty pointer if not possible. std::shared_ptr getIntegerType() const; From 293344b4733e2de8f9159f3b73bbdd6e4a475195 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 6 Feb 2015 16:27:41 +0100 Subject: [PATCH 6/8] SHA3 of string literals now should work --- AST.cpp | 14 ++------------ ExpressionCompiler.cpp | 11 ++++++----- ExpressionCompiler.h | 2 +- Types.h | 1 + 4 files changed, 10 insertions(+), 18 deletions(-) diff --git a/AST.cpp b/AST.cpp index c0a120b82..26897ddae 100644 --- a/AST.cpp +++ b/AST.cpp @@ -493,19 +493,9 @@ void FunctionCall::checkTypeRequirements() if (m_names.empty()) { for (size_t i = 0; i < m_arguments.size(); ++i) - { - if (functionType->getLocation() == FunctionType::Location::SHA3) - { -#if 0 // are we sure we want that? Literal constant nums can't live outside storage and so sha3(42) will fail - if (!m_arguments[i]->getType()->canLiveOutsideStorage()) - BOOST_THROW_EXCEPTION(createTypeError("SHA3 called with argument that can't live outside storage")); -#endif - if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[0])) - BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError("SHA3 argument can't be converted to hash")); - - } else if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) + if (functionType->getLocation() != FunctionType::Location::SHA3 && + !m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i])) BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call.")); - } } else if (functionType->getLocation() == FunctionType::Location::SHA3) BOOST_THROW_EXCEPTION(createTypeError("Named arguments can't be used for SHA3.")); diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 39593a6ed..4f091db4c 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -851,22 +851,23 @@ unsigned ExpressionCompiler::appendArgumentsCopyToMemory(vectorgetType()->getCategory() == Type::Category::STRING) ? false : true; _arguments[i]->accept(*this); - length += moveTypeToMemory(*_arguments[i]->getType()->getRealType(), _arguments[i]->getLocation(), _memoryOffset + length); + length += moveTypeToMemory(*_arguments[i]->getType()->getRealType(), _arguments[i]->getLocation(), _memoryOffset + length, wantPadding); } return length; } -unsigned ExpressionCompiler::moveTypeToMemory(Type const& _type, Location const& _location, unsigned _memoryOffset) +unsigned ExpressionCompiler::moveTypeToMemory(Type const& _type, Location const& _location, unsigned _memoryOffset, bool _padToWordBoundaries) { - unsigned const c_numBytes = CompilerUtils::getPaddedSize(_type.getCalldataEncodedSize()); + unsigned const encodedSize = _type.getCalldataEncodedSize(); + unsigned const c_numBytes = _padToWordBoundaries ? CompilerUtils::getPaddedSize(encodedSize) : encodedSize; if (c_numBytes == 0 || c_numBytes > 32) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location) << errinfo_comment("Type " + _type.toString() + " not yet supported.")); bool const c_leftAligned = _type.getCategory() == Type::Category::STRING; - bool const c_padToWords = true; - return CompilerUtils(m_context).storeInMemory(_memoryOffset, c_numBytes, c_leftAligned, c_padToWords); + return CompilerUtils(m_context).storeInMemory(_memoryOffset, c_numBytes, c_leftAligned, _padToWordBoundaries); } unsigned ExpressionCompiler::appendTypeConversionAndMoveToMemory(Type const& _expectedType, Type const& _type, diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h index 70cc2426b..006858cb8 100644 --- a/ExpressionCompiler.h +++ b/ExpressionCompiler.h @@ -103,7 +103,7 @@ private: Location const& _location, unsigned _memoryOffset = 0); /// Appends code that moves a type to memory /// @returns the number of bytes copied to memory - unsigned moveTypeToMemory(Type const& _type, Location const& _location, unsigned _memoryOffset); + unsigned moveTypeToMemory(Type const& _type, Location const& _location, unsigned _memoryOffset, bool _padToWordBoundaries = true); /// Appends code that evaluates a single expression and copies it to memory (with optional offset). /// @returns the number of bytes copied to memory unsigned appendExpressionCopyToMemory(Type const& _expectedType, Expression const& _expression, diff --git a/Types.h b/Types.h index 18a53f9a5..677e5e49e 100644 --- a/Types.h +++ b/Types.h @@ -249,6 +249,7 @@ public: virtual std::string toString() const override { return "string" + dev::toString(m_bytes); } virtual u256 literalValue(Literal const* _literal) const override; + virtual TypePointer getRealType() const override { return std::make_shared(m_bytes); } int getNumBytes() const { return m_bytes; } From f6586b81398d7670fc8a99b80e0d6342179e1907 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 6 Feb 2015 17:25:29 +0100 Subject: [PATCH 7/8] Small fixes for proper multitype/multiarg SHA3 --- ExpressionCompiler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 4f091db4c..0ce19ecd1 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -851,7 +851,7 @@ unsigned ExpressionCompiler::appendArgumentsCopyToMemory(vectorgetType()->getCategory() == Type::Category::STRING) ? false : true; + const bool wantPadding = false; _arguments[i]->accept(*this); length += moveTypeToMemory(*_arguments[i]->getType()->getRealType(), _arguments[i]->getLocation(), _memoryOffset + length, wantPadding); } From afe1d9a592446dd403b9ed349529098b71309756 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 6 Feb 2015 20:57:04 +0100 Subject: [PATCH 8/8] Small fixes in Types and ExpressionCompiler --- ExpressionCompiler.cpp | 4 ++-- Types.cpp | 3 +-- Types.h | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 0ce19ecd1..cd133222c 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -860,8 +860,8 @@ unsigned ExpressionCompiler::appendArgumentsCopyToMemory(vector 32) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location) diff --git a/Types.cpp b/Types.cpp index a9051a2ca..6a1282027 100644 --- a/Types.cpp +++ b/Types.cpp @@ -364,8 +364,7 @@ u256 IntegerConstantType::literalValue(Literal const* _literal) const TypePointer IntegerConstantType::getRealType() const { auto intType = getIntegerType(); - if (!intType) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("getRealType called with invalid integer constant" + toString())); + solAssert(!!intType, std::string("getRealType called with invalid integer constant") + toString()); return intType; } diff --git a/Types.h b/Types.h index 677e5e49e..fcd6d9560 100644 --- a/Types.h +++ b/Types.h @@ -131,7 +131,7 @@ public: virtual bool isValueType() const { return false; } virtual unsigned getSizeOnStack() const { return 1; } /// @returns the real type of some types, like e.g: IntegerConstant - virtual TypePointer getRealType() const { return TypePointer(); } + virtual TypePointer getRealType() const { return shared_from_this(); } /// Returns the list of all members of this type. Default implementation: no members. virtual MemberList const& getMembers() const { return EmptyMemberList; }