From 2cdf44f65cdd15f31293ae2fa78d9996d6219af0 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 20 Feb 2018 10:13:58 +0100 Subject: Move the old ABI decoder code. --- libsolidity/codegen/CompilerUtils.cpp | 99 +++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) (limited to 'libsolidity/codegen/CompilerUtils.cpp') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 533aca5c..704d8da8 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -159,6 +159,105 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound } } +void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMemory) +{ + // We do not check the calldata size, everything is zero-padded + + if (m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)) + { + // Use the new JULIA-based decoding function + auto stackHeightBefore = m_context.stackHeight(); + abiDecodeV2(_typeParameters, _fromMemory); + solAssert(m_context.stackHeight() - stackHeightBefore == sizeOnStack(_typeParameters) - 1, ""); + return; + } + + //@todo this does not yet support nested dynamic arrays + + // Retain the offset pointer as base_offset, the point from which the data offsets are computed. + m_context << Instruction::DUP1; + for (TypePointer const& parameterType: _typeParameters) + { + // stack: v1 v2 ... v(k-1) base_offset current_offset + TypePointer type = parameterType->decodingType(); + solUnimplementedAssert(type, "No decoding type found."); + if (type->category() == Type::Category::Array) + { + auto const& arrayType = dynamic_cast(*type); + solUnimplementedAssert(!arrayType.baseType()->isDynamicallySized(), "Nested arrays not yet implemented."); + if (_fromMemory) + { + solUnimplementedAssert( + arrayType.baseType()->isValueType(), + "Nested memory arrays not yet implemented here." + ); + // @todo If base type is an array or struct, it is still calldata-style encoded, so + // we would have to convert it like below. + solAssert(arrayType.location() == DataLocation::Memory, ""); + if (arrayType.isDynamicallySized()) + { + // compute data pointer + m_context << Instruction::DUP1 << Instruction::MLOAD; + m_context << Instruction::DUP3 << Instruction::ADD; + m_context << Instruction::SWAP2 << Instruction::SWAP1; + m_context << u256(0x20) << Instruction::ADD; + } + else + { + m_context << Instruction::SWAP1 << Instruction::DUP2; + m_context << u256(arrayType.calldataEncodedSize(true)) << Instruction::ADD; + } + } + else + { + // first load from calldata and potentially convert to memory if arrayType is memory + TypePointer calldataType = arrayType.copyForLocation(DataLocation::CallData, false); + if (calldataType->isDynamicallySized()) + { + // put on stack: data_pointer length + loadFromMemoryDynamic(IntegerType(256), !_fromMemory); + // stack: base_offset data_offset next_pointer + m_context << Instruction::SWAP1 << Instruction::DUP3 << Instruction::ADD; + // stack: base_offset next_pointer data_pointer + // retrieve length + loadFromMemoryDynamic(IntegerType(256), !_fromMemory, true); + // stack: base_offset next_pointer length data_pointer + m_context << Instruction::SWAP2; + // stack: base_offset data_pointer length next_pointer + } + else + { + // leave the pointer on the stack + m_context << Instruction::DUP1; + m_context << u256(calldataType->calldataEncodedSize()) << Instruction::ADD; + } + if (arrayType.location() == DataLocation::Memory) + { + // stack: base_offset calldata_ref [length] next_calldata + // copy to memory + // move calldata type up again + moveIntoStack(calldataType->sizeOnStack()); + convertType(*calldataType, arrayType, false, false, true); + // fetch next pointer again + moveToStackTop(arrayType.sizeOnStack()); + } + // move base_offset up + moveToStackTop(1 + arrayType.sizeOnStack()); + m_context << Instruction::SWAP1; + } + } + else + { + solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString()); + loadFromMemoryDynamic(*type, !_fromMemory, true); + moveToStackTop(1 + type->sizeOnStack()); + m_context << Instruction::SWAP1; + } + // stack: v1 v2 ... v(k-1) v(k) base_offset mem_offset + } + m_context << Instruction::POP << Instruction::POP; +} + void CompilerUtils::encodeToMemory( TypePointers const& _givenTypes, TypePointers const& _targetTypes, -- cgit v1.2.3 From 32c94f505901201126000eb12087251f5695acbd Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 13 Dec 2017 17:23:37 +0100 Subject: Simple size check for old ABI decoder. --- libsolidity/codegen/CompilerUtils.cpp | 117 +++++++++++++++++++++++++--------- 1 file changed, 88 insertions(+), 29 deletions(-) (limited to 'libsolidity/codegen/CompilerUtils.cpp') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 704d8da8..d9177312 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -22,11 +22,14 @@ #include #include -#include #include #include #include +#include + +#include + using namespace std; namespace dev @@ -159,26 +162,37 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound } } -void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMemory) +void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMemory, bool _revertOnOutOfBounds) { - // We do not check the calldata size, everything is zero-padded - + /// Stack: if (m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)) { // Use the new JULIA-based decoding function auto stackHeightBefore = m_context.stackHeight(); abiDecodeV2(_typeParameters, _fromMemory); - solAssert(m_context.stackHeight() - stackHeightBefore == sizeOnStack(_typeParameters) - 1, ""); + solAssert(m_context.stackHeight() - stackHeightBefore == sizeOnStack(_typeParameters) - 2, ""); return; } //@todo this does not yet support nested dynamic arrays + if (_revertOnOutOfBounds) + { + size_t encodedSize = 0; + for (auto const& t: _typeParameters) + encodedSize += t->decodingType()->calldataEncodedSize(true); + m_context.appendInlineAssembly("{ if lt(len, " + to_string(encodedSize) + ") { revert(0, 0) } }", {"len"}); + } + + m_context << Instruction::DUP2 << Instruction::ADD; + m_context << Instruction::SWAP1; + /// Stack: + // Retain the offset pointer as base_offset, the point from which the data offsets are computed. m_context << Instruction::DUP1; for (TypePointer const& parameterType: _typeParameters) { - // stack: v1 v2 ... v(k-1) base_offset current_offset + // stack: v1 v2 ... v(k-1) input_end base_offset current_offset TypePointer type = parameterType->decodingType(); solUnimplementedAssert(type, "No decoding type found."); if (type->category() == Type::Category::Array) @@ -198,13 +212,35 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem { // compute data pointer m_context << Instruction::DUP1 << Instruction::MLOAD; - m_context << Instruction::DUP3 << Instruction::ADD; - m_context << Instruction::SWAP2 << Instruction::SWAP1; + if (_revertOnOutOfBounds) + { + // Check that the data pointer is valid and that length times + // item size is still inside the range. + Whiskers templ(R"({ + if gt(ptr, 0x100000000) { revert(0, 0) } + ptr := add(ptr, base_offset) + let array_data_start := add(ptr, 0x20) + if gt(array_data_start, input_end) { revert(0, 0) } + let array_length := mload(ptr) + if or( + gt(array_length, 0x100000000), + gt(add(array_data_start, mul(array_length, )), input_end) + ) { revert(0, 0) } + })"); + templ("item_size", to_string(arrayType.isByteArray() ? 1 : arrayType.baseType()->calldataEncodedSize(true))); + m_context.appendInlineAssembly(templ.render(), {"input_end", "base_offset", "offset", "ptr"}); + } + else + m_context << Instruction::DUP3 << Instruction::ADD; + // stack: v1 v2 ... v(k-1) input_end base_offset current_offset v(k) + moveIntoStack(3); m_context << u256(0x20) << Instruction::ADD; } else { - m_context << Instruction::SWAP1 << Instruction::DUP2; + // Size has already been checked for this one. + moveIntoStack(2); + m_context << Instruction::DUP3; m_context << u256(arrayType.calldataEncodedSize(true)) << Instruction::ADD; } } @@ -216,24 +252,43 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem { // put on stack: data_pointer length loadFromMemoryDynamic(IntegerType(256), !_fromMemory); - // stack: base_offset data_offset next_pointer - m_context << Instruction::SWAP1 << Instruction::DUP3 << Instruction::ADD; - // stack: base_offset next_pointer data_pointer + m_context << Instruction::SWAP1; + // stack: input_end base_offset next_pointer data_offset + if (_revertOnOutOfBounds) + m_context.appendInlineAssembly("{ if gt(data_offset, 0x100000000) { revert(0, 0) } }", {"data_offset"}); + m_context << Instruction::DUP3 << Instruction::ADD; + // stack: input_end base_offset next_pointer array_head_ptr + if (_revertOnOutOfBounds) + m_context.appendInlineAssembly( + "{ if gt(add(array_head_ptr, 0x20), input_end) { revert(0, 0) } }", + {"input_end", "base_offset", "next_ptr", "array_head_ptr"} + ); // retrieve length loadFromMemoryDynamic(IntegerType(256), !_fromMemory, true); - // stack: base_offset next_pointer length data_pointer + // stack: input_end base_offset next_pointer array_length data_pointer m_context << Instruction::SWAP2; - // stack: base_offset data_pointer length next_pointer + // stack: input_end base_offset data_pointer array_length next_pointer + if (_revertOnOutOfBounds) + { + unsigned itemSize = arrayType.isByteArray() ? 1 : arrayType.baseType()->calldataEncodedSize(true); + m_context.appendInlineAssembly(R"({ + if or( + gt(array_length, 0x100000000), + gt(add(data_ptr, mul(array_length, )" + to_string(itemSize) + R"()), input_end) + ) { revert(0, 0) } + })", {"input_end", "base_offset", "data_ptr", "array_length", "next_ptr"}); + } } else { - // leave the pointer on the stack + // size has already been checked + // stack: input_end base_offset data_offset m_context << Instruction::DUP1; m_context << u256(calldataType->calldataEncodedSize()) << Instruction::ADD; } if (arrayType.location() == DataLocation::Memory) { - // stack: base_offset calldata_ref [length] next_calldata + // stack: input_end base_offset calldata_ref [length] next_calldata // copy to memory // move calldata type up again moveIntoStack(calldataType->sizeOnStack()); @@ -241,21 +296,27 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem // fetch next pointer again moveToStackTop(arrayType.sizeOnStack()); } - // move base_offset up - moveToStackTop(1 + arrayType.sizeOnStack()); + // move input_end up + // stack: input_end base_offset calldata_ref [length] next_calldata + moveToStackTop(2 + arrayType.sizeOnStack()); + m_context << Instruction::SWAP1; + // stack: base_offset calldata_ref [length] input_end next_calldata + moveToStackTop(2 + arrayType.sizeOnStack()); m_context << Instruction::SWAP1; + // stack: calldata_ref [length] input_end base_offset next_calldata } } else { solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString()); loadFromMemoryDynamic(*type, !_fromMemory, true); - moveToStackTop(1 + type->sizeOnStack()); - m_context << Instruction::SWAP1; + // stack: v1 v2 ... v(k-1) input_end base_offset v(k) mem_offset + moveToStackTop(1, type->sizeOnStack()); + moveIntoStack(3, type->sizeOnStack()); } - // stack: v1 v2 ... v(k-1) v(k) base_offset mem_offset + // stack: v1 v2 ... v(k-1) v(k) input_end base_offset next_offset } - m_context << Instruction::POP << Instruction::POP; + popStackSlots(3); } void CompilerUtils::encodeToMemory( @@ -420,15 +481,13 @@ void CompilerUtils::abiEncodeV2( void CompilerUtils::abiDecodeV2(TypePointers const& _parameterTypes, bool _fromMemory) { - // stack: + // stack: [stack top] auto ret = m_context.pushNewTag(); + moveIntoStack(2); + // stack: [stack top] + m_context << Instruction::DUP2 << Instruction::ADD; m_context << Instruction::SWAP1; - if (_fromMemory) - // TODO pass correct size for the memory case - m_context << (u256(1) << 63); - else - m_context << Instruction::CALLDATASIZE; - m_context << Instruction::SWAP1; + // stack: string decoderName = m_context.abiFunctions().tupleDecoder(_parameterTypes, _fromMemory); m_context.appendJumpTo(m_context.namedTag(decoderName)); m_context.adjustStackOffset(int(sizeOnStack(_parameterTypes)) - 3); -- cgit v1.2.3 From c2709a2d8e53155513fa8002a564e434fce68c68 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 21 Feb 2018 11:07:30 +0100 Subject: Decode dynamic data. --- libsolidity/codegen/CompilerUtils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libsolidity/codegen/CompilerUtils.cpp') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index d9177312..1bd1103b 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -198,7 +198,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem if (type->category() == Type::Category::Array) { auto const& arrayType = dynamic_cast(*type); - solUnimplementedAssert(!arrayType.baseType()->isDynamicallySized(), "Nested arrays not yet implemented."); + solUnimplementedAssert(!arrayType.baseType()->isDynamicallyEncoded(), "Nested arrays not yet implemented."); if (_fromMemory) { solUnimplementedAssert( @@ -308,7 +308,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem } else { - solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString()); + solAssert(!type->isDynamicallyEncoded(), "Unknown dynamically sized type: " + type->toString()); loadFromMemoryDynamic(*type, !_fromMemory, true); // stack: v1 v2 ... v(k-1) input_end base_offset v(k) mem_offset moveToStackTop(1, type->sizeOnStack()); -- cgit v1.2.3 From fab527c4146f08971938c63074c8c92e6ff241bc Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Tue, 27 Mar 2018 03:39:37 +0100 Subject: Add runtimeOnly option to pushCombinedFunctionEntryLabel --- libsolidity/codegen/CompilerUtils.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'libsolidity/codegen/CompilerUtils.cpp') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 1bd1103b..68f0b3a1 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -585,7 +585,7 @@ void CompilerUtils::combineExternalFunctionType(bool _leftAligned) leftShiftNumberOnStack(64); } -void CompilerUtils::pushCombinedFunctionEntryLabel(Declaration const& _function) +void CompilerUtils::pushCombinedFunctionEntryLabel(Declaration const& _function, bool _runtimeOnly) { m_context << m_context.functionEntryLabel(_function).pushTag(); // If there is a runtime context, we have to merge both labels into the same @@ -593,9 +593,10 @@ void CompilerUtils::pushCombinedFunctionEntryLabel(Declaration const& _function) if (CompilerContext* rtc = m_context.runtimeContext()) { leftShiftNumberOnStack(32); - m_context << - rtc->functionEntryLabel(_function).toSubAssemblyTag(m_context.runtimeSub()) << - Instruction::OR; + if (_runtimeOnly) + m_context << + rtc->functionEntryLabel(_function).toSubAssemblyTag(m_context.runtimeSub()) << + Instruction::OR; } } -- cgit v1.2.3 From 5c8a6aac698f6d084a22c6ec9f282b3f26ddb8bb Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 16 Mar 2018 16:06:40 +0100 Subject: Prevent encoding of weird types and support packed encoding of external function types. --- libsolidity/codegen/CompilerUtils.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'libsolidity/codegen/CompilerUtils.cpp') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 68f0b3a1..676d5d4e 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -142,7 +142,6 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound dynamic_cast(_type).kind() == FunctionType::Kind::External ) { - solUnimplementedAssert(_padToWordBoundaries, "Non-padded store for function not implemented."); combineExternalFunctionType(true); m_context << Instruction::DUP2 << Instruction::MSTORE; m_context << u256(_padToWordBoundaries ? 32 : 24) << Instruction::ADD; -- cgit v1.2.3 From 6777f7a57fed6b39128773f13084da729dd64588 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 8 Mar 2018 19:41:29 +0100 Subject: Optimize across MLOAD if MSIZE is not used. --- libsolidity/codegen/CompilerUtils.cpp | 36 +++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'libsolidity/codegen/CompilerUtils.cpp') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 676d5d4e..deaef017 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -495,14 +495,34 @@ void CompilerUtils::abiDecodeV2(TypePointers const& _parameterTypes, bool _fromM void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type) { - auto repeat = m_context.newTag(); - m_context << repeat; - pushZeroValue(*_type.baseType()); - storeInMemoryDynamic(*_type.baseType()); - m_context << Instruction::SWAP1 << u256(1) << Instruction::SWAP1; - m_context << Instruction::SUB << Instruction::SWAP1; - m_context << Instruction::DUP2; - m_context.appendConditionalJumpTo(repeat); + if (_type.baseType()->hasSimpleZeroValueInMemory()) + { + solAssert(_type.baseType()->isValueType(), ""); + Whiskers templ(R"({ + let size := mul(length, ) + // cheap way of zero-initializing a memory range + codecopy(memptr, codesize(), size) + memptr := add(memptr, size) + })"); + templ("element_size", to_string(_type.baseType()->memoryHeadSize())); + m_context.appendInlineAssembly(templ.render(), {"length", "memptr"}); + } + else + { + // TODO: Potential optimization: + // When we create a new multi-dimensional dynamic array, each element + // is initialized to an empty array. It actually does not hurt + // to re-use exactly the same empty array for all elements. Currently, + // a new one is created each time. + auto repeat = m_context.newTag(); + m_context << repeat; + pushZeroValue(*_type.baseType()); + storeInMemoryDynamic(*_type.baseType()); + m_context << Instruction::SWAP1 << u256(1) << Instruction::SWAP1; + m_context << Instruction::SUB << Instruction::SWAP1; + m_context << Instruction::DUP2; + m_context.appendConditionalJumpTo(repeat); + } m_context << Instruction::SWAP1 << Instruction::POP; } -- cgit v1.2.3 From 0cbe55005de79b0f7c5c770d50c3eb87df019789 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 13 Mar 2018 15:21:38 +0100 Subject: Create empty dynamic memory arrays more efficiently. --- libsolidity/codegen/CompilerUtils.cpp | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'libsolidity/codegen/CompilerUtils.cpp') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index deaef017..79aef7b0 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -21,6 +21,7 @@ */ #include + #include #include #include @@ -39,11 +40,17 @@ namespace solidity const unsigned CompilerUtils::dataStartOffset = 4; const size_t CompilerUtils::freeMemoryPointer = 64; +const size_t CompilerUtils::zeroPointer = CompilerUtils::freeMemoryPointer + 32; +const size_t CompilerUtils::generalPurposeMemoryStart = CompilerUtils::zeroPointer + 32; const unsigned CompilerUtils::identityContractAddress = 4; +static_assert(CompilerUtils::freeMemoryPointer >= 64, "Free memory pointer must not overlap with scratch area."); +static_assert(CompilerUtils::zeroPointer >= CompilerUtils::freeMemoryPointer + 32, "Zero pointer must not overlap with free memory pointer."); +static_assert(CompilerUtils::generalPurposeMemoryStart >= CompilerUtils::zeroPointer + 32, "General purpose memory must not overlap with zero area."); + void CompilerUtils::initialiseFreeMemoryPointer() { - m_context << u256(freeMemoryPointer + 32); + m_context << u256(generalPurposeMemoryStart); storeFreeMemoryPointer(); } @@ -1051,6 +1058,13 @@ void CompilerUtils::pushZeroValue(Type const& _type) return; } solAssert(referenceType->location() == DataLocation::Memory, ""); + if (auto arrayType = dynamic_cast(&_type)) + if (arrayType->isDynamicallySized()) + { + // Push a memory location that is (hopefully) always zero. + pushZeroPointer(); + return; + } TypePointer type = _type.shared_from_this(); m_context.callLowLevelFunction( @@ -1071,13 +1085,8 @@ void CompilerUtils::pushZeroValue(Type const& _type) } else if (auto arrayType = dynamic_cast(type.get())) { - if (arrayType->isDynamicallySized()) - { - // zero length - _context << u256(0); - utils.storeInMemoryDynamic(IntegerType(256)); - } - else if (arrayType->length() > 0) + solAssert(!arrayType->isDynamicallySized(), ""); + if (arrayType->length() > 0) { _context << arrayType->length() << Instruction::SWAP1; // stack: items_to_do memory_pos @@ -1094,6 +1103,11 @@ void CompilerUtils::pushZeroValue(Type const& _type) ); } +void CompilerUtils::pushZeroPointer() +{ + m_context << u256(zeroPointer); +} + void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable) { unsigned const stackPosition = m_context.baseToCurrentStackOffset(m_context.baseStackOffsetOfVariable(_variable)); -- cgit v1.2.3 From 7a9ee69e986cf58c8b2a6cabec2c59b0eb2fbb57 Mon Sep 17 00:00:00 2001 From: chriseth Date: Sat, 30 Dec 2017 20:13:41 +0100 Subject: Bubble up error messages. --- libsolidity/codegen/CompilerUtils.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'libsolidity/codegen/CompilerUtils.cpp') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 79aef7b0..34337d7d 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -691,6 +691,7 @@ void CompilerUtils::convertType( solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error."); m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT; if (_asPartOfArgumentDecoding) + // TODO: error message? m_context.appendConditionalRevert(); else m_context.appendConditionalInvalid(); -- cgit v1.2.3 From 4faa839813ce76fc87f99b002aad6cadd2b784e1 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 6 Apr 2018 15:14:55 +0200 Subject: Use error signature for revert data. --- libsolidity/codegen/CompilerUtils.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'libsolidity/codegen/CompilerUtils.cpp') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 34337d7d..b4550153 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -78,6 +78,20 @@ void CompilerUtils::toSizeAfterFreeMemoryPointer() m_context << Instruction::SWAP1; } +void CompilerUtils::revertWithStringData(Type const& _argumentType) +{ + solAssert(_argumentType.isImplicitlyConvertibleTo(*Type::fromElementaryTypeName("string memory")), ""); + fetchFreeMemoryPointer(); + m_context << (u256(FixedHash<4>::Arith(FixedHash<4>(dev::keccak256("Error(string)")))) << (256 - 32)); + m_context << Instruction::DUP2 << Instruction::MSTORE; + m_context << u256(4) << Instruction::ADD; + // Stack: + abiEncode({_argumentType.shared_from_this()}, {make_shared(DataLocation::Memory, true)}); + toSizeAfterFreeMemoryPointer(); + m_context << Instruction::REVERT; + m_context.adjustStackOffset(_argumentType.sizeOnStack()); +} + unsigned CompilerUtils::loadFromMemory( unsigned _offset, Type const& _type, -- cgit v1.2.3 From 4c1d39b7a2bc9e58436da0bf85edf5cd74d5a882 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 12 Apr 2018 00:39:20 +0200 Subject: Properly force-clean for shortening bytesXX conversions. --- libsolidity/codegen/CompilerUtils.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'libsolidity/codegen/CompilerUtils.cpp') diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index b4550153..4af7d905 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -684,19 +684,17 @@ void CompilerUtils::convertType( // clear for conversion to longer bytes solAssert(targetTypeCategory == Type::Category::FixedBytes, "Invalid type conversion requested."); FixedBytesType const& targetType = dynamic_cast(_targetType); - if (targetType.numBytes() > typeOnStack.numBytes() || _cleanupNeeded) + if (typeOnStack.numBytes() == 0 || targetType.numBytes() == 0) + m_context << Instruction::POP << u256(0); + else if (targetType.numBytes() > typeOnStack.numBytes() || _cleanupNeeded) { - if (typeOnStack.numBytes() == 0) - m_context << Instruction::POP << u256(0); - else - { - m_context << ((u256(1) << (256 - typeOnStack.numBytes() * 8)) - 1); - m_context << Instruction::NOT << Instruction::AND; - } + int bytes = min(typeOnStack.numBytes(), targetType.numBytes()); + m_context << ((u256(1) << (256 - bytes * 8)) - 1); + m_context << Instruction::NOT << Instruction::AND; } } - } break; + } case Type::Category::Enum: solAssert(_targetType == _typeOnStack || targetTypeCategory == Type::Category::Integer, ""); if (enumOverflowCheckPending) @@ -798,8 +796,9 @@ void CompilerUtils::convertType( bytesConstRef data(value); if (targetTypeCategory == Type::Category::FixedBytes) { + int const numBytes = dynamic_cast(_targetType).numBytes(); solAssert(data.size() <= 32, ""); - m_context << h256::Arith(h256(data, h256::AlignLeft)); + m_context << (h256::Arith(h256(data, h256::AlignLeft)) & (~(u256(-1) >> (8 * numBytes)))); } else if (targetTypeCategory == Type::Category::Array) { -- cgit v1.2.3