mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Decode dynamic data.
This commit is contained in:
parent
cc2f71e4ac
commit
c2709a2d8e
@ -1551,7 +1551,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
|||||||
_functionCall.expression().annotation().isPure &&
|
_functionCall.expression().annotation().isPure &&
|
||||||
functionType->isPure();
|
functionType->isPure();
|
||||||
|
|
||||||
bool allowDynamicTypes = false; // @TODO
|
bool allowDynamicTypes = m_evmVersion.supportsReturndata();
|
||||||
if (!functionType)
|
if (!functionType)
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(_functionCall.location(), "Type is not callable");
|
m_errorReporter.typeError(_functionCall.location(), "Type is not callable");
|
||||||
|
@ -253,6 +253,9 @@ string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
|
|||||||
templ("body", w.render());
|
templ("body", w.render());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Type::Category::InaccessibleDynamic:
|
||||||
|
templ("body", "cleaned := 0");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
solAssert(false, "Cleanup of type " + _type.identifier() + " requested.");
|
solAssert(false, "Cleanup of type " + _type.identifier() + " requested.");
|
||||||
}
|
}
|
||||||
|
@ -198,7 +198,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
|
|||||||
if (type->category() == Type::Category::Array)
|
if (type->category() == Type::Category::Array)
|
||||||
{
|
{
|
||||||
auto const& arrayType = dynamic_cast<ArrayType const&>(*type);
|
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)
|
if (_fromMemory)
|
||||||
{
|
{
|
||||||
solUnimplementedAssert(
|
solUnimplementedAssert(
|
||||||
@ -308,7 +308,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString());
|
solAssert(!type->isDynamicallyEncoded(), "Unknown dynamically sized type: " + type->toString());
|
||||||
loadFromMemoryDynamic(*type, !_fromMemory, true);
|
loadFromMemoryDynamic(*type, !_fromMemory, true);
|
||||||
// stack: v1 v2 ... v(k-1) input_end base_offset v(k) mem_offset
|
// stack: v1 v2 ... v(k-1) input_end base_offset v(k) mem_offset
|
||||||
moveToStackTop(1, type->sizeOnStack());
|
moveToStackTop(1, type->sizeOnStack());
|
||||||
|
@ -1618,22 +1618,27 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
m_context.experimentalFeatureActive(ExperimentalFeature::V050) &&
|
m_context.experimentalFeatureActive(ExperimentalFeature::V050) &&
|
||||||
m_context.evmVersion().hasStaticCall();
|
m_context.evmVersion().hasStaticCall();
|
||||||
|
|
||||||
bool allowDynamicTypes = false; // @TODO
|
bool haveReturndatacopy = m_context.evmVersion().supportsReturndata();
|
||||||
unsigned retSize = 0;
|
unsigned retSize = 0;
|
||||||
TypePointers returnTypes;
|
TypePointers returnTypes;
|
||||||
if (returnSuccessCondition)
|
if (returnSuccessCondition)
|
||||||
retSize = 0; // return value actually is success condition
|
retSize = 0; // return value actually is success condition
|
||||||
else if (allowDynamicTypes)
|
else if (haveReturndatacopy)
|
||||||
returnTypes = _functionType.returnParameterTypes();
|
returnTypes = _functionType.returnParameterTypes();
|
||||||
else
|
else
|
||||||
{
|
|
||||||
returnTypes = _functionType.returnParameterTypesWithoutDynamicTypes();
|
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.");
|
solAssert(haveReturndatacopy, "");
|
||||||
retSize += retType->calldataEncodedSize();
|
dynamicReturnSize = true;
|
||||||
|
retSize = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
retSize += retType->calldataEncodedSize();
|
||||||
|
|
||||||
// Evaluate arguments.
|
// Evaluate arguments.
|
||||||
TypePointers argumentTypes;
|
TypePointers argumentTypes;
|
||||||
@ -1834,17 +1839,39 @@ void ExpressionCompiler::appendExternalFunctionCall(
|
|||||||
else if (!returnTypes.empty())
|
else if (!returnTypes.empty())
|
||||||
{
|
{
|
||||||
utils().fetchFreeMemoryPointer();
|
utils().fetchFreeMemoryPointer();
|
||||||
bool memoryNeeded = false;
|
// Stack: return_data_start
|
||||||
for (auto const& retType: returnTypes)
|
|
||||||
{
|
// The old decoder did not allocate any memory (i.e. did not touch the free
|
||||||
utils().loadFromMemoryDynamic(*retType, false, true, true);
|
// memory pointer), but kept references to the return data for
|
||||||
if (dynamic_cast<ReferenceType const*>(retType.get()))
|
// (statically-sized) arrays
|
||||||
memoryNeeded = true;
|
bool needToUpdateFreeMemoryPtr = false;
|
||||||
}
|
if (dynamicReturnSize || m_context.experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2))
|
||||||
if (memoryNeeded)
|
needToUpdateFreeMemoryPtr = true;
|
||||||
utils().storeFreeMemoryPointer();
|
|
||||||
else
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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\".");
|
CHECK_ERROR(sourceCode, TypeError, "Explicit type conversion not allowed from \"inaccessible dynamic type\" to \"bytes storage pointer\".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user