From da5c5928fe403ebad08f7ec6e1d9e54999a19ec4 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 28 Sep 2021 14:21:39 +0200 Subject: [PATCH] Properly handle fixed-byte-like types. --- libsolidity/ast/Types.cpp | 1 + libsolidity/codegen/CompilerUtils.cpp | 18 +++++++++--------- libsolidity/codegen/LValue.cpp | 12 ++++++++---- libsolidity/codegen/YulUtilFunctions.cpp | 3 ++- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 3173d2763..5d624c26d 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -2537,6 +2537,7 @@ Type const& UserDefinedValueType::underlyingType() const { Type const* type = m_definition.underlyingType()->annotation().type; solAssert(type, ""); + solAssert(type->category() != Category::UserDefinedValueType, ""); return *type; } diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index b27bd7930..5e49868a3 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -1552,10 +1552,13 @@ void CompilerUtils::storeStringData(bytesConstRef _data) unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWords) { solAssert(_type.isValueType(), ""); + Type const* type = &_type; + if (auto const* userDefined = dynamic_cast(type)) + type = &userDefined->underlyingType(); - unsigned numBytes = _type.calldataEncodedSize(_padToWords); + unsigned numBytes = type->calldataEncodedSize(_padToWords); bool isExternalFunctionType = false; - if (auto const* funType = dynamic_cast(&_type)) + if (auto const* funType = dynamic_cast(type)) if (funType->kind() == FunctionType::Kind::External) isExternalFunctionType = true; if (numBytes == 0) @@ -1570,21 +1573,20 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda splitExternalFunctionType(true); else if (numBytes != 32) { - bool leftAligned = _type.category() == Type::Category::FixedBytes; // add leading or trailing zeros by dividing/multiplying depending on alignment unsigned shiftFactor = (32 - numBytes) * 8; rightShiftNumberOnStack(shiftFactor); - if (leftAligned) + if (type->leftAligned()) { leftShiftNumberOnStack(shiftFactor); cleanupNeeded = false; } - else if (IntegerType const* intType = dynamic_cast(&_type)) + else if (IntegerType const* intType = dynamic_cast(type)) if (!intType->isSigned()) cleanupNeeded = false; } if (_fromCalldata) - convertType(_type, _type, cleanupNeeded, false, true); + convertType(_type, *type, cleanupNeeded, false, true); return numBytes; } @@ -1639,12 +1641,10 @@ unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWords, "Memory store of more than 32 bytes requested (Type: " + _type.toString(true) + ")." ); - bool leftAligned = _type.category() == Type::Category::FixedBytes; - if (_cleanup) convertType(_type, _type, true); - if (numBytes != 32 && !leftAligned && !_padToWords) + if (numBytes != 32 && !_type.leftAligned() && !_padToWords) // shift the value accordingly before storing leftShiftNumberOnStack((32 - numBytes) * 8); diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp index 75a7f2749..01befb8a4 100644 --- a/libsolidity/codegen/LValue.cpp +++ b/libsolidity/codegen/LValue.cpp @@ -113,6 +113,7 @@ void MemoryItem::storeValue(Type const& _sourceType, SourceLocation const&, bool if (!m_padded) { solAssert(m_dataType->calldataEncodedSize(false) == 1, "Invalid non-padded type."); + solAssert(m_dataType->category() != Type::Category::UserDefinedValueType, ""); if (m_dataType->category() == Type::Category::FixedBytes) m_context << u256(0) << Instruction::BYTE; m_context << Instruction::SWAP1 << Instruction::MSTORE8; @@ -233,7 +234,7 @@ void StorageItem::retrieveValue(SourceLocation const&, bool _remove) const if (m_dataType->category() == Type::Category::FixedPoint) // implementation should be very similar to the integer case. solUnimplemented("Not yet implemented - FixedPointType."); - if (m_dataType->category() == Type::Category::FixedBytes) + if (m_dataType->leftAligned()) { CompilerUtils(m_context).leftShiftNumberOnStack(256 - 8 * m_dataType->storageBytes()); cleaned = true; @@ -329,10 +330,13 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc Instruction::AND; } } - else if (m_dataType->category() == Type::Category::FixedBytes) + else if (m_dataType->leftAligned()) { - solAssert(_sourceType.category() == Type::Category::FixedBytes, "source not fixed bytes"); - CompilerUtils(m_context).rightShiftNumberOnStack(256 - 8 * dynamic_cast(*m_dataType).numBytes()); + solAssert(_sourceType.category() == Type::Category::FixedBytes || ( + _sourceType.encodingType() && + _sourceType.encodingType()->category() == Type::Category::FixedBytes + ), "source not fixed bytes"); + CompilerUtils(m_context).rightShiftNumberOnStack(256 - 8 * m_dataType->storageBytes()); } else { diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index bb56c43df..ea3dd4526 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -2965,7 +2965,7 @@ string YulUtilFunctions::prepareStoreFunction(Type const& _type) } )"); templ("functionName", functionName); - if (_type.category() == Type::Category::FixedBytes) + if (_type.leftAligned()) templ("actualPrepare", shiftRightFunction(256 - 8 * _type.storageBytes()) + "(value)"); else templ("actualPrepare", "value"); @@ -3304,6 +3304,7 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) bodyTemplate("cleanOutput", cleanupFunction(_to)); string convert; + solAssert(_to.category() != Type::Category::UserDefinedValueType, ""); if (auto const* toFixedBytes = dynamic_cast(&_to)) convert = shiftLeftFunction(256 - toFixedBytes->numBytes() * 8); else if (dynamic_cast(&_to))