aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity')
-rw-r--r--libsolidity/analysis/TypeChecker.cpp2
-rw-r--r--libsolidity/codegen/ABIFunctions.cpp3
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp4
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp57
4 files changed, 48 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);
}
}