From 4034c0fb5bf1452f7e9a1bee8d908d3dadfae50d Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Wed, 5 Jul 2023 15:35:01 +0200 Subject: [PATCH] Implement non-returning functions --- lib/evmone/eof.cpp | 49 ++++++++++++++++++++++++++++++++++++++-------- lib/evmone/eof.hpp | 1 + 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/lib/evmone/eof.cpp b/lib/evmone/eof.cpp index 242b3d96cb..408b1f5ef0 100644 --- a/lib/evmone/eof.cpp +++ b/lib/evmone/eof.cpp @@ -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, MAX_SECTION + 1>; @@ -182,13 +183,14 @@ std::variant, 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) @@ -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]; @@ -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]); @@ -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; } @@ -346,10 +369,18 @@ std::variant 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( - 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(code_types[fid].inputs); + } + else + { + stack_height_required = + static_cast(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]; @@ -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"; } diff --git a/lib/evmone/eof.hpp b/lib/evmone/eof.hpp index 81d86de044..f022bd7bdc 100644 --- a/lib/evmone/eof.hpp +++ b/lib/evmone/eof.hpp @@ -100,6 +100,7 @@ enum class EOFValidationError invalid_code_section_index, invalid_dataloadn_index, jumpf_destination_incompatible_outputs, + invalid_non_returning_flag, impossible, };