Skip to content

Commit c696e38

Browse files
committed
baseline: Stack height check using over-aligned stack space pointer
1 parent e651019 commit c696e38

File tree

2 files changed

+22
-5
lines changed

2 files changed

+22
-5
lines changed

lib/evmone/baseline_execution.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ namespace
4242
/// or EVMC_SUCCESS if everything is fine.
4343
template <Opcode Op>
4444
inline evmc_status_code check_requirements(const CostTable& cost_table, int64_t& gas_left,
45-
const uint256* stack_top, const uint256* stack_bottom) noexcept
45+
const uint256* stack_end, [[maybe_unused]] const uint256* stack_bottom) noexcept
4646
{
4747
static_assert(
4848
!instr::has_const_gas_cost(Op) || instr::gas_costs[EVMC_FRONTIER][Op] != instr::undefined,
@@ -63,20 +63,36 @@ inline evmc_status_code check_requirements(const CostTable& cost_table, int64_t&
6363
}
6464
}
6565

66+
const auto stack_end_u = reinterpret_cast<uintptr_t>(stack_end);
67+
68+
const auto stack_height = stack_end_u % StackSpace::alignment / sizeof(uint256);
69+
70+
assert(stack_height == static_cast<uintptr_t>(stack_end - stack_bottom));
71+
6672
// Check stack requirements first. This order is not required,
6773
// but it is nicer because a complete gas check may need to inspect operands.
6874
if constexpr (instr::traits[Op].stack_height_change > 0)
6975
{
7076
static_assert(instr::traits[Op].stack_height_change == 1,
7177
"unexpected instruction with multiple results");
72-
if (INTX_UNLIKELY(stack_top == stack_bottom + StackSpace::limit))
78+
79+
const auto overflow = (stack_end_u & 0x8000) != 0;
80+
[[maybe_unused]] const auto expected_overflow = stack_height == StackSpace::limit;
81+
assert(overflow == expected_overflow);
82+
83+
if (INTX_UNLIKELY(overflow))
7384
return EVMC_STACK_OVERFLOW;
7485
}
7586
if constexpr (instr::traits[Op].stack_height_required > 0)
7687
{
7788
// Check stack underflow using pointer comparison <= (better optimization).
7889
static constexpr auto min_offset = instr::traits[Op].stack_height_required - 1;
79-
if (INTX_UNLIKELY(stack_top <= stack_bottom + min_offset))
90+
const auto arg0 = stack_end - 1 - min_offset;
91+
92+
const auto underflow = (reinterpret_cast<uintptr_t>(arg0) & 0x8000) != 0;
93+
assert(underflow == (stack_height <= min_offset));
94+
95+
if (INTX_UNLIKELY(underflow))
8096
return EVMC_STACK_UNDERFLOW;
8197
}
8298

lib/evmone/execution_state.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,17 @@ class StackSpace
3535
static constexpr auto limit = 1024;
3636

3737
/// Stack space items are aligned to 256 bits for better packing in cache lines.
38-
static constexpr auto alignment = sizeof(uint256);
38+
static constexpr auto alignment = 2 * limit * sizeof(uint256);
3939

40-
alignas(alignment) uint256 items[limit];
40+
alignas(alignment) uint256 items[2 * limit];
4141
};
4242

4343
/// The storage allocated for maximum possible number of items.
4444
std::unique_ptr<Storage> m_stack_space = std::make_unique<Storage>();
4545

4646
public:
4747
static constexpr auto limit = Storage::limit;
48+
static constexpr auto alignment = Storage::alignment;
4849

4950
/// Returns the pointer to the "bottom", i.e. below the stack space.
5051
[[nodiscard]] uint256* bottom() noexcept { return &m_stack_space->items[0]; }

0 commit comments

Comments
 (0)