Skip to content

Commit

Permalink
Merge pull request #15555 from ipsilon/stack-height
Browse files Browse the repository at this point in the history
eof: Implement stack height calculation
  • Loading branch information
cameel authored Dec 6, 2024
2 parents 32ae821 + 4edb59d commit 9ec58fa
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 16 deletions.
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)
{
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

0 comments on commit 9ec58fa

Please sign in to comment.