| 2539 | } |
| 2540 | |
| 2541 | std::string YulUtilFunctions::accessCalldataTailFunction(Type const& _type) |
| 2542 | { |
| 2543 | solAssert(_type.isDynamicallyEncoded(), ""); |
| 2544 | solAssert(_type.dataStoredIn(DataLocation::CallData), ""); |
| 2545 | std::string functionName = "access_calldata_tail_" + _type.identifier(); |
| 2546 | return m_functionCollector.createFunction(functionName, [&]() { |
| 2547 | return Whiskers(R"( |
| 2548 | function <functionName>(base_ref, ptr_to_tail) -> addr<?dynamicallySized>, length</dynamicallySized> { |
| 2549 | let rel_offset_of_tail := calldataload(ptr_to_tail) |
| 2550 | if iszero(slt(rel_offset_of_tail, sub(sub(calldatasize(), base_ref), sub(<neededLength>, 1)))) { <invalidCalldataTailOffset>() } |
| 2551 | addr := add(base_ref, rel_offset_of_tail) |
| 2552 | <?dynamicallySized> |
| 2553 | length := calldataload(addr) |
| 2554 | if gt(length, 0xffffffffffffffff) { <invalidCalldataTailLength>() } |
| 2555 | addr := add(addr, 32) |
| 2556 | if sgt(addr, sub(calldatasize(), mul(length, <calldataStride>))) { <shortCalldataTail>() } |
| 2557 | </dynamicallySized> |
| 2558 | } |
| 2559 | )") |
| 2560 | ("functionName", functionName) |
| 2561 | ("dynamicallySized", _type.isDynamicallySized()) |
| 2562 | ("neededLength", toCompactHexWithPrefix(_type.calldataEncodedTailSize())) |
| 2563 | ("calldataStride", toCompactHexWithPrefix(_type.isDynamicallySized() ? dynamic_cast<ArrayType const&>(_type).calldataStride() : 0)) |
| 2564 | ("invalidCalldataTailOffset", revertReasonIfDebugFunction("Invalid calldata tail offset")) |
| 2565 | ("invalidCalldataTailLength", revertReasonIfDebugFunction("Invalid calldata tail length")) |
| 2566 | ("shortCalldataTail", revertReasonIfDebugFunction("Calldata tail too short")) |
| 2567 | .render(); |
| 2568 | }); |
| 2569 | } |
| 2570 | |
| 2571 | std::string YulUtilFunctions::nextArrayElementFunction(ArrayType const& _type) |
| 2572 | { |
no test coverage detected