Skip to content

Commit 40d3223

Browse files
authored
Merge pull request #12565 from ethereum/ice-convert-string-bytes-11677
Fix ICE when converting from calldata string to bytes
2 parents 0b9ab33 + 6f4709d commit 40d3223

File tree

5 files changed

+186
-170
lines changed

5 files changed

+186
-170
lines changed

Changelog.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ Compiler Features:
1212

1313
Bugfixes:
1414
* Antlr Grammar: Allow builtin names in ``yulPath`` to support ``.address`` in function pointers.
15+
* Code Generator: Fix ICE when accessing the members of external functions occupying more than two stack slots.
16+
* Code Generator: Fix ICE when doing an explicit conversion from ``string calldata`` to ``bytes``.
1517
* Control Flow Graph: Perform proper virtual lookup for modifiers for uninitialized variable and unreachable code analysis.
1618
* Immutables: Fix wrong error when the constructor of a base contract uses ``return`` and the parent contract contains immutable variables.
1719
* IR Generator: Fix IR syntax error when copying storage arrays of structs containing functions.
1820
* Natspec: Fix ICE when overriding a struct getter with a Natspec-documented return value and the name in the struct is different.
1921
* TypeChecker: Fix ICE when a constant variable declaration forward references a struct.
20-
* Code Generator: Fix ICE when accessing the members of external functions occupying more than two stack slots.
2122

2223

2324
Solc-Js:

libsolidity/codegen/CompilerUtils.cpp

