Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eof: Implement stack height calculation #15555

Merged
merged 1 commit into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 89 additions & 2 deletions libevmasm/Assembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include <fstream>
#include <limits>
#include <iterator>
#include <stack>

using namespace solidity;
using namespace solidity::evmasm;
Expand Down Expand Up @@ -971,6 +972,93 @@ void appendBigEndianUint16(bytes& _dest, ValueT _value)
assertThrow(_value <= 0xFFFF, AssemblyException, "");
appendBigEndian(_dest, 2, static_cast<size_t>(_value));
}

// Calculates maximum stack height for given code section. According to EIP5450 https://eips.ethereum.org/EIPS/eip-5450
uint16_t calculateMaxStackHeight(Assembly::CodeSection const& _section)
{
static auto constexpr UNVISITED = std::numeric_limits<size_t>::max();

AssemblyItems const& items = _section.items;
solAssert(!items.empty());
uint16_t overallMaxHeight = _section.inputs;
std::stack<size_t> worklist;
std::vector<size_t> maxStackHeights(items.size(), UNVISITED);

// Init first item stack height to number of inputs to the code section
// maxStackHeights stores stack height for an item before the item execution
maxStackHeights[0] = _section.inputs;
// Push first item index to the worklist
worklist.push(0u);
while (!worklist.empty())
{
size_t idx = worklist.top();
worklist.pop();
AssemblyItem const& item = items[idx];
size_t stackHeightChange = item.deposit();
size_t currentMaxHeight = maxStackHeights[idx];
solAssert(currentMaxHeight != UNVISITED);

std::vector<size_t> successors;

// Add next instruction to successors for non-control-flow-changing instructions
if (
!(item.hasInstruction() && SemanticInformation::terminatesControlFlow(item.instruction())) &&
item.type() != RelativeJump &&
item.type() != RetF &&
item.type() != JumpF
)
{
solAssert(idx < items.size() - 1, "No terminating instruction.");
successors.emplace_back(idx + 1);
}

// Add jumps destinations to successors
// TODO: Remember to add RJUMPV when it is supported.
if (item.type() == RelativeJump || item.type() == ConditionalRelativeJump)
cameel marked this conversation as resolved.
Show resolved Hide resolved
{
auto const tagIt = std::find(items.begin(), items.end(), item.tag());
solAssert(tagIt != items.end(), "Tag not found.");
successors.emplace_back(static_cast<size_t>(std::distance(items.begin(), tagIt)));
// If backward jump the successor must be already visited.
solAssert(idx <= successors.back() || maxStackHeights[successors.back()] != UNVISITED);
}

solRequire(
currentMaxHeight + stackHeightChange <= std::numeric_limits<uint16_t>::max(),
AssemblyException,
"Stack overflow in EOF function."
);
overallMaxHeight = std::max(overallMaxHeight, static_cast<uint16_t>(currentMaxHeight + stackHeightChange));
currentMaxHeight += stackHeightChange;

// Set stack height for all instruction successors
for (size_t successor: successors)
{
solAssert(successor < maxStackHeights.size());
// Set stack height for newly visited
if (maxStackHeights[successor] == UNVISITED)
{
maxStackHeights[successor] = currentMaxHeight;
worklist.push(successor);
}
else
{
solAssert(successor < maxStackHeights.size());
// For backward jump successor stack height must be equal
if (successor < idx)
solAssert(maxStackHeights[successor] == currentMaxHeight, "Stack height mismatch.");

// If successor stack height is smaller update it and recalculate
if (currentMaxHeight > maxStackHeights[successor])
{
maxStackHeights[successor] = currentMaxHeight;
worklist.push(successor);
}
}
}
}
return overallMaxHeight;
}
}

