mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8416 from ethereum/reuseYulCalldataTailAccess
Fix yul calldata tail access functions and reuse them for old codegen.
This commit is contained in:
commit
b7c001eb7f
@ -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(<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."
|
||||
m_context << Instruction::SWAP1;
|
||||
m_context.callYulFunction(
|
||||
m_context.utilFunctions().accessCalldataTailFunction(_type),
|
||||
2,
|
||||
_type.isDynamicallySized() ? 2 : 1
|
||||
);
|
||||
}
|
||||
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(
|
||||
|
@ -942,13 +942,13 @@ string YulUtilFunctions::accessCalldataTailFunction(Type const& _type)
|
||||
return Whiskers(R"(
|
||||
function <functionName>(base_ref, ptr_to_tail) -> addr<?dynamicallySized>, length</dynamicallySized> {
|
||||
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)
|
||||
<?dynamicallySized>
|
||||
length := calldataload(addr)
|
||||
if gt(length, 0xffffffffffffffff) { revert(0, 0) }
|
||||
if sgt(base_ref, sub(calldatasize(), mul(length, <calldataStride>))) { revert(0, 0) }
|
||||
if gt(length, 0xffffffffffffffff) { <invalidCalldataTailLength> }
|
||||
addr := add(addr, 32)
|
||||
if sgt(addr, sub(calldatasize(), mul(length, <calldataStride>))) { <shortCalldataTail> }
|
||||
</dynamicallySized>
|
||||
}
|
||||
)")
|
||||
@ -956,6 +956,9 @@ string YulUtilFunctions::accessCalldataTailFunction(Type const& _type)
|
||||
("dynamicallySized", _type.isDynamicallySized())
|
||||
("neededLength", toCompactHexWithPrefix(_type.calldataEncodedTailSize()))
|
||||
("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();
|
||||
});
|
||||
}
|
||||
|
@ -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"
|
Loading…
Reference in New Issue
Block a user