From 919888ddbc470a628676586fcc1b21a7030b1042 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 2 Mar 2020 16:33:12 +0100 Subject: [PATCH] Use yul function for calldata tail access, fix checks and add additional revert reason. --- libsolidity/codegen/CompilerUtils.cpp | 56 ++----------------- libsolidity/codegen/YulUtilFunctions.cpp | 9 ++- .../revertStrings/calldata_tail_short.sol | 9 +++ 3 files changed, 21 insertions(+), 53 deletions(-) create mode 100644 test/libsolidity/semanticTests/revertStrings/calldata_tail_short.sol diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index b39633377..da82c1822 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -121,56 +121,12 @@ void CompilerUtils::returnDataToArray() void CompilerUtils::accessCalldataTail(Type const& _type) { - solAssert(_type.dataStoredIn(DataLocation::CallData), ""); - solAssert(_type.isDynamicallyEncoded(), ""); - - unsigned int tailSize = _type.calldataEncodedTailSize(); - solAssert(tailSize > 1, ""); - - // returns the absolute offset of the tail in "base_ref" - m_context.appendInlineAssembly(Whiskers(R"({ - let rel_offset_of_tail := calldataload(ptr_to_tail) - if iszero(slt(rel_offset_of_tail, sub(sub(calldatasize(), base_ref), sub(, 1)))) { } - base_ref := add(base_ref, rel_offset_of_tail) - })") - ("neededLength", toCompactHexWithPrefix(tailSize)) - ("revertString", m_context.revertReasonIfDebug("Invalid calldata tail offset")) - .render(), {"base_ref", "ptr_to_tail"}); - // stack layout: - - if (!_type.isDynamicallySized()) - { - m_context << Instruction::POP; - // stack layout: - solAssert( - _type.category() == Type::Category::Struct || - _type.category() == Type::Category::Array, - "Invalid dynamically encoded base type on tail access." - ); - } - else - { - auto const* arrayType = dynamic_cast(&_type); - solAssert(!!arrayType, "Invalid dynamically sized type."); - unsigned int calldataStride = arrayType->calldataStride(); - solAssert(calldataStride > 0, ""); - - // returns the absolute offset of the tail in "base_ref" - // and the length of the tail in "length" - m_context.appendInlineAssembly( - Whiskers(R"({ - length := calldataload(base_ref) - base_ref := add(base_ref, 0x20) - if gt(length, 0xffffffffffffffff) { } - if sgt(base_ref, sub(calldatasize(), mul(length, ))) { revert(0, 0) } - })") - ("calldataStride", toCompactHexWithPrefix(calldataStride)) - ("revertString", m_context.revertReasonIfDebug("Invalid calldata tail length")) - .render(), - {"base_ref", "length"} - ); - // stack layout: - } + m_context << Instruction::SWAP1; + m_context.callYulFunction( + m_context.utilFunctions().accessCalldataTailFunction(_type), + 2, + _type.isDynamicallySized() ? 2 : 1 + ); } unsigned CompilerUtils::loadFromMemory( diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 0472dd588..7a5036109 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -942,13 +942,13 @@ string YulUtilFunctions::accessCalldataTailFunction(Type const& _type) return Whiskers(R"( function (base_ref, ptr_to_tail) -> addr, length { let rel_offset_of_tail := calldataload(ptr_to_tail) - if iszero(slt(rel_offset_of_tail, sub(sub(calldatasize(), base_ref), sub(, 1)))) { revert(0, 0) } + if iszero(slt(rel_offset_of_tail, sub(sub(calldatasize(), base_ref), sub(, 1)))) { } addr := add(base_ref, rel_offset_of_tail) length := calldataload(addr) - if gt(length, 0xffffffffffffffff) { revert(0, 0) } - if sgt(base_ref, sub(calldatasize(), mul(length, ))) { revert(0, 0) } + if gt(length, 0xffffffffffffffff) { } addr := add(addr, 32) + if sgt(addr, sub(calldatasize(), mul(length, ))) { } } )") @@ -956,6 +956,9 @@ string YulUtilFunctions::accessCalldataTailFunction(Type const& _type) ("dynamicallySized", _type.isDynamicallySized()) ("neededLength", toCompactHexWithPrefix(_type.calldataEncodedTailSize())) ("calldataStride", toCompactHexWithPrefix(_type.isDynamicallySized() ? dynamic_cast(_type).calldataStride() : 0)) + ("invalidCalldataTailOffset", revertReasonIfDebug("Invalid calldata tail offset")) + ("invalidCalldataTailLength", revertReasonIfDebug("Invalid calldata tail length")) + ("shortCalldataTail", revertReasonIfDebug("Calldata tail too short")) .render(); }); } diff --git a/test/libsolidity/semanticTests/revertStrings/calldata_tail_short.sol b/test/libsolidity/semanticTests/revertStrings/calldata_tail_short.sol new file mode 100644 index 000000000..b6cc5800d --- /dev/null +++ b/test/libsolidity/semanticTests/revertStrings/calldata_tail_short.sol @@ -0,0 +1,9 @@ +pragma experimental ABIEncoderV2; +contract C { + function f(uint256[][] calldata x) external { x[0]; } +} +// ==== +// EVMVersion: >=byzantium +// revertStrings: debug +// ---- +// f(uint256[][]): 0x20, 1, 0x20, 2, 0x42 -> FAILURE, hex"08c379a0", 0x20, 23, "Calldata tail too short"