diff options
author | chriseth <chris@ethereum.org> | 2018-02-21 18:07:30 +0800 |
---|---|---|
committer | Alex Beregszaszi <alex@rtfs.hu> | 2018-03-21 22:53:29 +0800 |
commit | c2709a2d8e53155513fa8002a564e434fce68c68 (patch) | |
tree | 39588b44be72002e805c517ff13fa4cde2a77fc4 | |
parent | cc2f71e4acede70f6c220d3d0ba407ab73c2024c (diff) | |
download | dexon-solidity-c2709a2d8e53155513fa8002a564e434fce68c68.tar.gz dexon-solidity-c2709a2d8e53155513fa8002a564e434fce68c68.tar.zst dexon-solidity-c2709a2d8e53155513fa8002a564e434fce68c68.zip |
Decode dynamic data.
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 2 | ||||
-rw-r--r-- | libsolidity/codegen/ABIFunctions.cpp | 3 | ||||
-rw-r--r-- | libsolidity/codegen/CompilerUtils.cpp | 4 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 57 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 5 |
5 files changed, 53 insertions, 18 deletions
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index c8e64c78..999a2a97 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1551,7 +1551,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) _functionCall.expression().annotation().isPure && functionType->isPure(); - bool allowDynamicTypes = false; // @TODO + bool allowDynamicTypes = m_evmVersion.supportsReturndata(); if (!functionType) { m_errorReporter.typeError(_functionCall.location(), "Type is not callable"); diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 00f59065..8e890854 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -253,6 +253,9 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure) templ("body", w.render()); break; } + case Type::Category::InaccessibleDynamic: + templ("body", "cleaned := 0"); + break; default: solAssert(false, "Cleanup of type " + _type.identifier() + " requested."); } 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<ArrayType const&>(*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()); diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 7d148c0c..37069c3e 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1618,22 +1618,27 @@ void ExpressionCompiler::appendExternalFunctionCall( m_context.experimentalFeatureActive(ExperimentalFeature::V050) && m_context.evmVersion().hasStaticCall(); - bool allowDynamicTypes = false; // @TODO + bool haveReturndatacopy = m_context.evmVersion().supportsReturndata(); unsigned retSize = 0; TypePointers returnTypes; if (returnSuccessCondition) retSize = 0; // return value actually is success condition - else if (allowDynamicTypes) + else if (haveReturndatacopy) returnTypes = _functionType.returnParameterTypes(); else - { returnTypes = _functionType.returnParameterTypesWithoutDynamicTypes(); - for (auto const& retType: returnTypes) + + bool dynamicReturnSize = false; + for (auto const& retType: returnTypes) + if (retType->isDynamicallyEncoded()) { - solAssert(!retType->isDynamicallySized(), "Unable to return dynamic type from external call."); - retSize += retType->calldataEncodedSize(); + solAssert(haveReturndatacopy, ""); + dynamicReturnSize = true; + retSize = 0; + break; } - } + else + retSize += retType->calldataEncodedSize(); // Evaluate arguments. TypePointers argumentTypes; @@ -1834,17 +1839,39 @@ void ExpressionCompiler::appendExternalFunctionCall( else if (!returnTypes.empty()) { utils().fetchFreeMemoryPointer(); - bool memoryNeeded = false; - for (auto const& retType: returnTypes) + // Stack: return_data_start + + // The old decoder did not allocate any memory (i.e. did not touch the free + // memory pointer), but kept references to the return data for + // (statically-sized) arrays + bool needToUpdateFreeMemoryPtr = false; + if (dynamicReturnSize || m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2)) + needToUpdateFreeMemoryPtr = true; + else + for (auto const& retType: returnTypes) + if (dynamic_cast<ReferenceType const*>(retType.get())) + needToUpdateFreeMemoryPtr = true; + + // Stack: return_data_start + if (dynamicReturnSize) { - utils().loadFromMemoryDynamic(*retType, false, true, true); - if (dynamic_cast<ReferenceType const*>(retType.get())) - memoryNeeded = true; + solAssert(haveReturndatacopy, ""); + m_context.appendInlineAssembly("{ returndatacopy(return_data_start, 0, returndatasize()) }", {"return_data_start"}); } - if (memoryNeeded) - utils().storeFreeMemoryPointer(); else - m_context << Instruction::POP; + solAssert(retSize > 0, ""); + // Always use the actual return length, and not our calculated expected length, if returndatacopy is supported. + // This ensures it can catch badly formatted input from external calls. + m_context << (haveReturndatacopy ? eth::AssemblyItem(Instruction::RETURNDATASIZE) : u256(retSize)); + // Stack: return_data_start return_data_size + if (needToUpdateFreeMemoryPtr) + m_context.appendInlineAssembly(R"({ + // round size to the next multiple of 32 + let newMem := add(start, and(add(size, 0x1f), not(0x1f))) + mstore(0x40, newMem) + })", {"start", "size"}); + + utils().abiDecode(returnTypes, true, true); } } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index c757037c..8a020ca6 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -3372,6 +3372,11 @@ BOOST_AUTO_TEST_CASE(dynamic_return_types_not_possible) } } )"; + m_compiler.setEVMVersion(EVMVersion{}); + CHECK_WARNING(sourceCode, "Use of the \"var\" keyword is deprecated"); + m_compiler.setEVMVersion(*EVMVersion::fromString("byzantium")); + CHECK_WARNING(sourceCode, "Use of the \"var\" keyword is deprecated"); + m_compiler.setEVMVersion(*EVMVersion::fromString("homestead")); CHECK_ERROR(sourceCode, TypeError, "Explicit type conversion not allowed from \"inaccessible dynamic type\" to \"bytes storage pointer\"."); } |