Skip to content

Commit

Permalink
Implement non-returning functions
Browse files Browse the repository at this point in the history
  • Loading branch information
gumb0 committed Jul 6, 2023
1 parent 22901b7 commit 4034c0f
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 8 deletions.
49 changes: 41 additions & 8 deletions lib/evmone/eof.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ constexpr auto CODE_SECTION_NUMBER_LIMIT = 1024;
constexpr auto MAX_STACK_HEIGHT = 0x03FF;
constexpr auto OUTPUTS_INPUTS_NUMBER_LIMIT = 0x7F;
constexpr auto REL_OFFSET_SIZE = sizeof(int16_t);
constexpr uint8_t NON_RETURNING_FUNCITON = 0x80;

using EOFSectionHeaders = std::array<std::vector<uint16_t>, MAX_SECTION + 1>;

Expand Down Expand Up @@ -182,13 +183,14 @@ std::variant<std::vector<EOFCodeType>, EOFValidationError> validate_types(
container[offset], container[offset + 1], read_uint16_be(&container[offset + 2]));
}

// check 1st section is (0, 0)
if (types[0].inputs != 0 || types[0].outputs != 0)
// check 1st section is (0, 0x80)
if (types[0].inputs != 0 || types[0].outputs != NON_RETURNING_FUNCITON)
return EOFValidationError::invalid_first_section_type;

for (const auto& t : types)
{
if (t.outputs > OUTPUTS_INPUTS_NUMBER_LIMIT || t.inputs > OUTPUTS_INPUTS_NUMBER_LIMIT)
if ((t.outputs > OUTPUTS_INPUTS_NUMBER_LIMIT && t.outputs != NON_RETURNING_FUNCITON) ||
t.inputs > OUTPUTS_INPUTS_NUMBER_LIMIT)
return EOFValidationError::inputs_outputs_num_above_limit;

if (t.max_stack_height > MAX_STACK_HEIGHT)
Expand All @@ -206,6 +208,8 @@ EOFValidationError validate_instructions(

const auto& cost_table = baseline::get_baseline_cost_table(rev, 1);

bool is_returning = false;

for (size_t i = 0; i < code.size(); ++i)
{
const auto op = code[i];
Expand All @@ -224,13 +228,28 @@ EOFValidationError validate_instructions(
if (i >= code.size())
return EOFValidationError::truncated_instruction;
}
else if (op == OP_CALLF || op == OP_JUMPF)
else if (op == OP_CALLF)
{
const auto fid = read_uint16_be(&code[i + 1]);
if (fid >= header.types.size())
return EOFValidationError::invalid_code_section_index;
i += 2;
}
else if (op == OP_RETF)
{
is_returning = true;
static_assert(instr::traits[OP_RETF].immediate_size == 0);
}
else if (op == OP_JUMPF)
{
const auto fid = read_uint16_be(&code[i + 1]);
if (fid >= header.types.size())
return EOFValidationError::invalid_code_section_index;
// JUMPF into returning function means current function is returning.
if (header.types[fid].outputs != NON_RETURNING_FUNCITON)
is_returning = true;
i += 2;
}
else if (op == OP_DATALOADN)
{
const auto index = read_uint16_be(&code[i + 1]);
Expand All @@ -242,6 +261,10 @@ EOFValidationError validate_instructions(
i += instr::traits[op].immediate_size;
}

const auto decared_returning = (header.types[code_idx].outputs != NON_RETURNING_FUNCITON);
if (is_returning != decared_returning)
return EOFValidationError::invalid_non_returning_flag;

return EOFValidationError::success;
}

Expand Down Expand Up @@ -346,10 +369,18 @@ std::variant<EOFValidationError, int32_t> validate_max_stack_height(
if (code_types[func_index].outputs < code_types[fid].outputs)
return EOFValidationError::jumpf_destination_incompatible_outputs;

stack_height_required = static_cast<int8_t>(
code_types[func_index].outputs + code_types[fid].inputs - code_types[fid].outputs);
if (stack_heights[i] > stack_height_required)
return EOFValidationError::non_empty_stack_on_terminating_instruction;
if (code_types[fid].outputs == NON_RETURNING_FUNCITON)
{
stack_height_required = static_cast<int8_t>(code_types[fid].inputs);
}
else
{
stack_height_required =
static_cast<int8_t>(code_types[func_index].outputs + code_types[fid].inputs -
code_types[fid].outputs);
if (stack_heights[i] > stack_height_required)
return EOFValidationError::non_empty_stack_on_terminating_instruction;
}
}

auto stack_height = stack_heights[i];
Expand Down Expand Up @@ -634,6 +665,8 @@ std::string_view get_error_message(EOFValidationError err) noexcept
return "invalid_dataloadn_index";
case EOFValidationError::jumpf_destination_incompatible_outputs:
return "jumpf_destination_incompatible_outputs";
case EOFValidationError::invalid_non_returning_flag:
return "invalid_non_returning_flag";
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 @@ -100,6 +100,7 @@ enum class EOFValidationError
invalid_code_section_index,
invalid_dataloadn_index,
jumpf_destination_incompatible_outputs,
invalid_non_returning_flag,

impossible,
};
Expand Down

0 comments on commit 4034c0f

Please sign in to comment.