mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Decode dynamic data.
This commit is contained in:
committed by
Alex Beregszaszi
parent
cc2f71e4ac
commit
c2709a2d8e
@@ -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)
|
||||
{
|
||||
utils().loadFromMemoryDynamic(*retType, false, true, true);
|
||||
if (dynamic_cast<ReferenceType const*>(retType.get()))
|
||||
memoryNeeded = true;
|
||||
}
|
||||
if (memoryNeeded)
|
||||
utils().storeFreeMemoryPointer();
|
||||
// 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
|
||||
m_context << Instruction::POP;
|
||||
for (auto const& retType: returnTypes)
|
||||
if (dynamic_cast<ReferenceType const*>(retType.get()))
|
||||
needToUpdateFreeMemoryPtr = true;
|
||||
|
||||
// Stack: return_data_start
|
||||
if (dynamicReturnSize)
|
||||
{
|
||||
solAssert(haveReturndatacopy, "");
|
||||
m_context.appendInlineAssembly("{ returndatacopy(return_data_start, 0, returndatasize()) }", {"return_data_start"});
|
||||
}
|
||||
else
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user