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,57 +121,13 @@ 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(
|
||||||
unsigned _offset,
|
unsigned _offset,
|
||||||
|
@ -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();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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