From e73fe1727708c656e13d4d944e0e8ccd12991e0d Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Fri, 5 Jun 2020 10:37:00 +0200 Subject: [PATCH] Fixing ICE on calling externally a function that returns calldata pointers Co-authored-by: chriseth --- Changelog.md | 4 +--- libsolidity/ast/TypeProvider.h | 12 +++++++++-- libsolidity/ast/Types.cpp | 20 +++++++++++++------ .../calldata/calldata_bytes_external.sol | 12 +++++++++++ 4 files changed, 37 insertions(+), 11 deletions(-) create mode 100644 test/libsolidity/semanticTests/calldata/calldata_bytes_external.sol diff --git a/Changelog.md b/Changelog.md index 5da6cb372..83801c65c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,15 +2,13 @@ Language Features: - Compiler Features: * Yul: Raise warning for switch statements that only have a default and no other cases. - Bugfixes: * SMTChecker: Fix internal error when encoding tuples of tuples. * SMTChecker: Fix aliasing soundness after pushing to an array pointer. - + * Type system: Fix internal compiler error on calling externally a function that returns variables with calldata location. ### 0.6.9 (2020-06-04) diff --git a/libsolidity/ast/TypeProvider.h b/libsolidity/ast/TypeProvider.h index 38f2642eb..a86542d16 100644 --- a/libsolidity/ast/TypeProvider.h +++ b/libsolidity/ast/TypeProvider.h @@ -112,14 +112,22 @@ public: /// @returns a copy of @a _type having the same location as this (and is not a pointer type) /// if _type is a reference type and an unmodified copy of _type otherwise. /// This function is mostly useful to modify inner types appropriately. - static Type const* withLocationIfReference(DataLocation _location, Type const* _type) + static Type const* withLocationIfReference(DataLocation _location, Type const* _type, bool _isPointer = false) { if (auto refType = dynamic_cast(_type)) - return withLocation(refType, _location, false); + return withLocation(refType, _location, _isPointer); return _type; } + static bool isReferenceWithLocation(Type const* _type, DataLocation _location) + { + if (auto const* refType = dynamic_cast(_type)) + if (refType->location() == _location) + return true; + return false; + } + /// @returns the internally-facing or externally-facing type of a function or the type of a function declaration. static FunctionType const* function(FunctionDefinition const& _function, FunctionType::Kind _kind = FunctionType::Kind::Declaration); diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 66681ea10..8114be800 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -3445,13 +3445,21 @@ FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary, TypePointers parameterTypes; for (auto const& t: m_parameterTypes) - { - auto refType = dynamic_cast(t); - if (refType && refType->location() == DataLocation::CallData) - parameterTypes.push_back(TypeProvider::withLocation(refType, DataLocation::Memory, true)); + if (TypeProvider::isReferenceWithLocation(t, DataLocation::CallData)) + parameterTypes.push_back( + TypeProvider::withLocationIfReference(DataLocation::Memory, t, true) + ); else parameterTypes.push_back(t); - } + + TypePointers returnParameterTypes; + for (auto const& returnParamType: m_returnParameterTypes) + if (TypeProvider::isReferenceWithLocation(returnParamType, DataLocation::CallData)) + returnParameterTypes.push_back( + TypeProvider::withLocationIfReference(DataLocation::Memory, returnParamType, true) + ); + else + returnParameterTypes.push_back(returnParamType); Kind kind = m_kind; if (_inLibrary) @@ -3465,7 +3473,7 @@ FunctionTypePointer FunctionType::asExternallyCallableFunction(bool _inLibrary, return TypeProvider::function( parameterTypes, - m_returnParameterTypes, + returnParameterTypes, m_parameterNames, m_returnParameterNames, kind, diff --git a/test/libsolidity/semanticTests/calldata/calldata_bytes_external.sol b/test/libsolidity/semanticTests/calldata/calldata_bytes_external.sol new file mode 100644 index 000000000..9917e736a --- /dev/null +++ b/test/libsolidity/semanticTests/calldata/calldata_bytes_external.sol @@ -0,0 +1,12 @@ +contract CalldataTest { + function test(bytes calldata x) public returns (bytes calldata) { + return x; + } + function tester(bytes calldata x) public returns (byte) { + return this.test(x)[2]; + } +} +// ==== +// EVMVersion: >=byzantium +// ---- +// tester(bytes): 0x20, 0x08, "abcdefgh" -> "c"