Merge pull request #8416 from ethereum/reuseYulCalldataTailAccess

Fix yul calldata tail access functions and reuse them for old codegen.
This commit is contained in:
chriseth 2020-03-09 15:10:48 +01:00 committed by GitHub
commit b7c001eb7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 21 additions and 53 deletions

View File

@ -121,56 +121,12 @@ void CompilerUtils::returnDataToArray()
void CompilerUtils::accessCalldataTail(Type const& _type) void CompilerUtils::accessCalldataTail(Type const& _type)
{ {
solAssert(_type.dataStoredIn(DataLocation::CallData), ""); m_context << Instruction::SWAP1;
solAssert(_type.isDynamicallyEncoded(), ""); m_context.callYulFunction(
m_context.utilFunctions().accessCalldataTailFunction(_type),
unsigned int tailSize = _type.calldataEncodedTailSize(); 2,
solAssert(tailSize > 1, ""); _type.isDynamicallySized() ? 2 : 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(<neededLength>, 1)))) { <revertString> }
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: <absolute_offset_of_tail> <garbage>
if (!_type.isDynamicallySized())
{
m_context << Instruction::POP;
// stack layout: <absolute_offset_of_tail>
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<ArrayType const*>(&_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) { <revertString> }
if sgt(base_ref, sub(calldatasize(), mul(length, <calldataStride>))) { revert(0, 0) }
})")
("calldataStride", toCompactHexWithPrefix(calldataStride))
("revertString", m_context.revertReasonIfDebug("Invalid calldata tail length"))
.render(),
{"base_ref", "length"}
);
// stack layout: <absolute_offset_of_tail> <length>
}
} }
unsigned CompilerUtils::loadFromMemory( unsigned CompilerUtils::loadFromMemory(

View File

@ -942,13 +942,13 @@ string YulUtilFunctions::accessCalldataTailFunction(Type const& _type)
return Whiskers(R"( return Whiskers(R"(
function <functionName>(base_ref, ptr_to_tail) -> addr<?dynamicallySized>, length</dynamicallySized> { function <functionName>(base_ref, ptr_to_tail) -> addr<?dynamicallySized>, length</dynamicallySized> {
let rel_offset_of_tail := calldataload(ptr_to_tail) let rel_offset_of_tail := calldataload(ptr_to_tail)
if iszero(slt(rel_offset_of_tail, sub(sub(calldatasize(), base_ref), sub(<neededLength>, 1)))) { revert(0, 0) } if iszero(slt(rel_offset_of_tail, sub(sub(calldatasize(), base_ref), sub(<neededLength>, 1)))) { <invalidCalldataTailOffset> }
addr := add(base_ref, rel_offset_of_tail) addr := add(base_ref, rel_offset_of_tail)
<?dynamicallySized> <?dynamicallySized>
length := calldataload(addr) length := calldataload(addr)
if gt(length, 0xffffffffffffffff) { revert(0, 0) } if gt(length, 0xffffffffffffffff) { <invalidCalldataTailLength> }
if sgt(base_ref, sub(calldatasize(), mul(length, <calldataStride>))) { revert(0, 0) }
addr := add(addr, 32) addr := add(addr, 32)
if sgt(addr, sub(calldatasize(), mul(length, <calldataStride>))) { <shortCalldataTail> }
</dynamicallySized> </dynamicallySized>
} }
)") )")
@ -956,6 +956,9 @@ string YulUtilFunctions::accessCalldataTailFunction(Type const& _type)
("dynamicallySized", _type.isDynamicallySized()) ("dynamicallySized", _type.isDynamicallySized())
("neededLength", toCompactHexWithPrefix(_type.calldataEncodedTailSize())) ("neededLength", toCompactHexWithPrefix(_type.calldataEncodedTailSize()))
("calldataStride", toCompactHexWithPrefix(_type.isDynamicallySized() ? dynamic_cast<ArrayType const&>(_type).calldataStride() : 0)) ("calldataStride", toCompactHexWithPrefix(_type.isDynamicallySized() ? dynamic_cast<ArrayType const&>(_type).calldataStride() : 0))
("invalidCalldataTailOffset", revertReasonIfDebug("Invalid calldata tail offset"))
("invalidCalldataTailLength", revertReasonIfDebug("Invalid calldata tail length"))
("shortCalldataTail", revertReasonIfDebug("Calldata tail too short"))
.render(); .render();
}); });
} }

View File

@ -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"