Skip to content

Commit

Permalink
eof: Detect unused inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
chfast committed Feb 4, 2025
1 parent dd38ff4 commit 173dab9
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 5 deletions.
8 changes: 8 additions & 0 deletions lib/evmone/eof.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ std::variant<EOFValidationError, int32_t> validate_max_stack_height(
const auto type = header.get_type(container, func_index);
std::vector<StackHeightRange> stack_heights(code.size());
stack_heights[0] = {type.inputs, type.inputs};
bool stack_bottom_reached = false;

Check warning on line 427 in lib/evmone/eof.cpp

View check run for this annotation

Codecov / codecov/patch

lib/evmone/eof.cpp#L427

Added line #L427 was not covered by tests

for (size_t i = 0; i < code.size();)
{
Expand Down Expand Up @@ -500,6 +501,8 @@ std::variant<EOFValidationError, int32_t> validate_max_stack_height(

if (stack_height.min < stack_height_required)
return EOFValidationError::stack_underflow;
else if (stack_height.min == stack_height_required)
stack_bottom_reached = true;

Check warning on line 505 in lib/evmone/eof.cpp

View check run for this annotation

Codecov / codecov/patch

lib/evmone/eof.cpp#L504-L505

Added lines #L504 - L505 were not covered by tests

const StackHeightRange next_stack_height{
stack_height.min + stack_height_change, stack_height.max + stack_height_change};
Expand Down Expand Up @@ -574,6 +577,9 @@ std::variant<EOFValidationError, int32_t> validate_max_stack_height(
i = next;
}

if (!stack_bottom_reached)
return EOFValidationError::unused_input;

Check warning on line 581 in lib/evmone/eof.cpp

View check run for this annotation

Codecov / codecov/patch

lib/evmone/eof.cpp#L580-L581

Added lines #L580 - L581 were not covered by tests

const auto max_stack_height_it = std::ranges::max_element(stack_heights,
[](StackHeightRange lhs, StackHeightRange rhs) noexcept { return lhs.max < rhs.max; });
return max_stack_height_it->max;
Expand Down Expand Up @@ -975,6 +981,8 @@ std::string_view get_error_message(EOFValidationError err) noexcept
return "container_size_above_limit";
case EOFValidationError::unreferenced_subcontainer:
return "unreferenced_subcontainer";
case EOFValidationError::unused_input:
return "unused_input";

Check warning on line 985 in lib/evmone/eof.cpp

View check run for this annotation

Codecov / codecov/patch

lib/evmone/eof.cpp#L984-L985

Added lines #L984 - L985 were not covered by tests
case EOFValidationError::impossible:
return "impossible";
}
Expand Down
1 change: 1 addition & 0 deletions lib/evmone/eof.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ enum class EOFValidationError
incompatible_container_kind,
container_size_above_limit,
unreferenced_subcontainer,
unused_input,

impossible,
};
Expand Down
2 changes: 2 additions & 0 deletions test/unittests/eof_validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ std::string_view get_tests_error_message(EOFValidationError err) noexcept
return "EOF_ContainerSizeAboveLimit";
case EOFValidationError::unreferenced_subcontainer:
return "EOF_UnreferencedSubcontainer";
case EOFValidationError::unused_input:
return "EOFException.UNUSED_INPUT";

Check warning on line 101 in test/unittests/eof_validation.cpp

View check run for this annotation

Codecov / codecov/patch

test/unittests/eof_validation.cpp#L100-L101

Added lines #L100 - L101 were not covered by tests
case EOFValidationError::impossible:
return "impossible";
}
Expand Down
10 changes: 5 additions & 5 deletions test/unittests/eof_validation_stack_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1241,11 +1241,11 @@ TEST_F(eof_validation, jumpf_to_nonreturning)

// Exactly required inputs on stack at JUMPF
add_test_case(eof_bytecode(3 * OP_PUSH0 + jumpf(1), 3).code(OP_STOP, 3, 0x80, 3),
EOFValidationError::success);
EOFValidationError::unused_input);

// Extra items on stack at JUMPF
add_test_case(eof_bytecode(4 * OP_PUSH0 + jumpf(1), 4).code(OP_STOP, 3, 0x80, 3),
EOFValidationError::success);
EOFValidationError::unused_input);

// Not enough inputs on stack at JUMPF
add_test_case(eof_bytecode(2 * OP_PUSH0 + jumpf(1), 2).code(OP_STOP, 3, 0x80, 3),
Expand All @@ -1266,7 +1266,7 @@ TEST_F(eof_validation, jumpf_to_nonreturning_variable_stack)

// JUMPF from [1, 3] stack to non-returning function with 1 inputs
add_test_case(eof_bytecode(varstack + jumpf(1), 3).code(Opcode{OP_INVALID}, 1, 0x80, 1),
EOFValidationError::success);
EOFValidationError::unused_input);

// JUMPF from [1, 3] stack to non-returning function with 0 inputs
add_test_case(eof_bytecode(varstack + jumpf(1), 3).code(Opcode{OP_INVALID}, 0, 0x80, 0),
Expand Down Expand Up @@ -1324,7 +1324,7 @@ TEST_F(eof_validation, jumpf_stack_overflow_variable_stack)
TEST_F(eof_validation, jumpf_with_inputs_stack_overflow)
{
add_test_case(eof_bytecode(1023 * push0() + jumpf(1), 1023).code(push0() + OP_STOP, 2, 0x80, 3),
EOFValidationError::success);
EOFValidationError::unused_input);

add_test_case(
eof_bytecode(1023 * push0() + jumpf(1), 1023).code(push0() + push0() + OP_STOP, 2, 0x80, 4),
Expand All @@ -1340,7 +1340,7 @@ TEST_F(eof_validation, jumpf_with_inputs_stack_overflow_variable_stack)
// JUMPF from [1021, 1023] stack to 2 inputs and 3 max stack
add_test_case(eof_bytecode(varstack + 1020 * push0() + jumpf(1), 1023)
.code(push0() + OP_STOP, 2, 0x80, 3),
EOFValidationError::success);
EOFValidationError::unused_input);

// JUMPF from [1021, 1023] stack to 2 inputs and 6 max stack - min and max stack overflow
add_test_case(eof_bytecode(varstack + 1020 * push0() + jumpf(1), 1023)
Expand Down

0 comments on commit 173dab9

Please sign in to comment.