std::tuple<bytes, std::vector<size_t>, size_t> Assembly::createEOFHeader(std::set<ContainerID> const& _referencedSubIds) const
Expand Down Expand Up @@ -1015,8 +1103,7 @@ std::tuple<bytes, std::vector<size_t>, size_t> Assembly::createEOFHeader(std::se
{
retBytecode.push_back(codeSection.inputs);
retBytecode.push_back(codeSection.outputs);
// TODO: Add stack height calculation
appendBigEndianUint16(retBytecode, 0xFFFFu);
appendBigEndianUint16(retBytecode, calculateMaxStackHeight(codeSection));
}

return {retBytecode, codeSectionSizePositions, dataSectionSizePosition};
Expand Down
2 changes: 1 addition & 1 deletion test/cmdlineTests/strict_asm_eof_container_prague/output
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ object "object" {


Binary representation:
ef0001010004020001001503000200370037040000000080ffff5f808080ec005f525f808080ec0160205260405ff3ef00010100040200010004030001001b040000000080ffff5f80ee00ef00010100040200010008040000000080ffff60015f5260205ffdef00010100040200010004030001001b040000000080ffff5f80ee00ef00010100040200010008040000000080ffff60205f5260205ffd
ef000101000402000100150300020037003704000000008000045f808080ec005f525f808080ec0160205260405ff3ef00010100040200010004030001001b04000000008000025f80ee00ef00010100040200010008040000000080000260015f5260205ffdef00010100040200010004030001001b04000000008000025f80ee00ef00010100040200010008040000000080000260205f5260205ffd

Text representation:
0x00
Expand Down
2 changes: 1 addition & 1 deletion test/cmdlineTests/strict_asm_eof_dataloadn_prague/output
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ object "a" {


Binary representation:
ef0001010004020001000904002d000080ffffd1000d5f5260205ff348656c6c6f2c20576f726c6421
ef0001010004020001000904002d0000800002d1000d5f5260205ff348656c6c6f2c20576f726c6421

Text representation:
auxdataloadn{0}
Expand Down
4 changes: 2 additions & 2 deletions test/libyul/objectCompiler/eof/256_subcontainers.yul

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions test/libyul/objectCompiler/eof/creation_with_immutables.yul
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,6 @@ object "a" {
// return
// }
// }
// Bytecode: ef0001010004020001000c030001008704000d000080ffff5f808080ec005f5260205ff3ef0001010004020001004c0300010023040000000080ffff7f11223344556677889900112233445566778899001122334455667788990011225f527f112233445566778899001122334455667788990011223344556677889900112260205260405fee00ef00010100040200010010040040000080ffffd10000d10020905f5260205260405ff348656c6c6f2c20576f726c6421
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP 0xC SUB STOP ADD STOP DUP8 DIV STOP 0xD STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT PUSH0 DUP1 DUP1 DUP1 EOFCREATE 0x0 PUSH0 MSTORE PUSH1 0x20 PUSH0 RETURN 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP 0x4C SUB STOP ADD STOP 0x23 DIV STOP STOP STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT PUSH32 0x1122334455667788990011223344556677889900112233445566778899001122 PUSH0 MSTORE PUSH32 0x1122334455667788990011223344556677889900112233445566778899001122 PUSH1 0x20 MSTORE PUSH1 0x40 PUSH0 RETURNCONTRACT 0x0 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP LT DIV STOP BLOCKHASH STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT DATALOADN 0x0 DATALOADN 0x20 SWAP1 PUSH0 MSTORE PUSH1 0x20 MSTORE PUSH1 0x40 PUSH0 RETURN BASEFEE PUSH6 0x6C6C6F2C2057 PUSH16 0x726C6421000000000000000000000000
// Bytecode: ef0001010004020001000c030001008704000d00008000045f808080ec005f5260205ff3ef0001010004020001004c030001002304000000008000027f11223344556677889900112233445566778899001122334455667788990011225f527f112233445566778899001122334455667788990011223344556677889900112260205260405fee00ef000101000402000100100400400000800003d10000d10020905f5260205260405ff348656c6c6f2c20576f726c6421
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP 0xC SUB STOP ADD STOP DUP8 DIV STOP 0xD STOP STOP DUP1 STOP DIV PUSH0 DUP1 DUP1 DUP1 EOFCREATE 0x0 PUSH0 MSTORE PUSH1 0x20 PUSH0 RETURN 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP 0x4C SUB STOP ADD STOP 0x23 DIV STOP STOP STOP STOP DUP1 STOP MUL PUSH32 0x1122334455667788990011223344556677889900112233445566778899001122 PUSH0 MSTORE PUSH32 0x1122334455667788990011223344556677889900112233445566778899001122 PUSH1 0x20 MSTORE PUSH1 0x40 PUSH0 RETURNCONTRACT 0x0 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP LT DIV STOP BLOCKHASH STOP STOP DUP1 STOP SUB DATALOADN 0x0 DATALOADN 0x20 SWAP1 PUSH0 MSTORE PUSH1 0x20 MSTORE PUSH1 0x40 PUSH0 RETURN BASEFEE PUSH6 0x6C6C6F2C2057 PUSH16 0x726C6421000000000000000000000000
// SourceMappings: 80:1:0:-:0;56:26;;;;53:1;46:37;106:2;103:1;96:13
4 changes: 2 additions & 2 deletions test/libyul/objectCompiler/eof/dataloadn.yul
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ object "a" {
// return
// stop
// data_acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f 48656c6c6f2c20576f726c6421
// Bytecode: ef0001010004020001000904002d000080ffffd1000d5f5260205ff348656c6c6f2c20576f726c6421
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP MULMOD DIV STOP 0x2D STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT DATALOADN 0xD PUSH0 MSTORE PUSH1 0x20 PUSH0 RETURN BASEFEE PUSH6 0x6C6C6F2C2057 PUSH16 0x726C6421000000000000000000000000
// Bytecode: ef0001010004020001000904002d0000800002d1000d5f5260205ff348656c6c6f2c20576f726c6421
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP MULMOD DIV STOP 0x2D STOP STOP DUP1 STOP MUL DATALOADN 0xD PUSH0 MSTORE PUSH1 0x20 PUSH0 RETURN BASEFEE PUSH6 0x6C6C6F2C2057 PUSH16 0x726C6421000000000000000000000000
// SourceMappings: 56:15:0:-:0;53:1;46:26;95:2;92:1;85:13
4 changes: 2 additions & 2 deletions test/libyul/objectCompiler/eof/functions.yul
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,6 @@ object "a" {
// dup1
// revert
// }
// Bytecode: ef000101000c020003001400090003040000000080ffff0101ffff0080ffff5f35e300015f52602035e1000460205ff3e50002e100036063e46005e45f80fd
// Opcodes: 0xEF STOP ADD ADD STOP 0xC MUL STOP SUB STOP EQ STOP MULMOD STOP SUB DIV STOP STOP STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT ADD ADD SELFDESTRUCT SELFDESTRUCT STOP DUP1 SELFDESTRUCT SELFDESTRUCT PUSH0 CALLDATALOAD CALLF 0x1 PUSH0 MSTORE PUSH1 0x20 CALLDATALOAD RJUMPI 0x4 PUSH1 0x20 PUSH0 RETURN JUMPF 0x2 RJUMPI 0x3 PUSH1 0x63 RETF PUSH1 0x5 RETF PUSH0 DUP1 REVERT
// Bytecode: ef000101000c020003001400090003040000000080000201010001008000025f35e300015f52602035e1000460205ff3e50002e100036063e46005e45f80fd
// Opcodes: 0xEF STOP ADD ADD STOP 0xC MUL STOP SUB STOP EQ STOP MULMOD STOP SUB DIV STOP STOP STOP STOP DUP1 STOP MUL ADD ADD STOP ADD STOP DUP1 STOP MUL PUSH0 CALLDATALOAD CALLF 0x1 PUSH0 MSTORE PUSH1 0x20 CALLDATALOAD RJUMPI 0x4 PUSH1 0x20 PUSH0 RETURN JUMPF 0x2 RJUMPI 0x3 PUSH1 0x63 RETF PUSH1 0x5 RETF PUSH0 DUP1 REVERT
// SourceMappings: 74:1:0:-:0;61:15;56:21::i;53:1::-;46:32;107:2;94:16;91:37;22:364;151:2;148:1;141:13;111:17;113:13::i217:77:0:-:0;203:121;312:2;173:151::o;234:60::-;257:1;275:5::o376:1:0:-:0;366:12;
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,6 @@ object "a" {
// /* "source":421:649 */
// stop
// }
// Bytecode: ef0001010004020001000c030001005b040000000080ffff5f808080ec005f5260205ff3ef00010100040200010048040000000080ffff7f11223344556677889900112233445566778899001122334455667788990011225f527f112233445566778899001122334455667788990011223344556677889900112260205200
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP 0xC SUB STOP ADD STOP JUMPDEST DIV STOP STOP STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT PUSH0 DUP1 DUP1 DUP1 EOFCREATE 0x0 PUSH0 MSTORE PUSH1 0x20 PUSH0 RETURN 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP BASEFEE DIV STOP STOP STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT PUSH32 0x1122334455667788990011223344556677889900112233445566778899001122 PUSH0 MSTORE PUSH32 0x1122334455667788990011223344556677889900112233445566778899001122 PUSH1 0x20 MSTORE STOP
// Bytecode: ef0001010004020001000c030001005b04000000008000045f808080ec005f5260205ff3ef0001010004020001004804000000008000027f11223344556677889900112233445566778899001122334455667788990011225f527f112233445566778899001122334455667788990011223344556677889900112260205200
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP 0xC SUB STOP ADD STOP JUMPDEST DIV STOP STOP STOP STOP DUP1 STOP DIV PUSH0 DUP1 DUP1 DUP1 EOFCREATE 0x0 PUSH0 MSTORE PUSH1 0x20 PUSH0 RETURN 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP BASEFEE DIV STOP STOP STOP STOP DUP1 STOP MUL PUSH32 0x1122334455667788990011223344556677889900112233445566778899001122 PUSH0 MSTORE PUSH32 0x1122334455667788990011223344556677889900112233445566778899001122 PUSH1 0x20 MSTORE STOP
// SourceMappings: 80:1:0:-:0;56:26;;;;53:1;46:37;106:2;103:1;96:13
4 changes: 2 additions & 2 deletions test/libyul/objectCompiler/eof/rjumps.yul
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ object "a" {
// mstore
// /* "source":54:70 */
// rjump{tag_2}
// Bytecode: ef00010100040200010010040000000080ffff6001e1000460205ff360015f52e0fff5
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP LT DIV STOP STOP STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT PUSH1 0x1 RJUMPI 0x4 PUSH1 0x20 PUSH0 RETURN PUSH1 0x1 PUSH0 MSTORE RJUMP 0xFFF5
// Bytecode: ef0001010004020001001004000000008000026001e1000460205ff360015f52e0fff5
// Opcodes: 0xEF STOP ADD ADD STOP DIV MUL STOP ADD STOP LT DIV STOP STOP STOP STOP DUP1 STOP MUL PUSH1 0x1 RJUMPI 0x4 PUSH1 0x20 PUSH0 RETURN PUSH1 0x1 PUSH0 MSTORE RJUMP 0xFFF5
// SourceMappings: 49:4:0:-:0;46:24;22:90;93:2;90:1;83:13;54:16;66:1;63;56:12;54:16