Lines changed: 51 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ static_assert(CompilerUtils::generalPurposeMemoryStart >= CompilerUtils::zeroPoi
5454
void CompilerUtils::initialiseFreeMemoryPointer()
5555
{
5656
size_t reservedMemory = m_context.reservedMemory();
57-
solAssert(bigint(generalPurposeMemoryStart) + bigint(reservedMemory) < bigint(1) << 63, "");
57+
solAssert(bigint(generalPurposeMemoryStart) + bigint(reservedMemory) < bigint(1) << 63);
5858
m_context << (u256(generalPurposeMemoryStart) + reservedMemory);
5959
storeFreeMemoryPointer();
6060
}
@@ -92,7 +92,7 @@ void CompilerUtils::toSizeAfterFreeMemoryPointer()
9292

9393
void CompilerUtils::revertWithStringData(Type const& _argumentType)
9494
{
95-
solAssert(_argumentType.isImplicitlyConvertibleTo(*TypeProvider::fromElementaryTypeName("string memory")), "");
95+
solAssert(_argumentType.isImplicitlyConvertibleTo(*TypeProvider::fromElementaryTypeName("string memory")));
9696
fetchFreeMemoryPointer();
9797
m_context << util::selectorFromSignature("Error(string)");
9898
m_context << Instruction::DUP2 << Instruction::MSTORE;
@@ -173,9 +173,9 @@ void CompilerUtils::loadFromMemoryDynamic(
173173

174174
if (auto arrayType = dynamic_cast<ArrayType const*>(&_type))
175175
{
176-
solAssert(!arrayType->isDynamicallySized(), "");
177-
solAssert(!_fromCalldata, "");
178-
solAssert(_padToWordBoundaries, "");
176+
solAssert(!arrayType->isDynamicallySized());
177+
solAssert(!_fromCalldata);
178+
solAssert(_padToWordBoundaries);
179179
if (_keepUpdatedMemoryOffset)
180180
m_context << arrayType->memoryDataSize() << Instruction::ADD;
181181
}
@@ -251,7 +251,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
251251
// Use the new Yul-based decoding function
252252
auto stackHeightBefore = m_context.stackHeight();
253253
abiDecodeV2(_typeParameters, _fromMemory);
254-
solAssert(m_context.stackHeight() - stackHeightBefore == sizeOnStack(_typeParameters) - 2, "");
254+
solAssert(m_context.stackHeight() - stackHeightBefore == sizeOnStack(_typeParameters) - 2);
255255
return;
256256
}
257257

@@ -290,7 +290,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
290290
);
291291
// @todo If base type is an array or struct, it is still calldata-style encoded, so
292292
// we would have to convert it like below.
293-
solAssert(arrayType.location() == DataLocation::Memory, "");
293+
solAssert(arrayType.location() == DataLocation::Memory);
294294
if (arrayType.isDynamicallySized())
295295
{
296296
// compute data pointer
@@ -430,7 +430,7 @@ void CompilerUtils::encodeToMemory(
430430
// stack: <v1> <v2> ... <vn> <mem>
431431
bool const encoderV2 = m_context.useABICoderV2();
432432
TypePointers targetTypes = _targetTypes.empty() ? _givenTypes : _targetTypes;
433-
solAssert(targetTypes.size() == _givenTypes.size(), "");
433+
solAssert(targetTypes.size() == _givenTypes.size());
434434
for (Type const*& t: targetTypes)
435435
{
436436
Type const* tEncoding = t->fullEncodingType(_encodeAsLibraryTypes, encoderV2, !_padToWordBoundaries);
@@ -449,7 +449,7 @@ void CompilerUtils::encodeToMemory(
449449
);
450450
auto stackHeightBefore = m_context.stackHeight();
451451
abiEncodeV2(_givenTypes, targetTypes, _encodeAsLibraryTypes, _padToWordBoundaries);
452-
solAssert(stackHeightBefore - m_context.stackHeight() == sizeOnStack(_givenTypes), "");
452+
solAssert(stackHeightBefore - m_context.stackHeight() == sizeOnStack(_givenTypes));
453453
return;
454454
}
455455

@@ -489,8 +489,8 @@ void CompilerUtils::encodeToMemory(
489489
{
490490
// special case: convert storage reference type to value type - this is only
491491
// possible for library calls where we just forward the storage reference
492-
solAssert(_encodeAsLibraryTypes, "");
493-
solAssert(_givenTypes[i]->sizeOnStack() == 1, "");
492+
solAssert(_encodeAsLibraryTypes);
493+
solAssert(_givenTypes[i]->sizeOnStack() == 1);
494494
}
495495
else if (
496496
_givenTypes[i]->dataStoredIn(DataLocation::Storage) ||
@@ -638,7 +638,7 @@ void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type)
638638
{
639639
if (_type.baseType()->hasSimpleZeroValueInMemory())
640640
{
641-
solAssert(_type.baseType()->isValueType(), "");
641+
solAssert(_type.baseType()->isValueType());
642642
Whiskers templ(R"({
643643
let size := mul(length, <element_size>)
644644
// cheap way of zero-initializing a memory range
@@ -774,9 +774,9 @@ void CompilerUtils::convertType(
774774

775775
if (stackTypeCategory == Type::Category::UserDefinedValueType)
776776
{
777-
solAssert(_cleanupNeeded, "");
777+
solAssert(_cleanupNeeded);
778778
auto& userDefined = dynamic_cast<UserDefinedValueType const&>(_typeOnStack);
779-
solAssert(_typeOnStack == _targetType || _targetType == userDefined.underlyingType(), "");
779+
solAssert(_typeOnStack == _targetType || _targetType == userDefined.underlyingType());
780780
return convertType(
781781
userDefined.underlyingType(),
782782
_targetType,
@@ -787,9 +787,9 @@ void CompilerUtils::convertType(
787787
}
788788
if (targetTypeCategory == Type::Category::UserDefinedValueType)
789789
{
790-
solAssert(_cleanupNeeded, "");
790+
solAssert(_cleanupNeeded);
791791
auto& userDefined = dynamic_cast<UserDefinedValueType const&>(_targetType);
792-
solAssert(_typeOnStack.isImplicitlyConvertibleTo(userDefined.underlyingType()), "");
792+
solAssert(_typeOnStack.isImplicitlyConvertibleTo(userDefined.underlyingType()));
793793
return convertType(
794794
_typeOnStack,
795795
userDefined.underlyingType(),
@@ -829,7 +829,7 @@ void CompilerUtils::convertType(
829829
}
830830
else if (targetTypeCategory == Type::Category::Address)
831831
{
832-
solAssert(typeOnStack.numBytes() * 8 == 160, "");
832+
solAssert(typeOnStack.numBytes() * 8 == 160);
833833
rightShiftNumberOnStack(256 - 160);
834834
}
835835
else
@@ -849,7 +849,7 @@ void CompilerUtils::convertType(
849849
break;
850850
}
851851
case Type::Category::Enum:
852-
solAssert(_targetType == _typeOnStack || targetTypeCategory == Type::Category::Integer, "");
852+
solAssert(_targetType == _typeOnStack || targetTypeCategory == Type::Category::Integer);
853853
if (enumOverflowCheckPending)
854854
{
855855
EnumType const& enumType = dynamic_cast<decltype(enumType)>(_typeOnStack);
@@ -885,13 +885,13 @@ void CompilerUtils::convertType(
885885
cleanHigherOrderBits(*typeOnStack);
886886
}
887887
else if (stackTypeCategory == Type::Category::Address)
888-
solAssert(targetBytesType.numBytes() * 8 == 160, "");
888+
solAssert(targetBytesType.numBytes() * 8 == 160);
889889
leftShiftNumberOnStack(256 - targetBytesType.numBytes() * 8);
890890
}
891891
else if (targetTypeCategory == Type::Category::Enum)
892892
{
893893
solAssert(stackTypeCategory != Type::Category::Address, "Invalid conversion to EnumType requested.");
894-
solAssert(_typeOnStack.mobileType(), "");
894+
solAssert(_typeOnStack.mobileType());
895895
// just clean
896896
convertType(_typeOnStack, *_typeOnStack.mobileType(), true);
897897
EnumType const& enumType = dynamic_cast<decltype(enumType)>(_targetType);
@@ -964,13 +964,13 @@ void CompilerUtils::convertType(
964964
if (targetTypeCategory == Type::Category::FixedBytes)
965965
{
966966
unsigned const numBytes = dynamic_cast<FixedBytesType const&>(_targetType).numBytes();
967-
solAssert(data.size() <= 32, "");
967+
solAssert(data.size() <= 32);
968968
m_context << (u256(h256(data, h256::AlignLeft)) & (~(u256(-1) >> (8 * numBytes))));
969969
}
970970
else if (targetTypeCategory == Type::Category::Array)
971971
{
972972
auto const& arrayType = dynamic_cast<ArrayType const&>(_targetType);
973-
solAssert(arrayType.isByteArray(), "");
973+
solAssert(arrayType.isByteArray());
974974
size_t storageSize = 32 + ((data.size() + 31) / 32) * 32;
975975
allocateMemory(storageSize);
976976
// stack: mempos
@@ -995,10 +995,10 @@ void CompilerUtils::convertType(
995995
typeOnStack.isByteArray() && !typeOnStack.isString(),
996996
"Array types other than bytes not convertible to bytesNN."
997997
);
998-
solAssert(typeOnStack.isDynamicallySized(), "");
998+
solAssert(typeOnStack.isDynamicallySized());
999999

10001000
bool fromCalldata = typeOnStack.dataStoredIn(DataLocation::CallData);
1001-
solAssert(typeOnStack.sizeOnStack() == (fromCalldata ? 2 : 1), "");
1001+
solAssert(typeOnStack.sizeOnStack() == (fromCalldata ? 2 : 1));
10021002
if (fromCalldata)
10031003
m_context << Instruction::SWAP1;
10041004

@@ -1012,7 +1012,7 @@ void CompilerUtils::convertType(
10121012
);
10131013
break;
10141014
}
1015-
solAssert(targetTypeCategory == stackTypeCategory, "");
1015+
solAssert(targetTypeCategory == stackTypeCategory);
10161016
auto const& targetType = dynamic_cast<ArrayType const&>(_targetType);
10171017
switch (targetType.location())
10181018
{
@@ -1034,9 +1034,9 @@ void CompilerUtils::convertType(
10341034
typeOnStack.baseType()->isDynamicallyEncoded()
10351035
)
10361036
{
1037-
solAssert(m_context.useABICoderV2(), "");
1037+
solAssert(m_context.useABICoderV2());
10381038
// stack: offset length(optional in case of dynamically sized array)
1039-
solAssert(typeOnStack.sizeOnStack() == (typeOnStack.isDynamicallySized() ? 2 : 1), "");
1039+
solAssert(typeOnStack.sizeOnStack() == (typeOnStack.isDynamicallySized() ? 2 : 1));
10401040
if (typeOnStack.isDynamicallySized())
10411041
m_context << Instruction::SWAP1;
10421042

@@ -1122,9 +1122,9 @@ void CompilerUtils::convertType(
11221122
typeOnStack.arrayType().isByteArray() && !typeOnStack.arrayType().isString(),
11231123
"Array types other than bytes not convertible to bytesNN."
11241124
);
1125-
solAssert(typeOnStack.isDynamicallySized(), "");
1126-
solAssert(typeOnStack.dataStoredIn(DataLocation::CallData), "");
1127-
solAssert(typeOnStack.sizeOnStack() == 2, "");
1125+
solAssert(typeOnStack.isDynamicallySized());
1126+
solAssert(typeOnStack.dataStoredIn(DataLocation::CallData));
1127+
solAssert(typeOnStack.sizeOnStack() == 2);
11281128

11291129
m_context << Instruction::SWAP1;
11301130
m_context.callYulFunction(
@@ -1138,22 +1138,24 @@ void CompilerUtils::convertType(
11381138
break;
11391139
}
11401140

1141-
solAssert(_targetType.category() == Type::Category::Array, "");
1141+
solAssert(_targetType.category() == Type::Category::Array);
11421142
auto const& targetArrayType = dynamic_cast<ArrayType const&>(_targetType);
1143-
solAssert(typeOnStack.arrayType().isImplicitlyConvertibleTo(targetArrayType), "");
1143+
solAssert(
1144+
typeOnStack.arrayType().isImplicitlyConvertibleTo(targetArrayType) ||
1145+
(typeOnStack.arrayType().isByteArray() && targetArrayType.isByteArray())
1146+
);
11441147
solAssert(
11451148
typeOnStack.arrayType().dataStoredIn(DataLocation::CallData) &&
11461149
typeOnStack.arrayType().isDynamicallySized() &&
1147-
!typeOnStack.arrayType().baseType()->isDynamicallyEncoded(),
1148-
""
1150+
!typeOnStack.arrayType().baseType()->isDynamicallyEncoded()
11491151
);
11501152
if (!_targetType.dataStoredIn(DataLocation::CallData))
11511153
return convertType(typeOnStack.arrayType(), _targetType);
11521154
break;
11531155
}
11541156
case Type::Category::Struct:
11551157
{
1156-
solAssert(targetTypeCategory == stackTypeCategory, "");
1158+
solAssert(targetTypeCategory == stackTypeCategory);
11571159
auto& targetType = dynamic_cast<StructType const&>(_targetType);
11581160
auto& typeOnStack = dynamic_cast<StructType const&>(_typeOnStack);
11591161
switch (targetType.location())
@@ -1182,7 +1184,7 @@ void CompilerUtils::convertType(
11821184
// stack: <memory ptr> <source ref> <memory ptr>
11831185
for (auto const& member: typeOnStack->members(nullptr))
11841186
{
1185-
solAssert(!member.type->containsNestedMapping(), "");
1187+
solAssert(!member.type->containsNestedMapping());
11861188
pair<u256, unsigned> const& offsets = typeOnStack->storageOffsetsOfMember(member.name);
11871189
_context << offsets.first << Instruction::DUP3 << Instruction::ADD;
11881190
_context << u256(offsets.second);
@@ -1209,7 +1211,7 @@ void CompilerUtils::convertType(
12091211
{
12101212
if (typeOnStack.isDynamicallyEncoded())
12111213
{
1212-
solAssert(m_context.useABICoderV2(), "");
1214+
solAssert(m_context.useABICoderV2());
12131215
m_context.callYulFunction(
12141216
m_context.utilFunctions().conversionFunction(typeOnStack, targetType),
12151217
1,
@@ -1231,7 +1233,7 @@ void CompilerUtils::convertType(
12311233
}
12321234
break;
12331235
case DataLocation::CallData:
1234-
solAssert(_typeOnStack == _targetType, "");
1236+
solAssert(_typeOnStack == _targetType);
12351237
// nothing to do
12361238
break;
12371239
}
@@ -1241,15 +1243,15 @@ void CompilerUtils::convertType(
12411243
{
12421244
TupleType const& sourceTuple = dynamic_cast<TupleType const&>(_typeOnStack);
12431245
TupleType const& targetTuple = dynamic_cast<TupleType const&>(_targetType);
1244-
solAssert(targetTuple.components().size() == sourceTuple.components().size(), "");
1246+
solAssert(targetTuple.components().size() == sourceTuple.components().size());
12451247
unsigned depth = sourceTuple.sizeOnStack();
12461248
for (size_t i = 0; i < sourceTuple.components().size(); ++i)
12471249
{
12481250
Type const* sourceType = sourceTuple.components()[i];
12491251
Type const* targetType = targetTuple.components()[i];
12501252
if (!sourceType)
12511253
{
1252-
solAssert(!targetType, "");
1254+
solAssert(!targetType);
12531255
continue;
12541256
}
12551257
unsigned sourceSize = sourceType->sizeOnStack();
@@ -1291,7 +1293,7 @@ void CompilerUtils::convertType(
12911293
break;
12921294
default:
12931295
// we used to allow conversions from function to address
1294-
solAssert(!(stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Address), "");
1296+
solAssert(!(stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Address));
12951297
if (stackTypeCategory == Type::Category::Function && targetTypeCategory == Type::Category::Function)
12961298
{
12971299
FunctionType const& typeOnStack = dynamic_cast<FunctionType const&>(_typeOnStack);
@@ -1348,14 +1350,14 @@ void CompilerUtils::pushZeroValue(Type const& _type)
13481350
}
13491351
if (referenceType->location() == DataLocation::CallData)
13501352
{
1351-
solAssert(referenceType->sizeOnStack() == 1 || referenceType->sizeOnStack() == 2, "");
1353+
solAssert(referenceType->sizeOnStack() == 1 || referenceType->sizeOnStack() == 2);
13521354
m_context << Instruction::CALLDATASIZE;
13531355
if (referenceType->sizeOnStack() == 2)
13541356
m_context << 0;
13551357
return;
13561358
}
13571359

1358-
solAssert(referenceType->location() == DataLocation::Memory, "");
1360+
solAssert(referenceType->location() == DataLocation::Memory);
13591361
if (auto arrayType = dynamic_cast<ArrayType const*>(&_type))
13601362
if (arrayType->isDynamicallySized())
13611363
{
@@ -1383,7 +1385,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
13831385
}
13841386
else if (auto arrayType = dynamic_cast<ArrayType const*>(type))
13851387
{
1386-
solAssert(!arrayType->isDynamicallySized(), "");
1388+
solAssert(!arrayType->isDynamicallySized());
13871389
if (arrayType->length() > 0)
13881390
{
13891391
_context << arrayType->length() << Instruction::SWAP1;
@@ -1483,7 +1485,7 @@ void CompilerUtils::popStackSlots(size_t _amount)
14831485

14841486
void CompilerUtils::popAndJump(unsigned _toHeight, evmasm::AssemblyItem const& _jumpTo)
14851487
{
1486-
solAssert(m_context.stackHeight() >= _toHeight, "");
1488+
solAssert(m_context.stackHeight() >= _toHeight);
14871489
unsigned amount = m_context.stackHeight() - _toHeight;
14881490
popStackSlots(amount);
14891491
m_context.appendJumpTo(_jumpTo);
@@ -1551,7 +1553,7 @@ void CompilerUtils::storeStringData(bytesConstRef _data)
15511553

15521554
unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWords)
15531555
{
1554-
solAssert(_type.isValueType(), "");
1556+
solAssert(_type.isValueType());
15551557
Type const* type = &_type;
15561558
if (auto const* userDefined = dynamic_cast<UserDefinedValueType const*>(type))
15571559
type = &userDefined->underlyingType();
@@ -1603,7 +1605,7 @@ void CompilerUtils::cleanHigherOrderBits(IntegerType const& _typeOnStack)
16031605

16041606
void CompilerUtils::leftShiftNumberOnStack(unsigned _bits)
16051607
{
1606-
solAssert(_bits < 256, "");
1608+
solAssert(_bits < 256);
16071609
if (m_context.evmVersion().hasBitwiseShifting())
16081610
m_context << _bits << Instruction::SHL;
16091611
else
@@ -1612,7 +1614,7 @@ void CompilerUtils::leftShiftNumberOnStack(unsigned _bits)
16121614

16131615
void CompilerUtils::rightShiftNumberOnStack(unsigned _bits)
16141616
{
1615-
solAssert(_bits < 256, "");
1617+
solAssert(_bits < 256);
16161618
// NOTE: If we add signed right shift, SAR rounds differently than SDIV
16171619
if (m_context.evmVersion().hasBitwiseShifting())
16181620
m_context << _bits << Instruction::SHR;
@@ -1627,7 +1629,7 @@ unsigned CompilerUtils::prepareMemoryStore(Type const& _type, bool _padToWords,
16271629
"Memory store of types with stack size != 1 not allowed (Type: " + _type.toString(true) + ")."
16281630
);
16291631

1630-
solAssert(!_type.isDynamicallyEncoded(), "");
1632+
solAssert(!_type.isDynamicallyEncoded());
16311633

16321634
unsigned numBytes = _type.calldataEncodedSize(_padToWords);
16331635

libsolidity/codegen/YulUtilFunctions.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3219,15 +3219,17 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
32193219
solAssert(fromType.arrayType().isByteArray(), "Array types other than bytes not convertible to bytesNN.");
32203220
return bytesToFixedBytesConversionFunction(fromType.arrayType(), dynamic_cast<FixedBytesType const &>(_to));
32213221
}
3222-
solAssert(_to.category() == Type::Category::Array, "");
3222+
solAssert(_to.category() == Type::Category::Array);
32233223
auto const& targetType = dynamic_cast<ArrayType const&>(_to);
32243224

3225-
solAssert(fromType.arrayType().isImplicitlyConvertibleTo(targetType), "");
3225+
solAssert(
3226+
fromType.arrayType().isImplicitlyConvertibleTo(targetType) ||
3227+
(fromType.arrayType().isByteArray() && targetType.isByteArray())
3228+
);
32263229
solAssert(
32273230
fromType.arrayType().dataStoredIn(DataLocation::CallData) &&
32283231
fromType.arrayType().isDynamicallySized() &&
3229-
!fromType.arrayType().baseType()->isDynamicallyEncoded(),
3230-
""
3232+
!fromType.arrayType().baseType()->isDynamicallyEncoded()
32313233
);
32323234

32333235
if (!targetType.dataStoredIn(DataLocation::CallData))

0 commit comments

Comments
 (0)