diff options
Diffstat (limited to 'src/binary-reader.cc')
-rw-r--r-- | src/binary-reader.cc | 1089 |
1 files changed, 582 insertions, 507 deletions
diff --git a/src/binary-reader.cc b/src/binary-reader.cc index be59691e..48e0fbed 100644 --- a/src/binary-reader.cc +++ b/src/binary-reader.cc @@ -18,7 +18,6 @@ #include <cassert> #include <cinttypes> -#include <csetjmp> #include <cstdarg> #include <cstdint> #include <cstdio> @@ -35,85 +34,30 @@ #include <alloca.h> #endif -namespace wabt { +#define CHECK_RESULT(expr) \ + do { \ + if (WABT_FAILED(expr)) \ + return Result::Error; \ + } while (0) -namespace { +#define ERROR_UNLESS(expr, ...) \ + do { \ + if (!(expr)) { \ + PrintError(__VA_ARGS__); \ + return Result::Error; \ + } \ + } while (0) #define CALLBACK0(member) \ - RAISE_ERROR_UNLESS(WABT_SUCCEEDED(ctx->reader->member()), \ - #member " callback failed") - -#define CALLBACK(member, ...) \ - RAISE_ERROR_UNLESS(WABT_SUCCEEDED(ctx->reader->member(__VA_ARGS__)), \ - #member " callback failed") - -#define RAISE_ERROR(...) raise_error(ctx, __VA_ARGS__) - -#define RAISE_ERROR_UNLESS(cond, ...) \ - if (!(cond)) \ - RAISE_ERROR(__VA_ARGS__); - -struct Context { - size_t read_end = 0; /* Either the section end or data_size. */ - BinaryReader* reader = nullptr; - BinaryReader::State state; - jmp_buf error_jmp_buf; - TypeVector param_types; - std::vector<Index> target_depths; - const ReadBinaryOptions* options = nullptr; - BinarySection last_known_section = BinarySection::Invalid; - Index num_signatures = 0; - Index num_imports = 0; - Index num_func_imports = 0; - Index num_table_imports = 0; - Index num_memory_imports = 0; - Index num_global_imports = 0; - Index num_function_signatures = 0; - Index num_tables = 0; - Index num_memories = 0; - Index num_globals = 0; - Index num_exports = 0; - Index num_function_bodies = 0; -}; - -} // namespace - -static void WABT_PRINTF_FORMAT(2, 3) - raise_error(Context* ctx, const char* format, ...) { - WABT_SNPRINTF_ALLOCA(buffer, length, format); - bool handled = ctx->reader->OnError(buffer); - - if (!handled) { - /* Not great to just print, but we don't want to eat the error either. */ - fprintf(stderr, "*ERROR*: @0x%08zx: %s\n", ctx->state.offset, buffer); - } - longjmp(ctx->error_jmp_buf, 1); -} - -#define IN_SIZE(type) \ - if (ctx->state.offset + sizeof(type) > ctx->read_end) { \ - RAISE_ERROR("unable to read " #type ": %s", desc); \ - } \ - memcpy(out_value, ctx->state.data + ctx->state.offset, sizeof(type)); \ - ctx->state.offset += sizeof(type) - -static void in_u8(Context* ctx, uint8_t* out_value, const char* desc) { - IN_SIZE(uint8_t); -} - -static void in_u32(Context* ctx, uint32_t* out_value, const char* desc) { - IN_SIZE(uint32_t); -} + ERROR_UNLESS(WABT_SUCCEEDED(delegate_->member()), #member \ + " callback " \ + "failed") -static void in_f32(Context* ctx, uint32_t* out_value, const char* desc) { - IN_SIZE(float); -} +#define CALLBACK(member, ...) \ + ERROR_UNLESS(WABT_SUCCEEDED(delegate_->member(__VA_ARGS__)), \ + #member " callback failed") -static void in_f64(Context* ctx, uint64_t* out_value, const char* desc) { - IN_SIZE(double); -} - -#undef IN_SIZE +namespace wabt { #define BYTE_AT(type, i, shift) ((static_cast<type>(p[i]) & 0x7f) << (shift)) @@ -133,6 +77,7 @@ static void in_f64(Context* ctx, uint64_t* out_value, const char* desc) { (static_cast<type>((value) << SHIFT_AMOUNT(type, sign_bit)) >> \ SHIFT_AMOUNT(type, sign_bit)) +// TODO(binji): move LEB functions elsewhere size_t read_u32_leb128(const uint8_t* p, const uint8_t* end, uint32_t* out_value) { @@ -161,15 +106,6 @@ size_t read_u32_leb128(const uint8_t* p, } } -static void in_u32_leb128(Context* ctx, uint32_t* out_value, const char* desc) { - const uint8_t* p = ctx->state.data + ctx->state.offset; - const uint8_t* end = ctx->state.data + ctx->read_end; - size_t bytes_read = read_u32_leb128(p, end, out_value); - if (!bytes_read) - RAISE_ERROR("unable to read u32 leb128: %s", desc); - ctx->state.offset += bytes_read; -} - size_t read_i32_leb128(const uint8_t* p, const uint8_t* end, uint32_t* out_value) { @@ -206,70 +142,210 @@ size_t read_i32_leb128(const uint8_t* p, } } -static void in_i32_leb128(Context* ctx, uint32_t* out_value, const char* desc) { - const uint8_t* p = ctx->state.data + ctx->state.offset; - const uint8_t* end = ctx->state.data + ctx->read_end; +namespace { + +class BinaryReader { + public: + BinaryReader(const void* data, + size_t size, + BinaryReaderDelegate* delegate, + const ReadBinaryOptions* options); + + Result ReadModule(); + + private: + void WABT_PRINTF_FORMAT(2, 3) PrintError(const char* format, ...); + Result ReadU8(uint8_t* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadU32(uint32_t* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadF32(uint32_t* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadF64(uint64_t* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadU32Leb128(uint32_t* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadI32Leb128(uint32_t* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadI64Leb128(uint64_t* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadType(Type* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadStr(StringSlice* out_str, const char* desc) WABT_WARN_UNUSED; + Result ReadBytes(const void** out_data, + Address* out_data_size, + const char* desc) WABT_WARN_UNUSED; + Result ReadIndex(Index* index, const char* desc) WABT_WARN_UNUSED; + Result ReadOffset(Offset* offset, const char* desc) WABT_WARN_UNUSED; + + Index NumTotalFuncs(); + Index NumTotalTables(); + Index NumTotalMemories(); + Index NumTotalGlobals(); + + Result ReadInitExpr(Index index) WABT_WARN_UNUSED; + Result ReadTable(Type* out_elem_type, + Limits* out_elem_limits) WABT_WARN_UNUSED; + Result ReadMemory(Limits* out_page_limits) WABT_WARN_UNUSED; + Result ReadGlobalHeader(Type* out_type, bool* out_mutable) WABT_WARN_UNUSED; + Result ReadFunctionBody(Offset end_offset) WABT_WARN_UNUSED; + Result ReadNamesSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadRelocSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadCustomSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadTypeSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadImportSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadFunctionSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadTableSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadMemorySection(Offset section_size) WABT_WARN_UNUSED; + Result ReadGlobalSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadExportSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadStartSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadElemSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadCodeSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadDataSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadSections() WABT_WARN_UNUSED; + + size_t read_end_ = 0; /* Either the section end or data_size. */ + BinaryReaderDelegate::State state_; + BinaryReaderLogging logging_delegate_; + BinaryReaderDelegate* delegate_ = nullptr; + TypeVector param_types_; + std::vector<Index> target_depths_; + const ReadBinaryOptions* options_ = nullptr; + BinarySection last_known_section_ = BinarySection::Invalid; + Index num_signatures_ = 0; + Index num_imports_ = 0; + Index num_func_imports_ = 0; + Index num_table_imports_ = 0; + Index num_memory_imports_ = 0; + Index num_global_imports_ = 0; + Index num_function_signatures_ = 0; + Index num_tables_ = 0; + Index num_memories_ = 0; + Index num_globals_ = 0; + Index num_exports_ = 0; + Index num_function_bodies_ = 0; +}; + +BinaryReader::BinaryReader(const void* data, + size_t size, + BinaryReaderDelegate* delegate, + const ReadBinaryOptions* options) + : read_end_(size), + state_(static_cast<const uint8_t*>(data), size), + logging_delegate_(options->log_stream, delegate), + delegate_(options->log_stream ? &logging_delegate_ : delegate), + options_(options), + last_known_section_(BinarySection::Invalid) { + delegate->OnSetState(&state_); +} + +void WABT_PRINTF_FORMAT(2, 3) BinaryReader::PrintError(const char* format, + ...) { + WABT_SNPRINTF_ALLOCA(buffer, length, format); + bool handled = delegate_->OnError(buffer); + + if (!handled) { + /* Not great to just print, but we don't want to eat the error either. */ + fprintf(stderr, "*ERROR*: @0x%08zx: %s\n", state_.offset, buffer); + } +} + +#define IN_SIZE(type) \ + if (state_.offset + sizeof(type) > read_end_) { \ + PrintError("unable to read " #type ": %s", desc); \ + return Result::Error; \ + } \ + memcpy(out_value, state_.data + state_.offset, sizeof(type)); \ + state_.offset += sizeof(type); \ + return Result::Ok + +Result BinaryReader::ReadU8(uint8_t* out_value, const char* desc) { + IN_SIZE(uint8_t); +} + +Result BinaryReader::ReadU32(uint32_t* out_value, const char* desc) { + IN_SIZE(uint32_t); +} + +Result BinaryReader::ReadF32(uint32_t* out_value, const char* desc) { + IN_SIZE(float); +} + +Result BinaryReader::ReadF64(uint64_t* out_value, const char* desc) { + IN_SIZE(double); +} + +#undef IN_SIZE + +Result BinaryReader::ReadU32Leb128(uint32_t* out_value, const char* desc) { + const uint8_t* p = state_.data + state_.offset; + const uint8_t* end = state_.data + read_end_; + size_t bytes_read = read_u32_leb128(p, end, out_value); + ERROR_UNLESS(bytes_read > 0, "unable to read u32 leb128: %s", desc); + state_.offset += bytes_read; + return Result::Ok; +} + +Result BinaryReader::ReadI32Leb128(uint32_t* out_value, const char* desc) { + const uint8_t* p = state_.data + state_.offset; + const uint8_t* end = state_.data + read_end_; size_t bytes_read = read_i32_leb128(p, end, out_value); - if (!bytes_read) - RAISE_ERROR("unable to read i32 leb128: %s", desc); - ctx->state.offset += bytes_read; + ERROR_UNLESS(bytes_read > 0, "unable to read i32 leb128: %s", desc); + state_.offset += bytes_read; + return Result::Ok; } -static void in_i64_leb128(Context* ctx, uint64_t* out_value, const char* desc) { - const uint8_t* p = ctx->state.data + ctx->state.offset; - const uint8_t* end = ctx->state.data + ctx->read_end; +Result BinaryReader::ReadI64Leb128(uint64_t* out_value, const char* desc) { + const uint8_t* p = state_.data + state_.offset; + const uint8_t* end = state_.data + read_end_; if (p < end && (p[0] & 0x80) == 0) { uint64_t result = LEB128_1(uint64_t); *out_value = SIGN_EXTEND(int64_t, result, 6); - ctx->state.offset += 1; + state_.offset += 1; } else if (p + 1 < end && (p[1] & 0x80) == 0) { uint64_t result = LEB128_2(uint64_t); *out_value = SIGN_EXTEND(int64_t, result, 13); - ctx->state.offset += 2; + state_.offset += 2; } else if (p + 2 < end && (p[2] & 0x80) == 0) { uint64_t result = LEB128_3(uint64_t); *out_value = SIGN_EXTEND(int64_t, result, 20); - ctx->state.offset += 3; + state_.offset += 3; } else if (p + 3 < end && (p[3] & 0x80) == 0) { uint64_t result = LEB128_4(uint64_t); *out_value = SIGN_EXTEND(int64_t, result, 27); - ctx->state.offset += 4; + state_.offset += 4; } else if (p + 4 < end && (p[4] & 0x80) == 0) { uint64_t result = LEB128_5(uint64_t); *out_value = SIGN_EXTEND(int64_t, result, 34); - ctx->state.offset += 5; + state_.offset += 5; } else if (p + 5 < end && (p[5] & 0x80) == 0) { uint64_t result = LEB128_6(uint64_t); *out_value = SIGN_EXTEND(int64_t, result, 41); - ctx->state.offset += 6; + state_.offset += 6; } else if (p + 6 < end && (p[6] & 0x80) == 0) { uint64_t result = LEB128_7(uint64_t); *out_value = SIGN_EXTEND(int64_t, result, 48); - ctx->state.offset += 7; + state_.offset += 7; } else if (p + 7 < end && (p[7] & 0x80) == 0) { uint64_t result = LEB128_8(uint64_t); *out_value = SIGN_EXTEND(int64_t, result, 55); - ctx->state.offset += 8; + state_.offset += 8; } else if (p + 8 < end && (p[8] & 0x80) == 0) { uint64_t result = LEB128_9(uint64_t); *out_value = SIGN_EXTEND(int64_t, result, 62); - ctx->state.offset += 9; + state_.offset += 9; } else if (p + 9 < end && (p[9] & 0x80) == 0) { /* the top bits should be a sign-extension of the sign bit */ bool sign_bit_set = (p[9] & 0x1); int top_bits = p[9] & 0xfe; if ((sign_bit_set && top_bits != 0x7e) || (!sign_bit_set && top_bits != 0)) { - RAISE_ERROR("invalid i64 leb128: %s", desc); + PrintError("invalid i64 leb128: %s", desc); + return Result::Error; } uint64_t result = LEB128_10(uint64_t); *out_value = result; - ctx->state.offset += 10; + state_.offset += 10; } else { /* past the end */ - RAISE_ERROR("unable to read i64 leb128: %s", desc); + PrintError("unable to read i64 leb128: %s", desc); + return Result::Error; } + return Result::Ok; } #undef BYTE_AT @@ -286,57 +362,60 @@ static void in_i64_leb128(Context* ctx, uint64_t* out_value, const char* desc) { #undef SHIFT_AMOUNT #undef SIGN_EXTEND -static void in_type(Context* ctx, Type* out_value, const char* desc) { +Result BinaryReader::ReadType(Type* out_value, const char* desc) { uint32_t type = 0; - in_i32_leb128(ctx, &type, desc); + CHECK_RESULT(ReadI32Leb128(&type, desc)); /* Must be in the vs7 range: [-128, 127). */ - if (static_cast<int32_t>(type) < -128 || static_cast<int32_t>(type) > 127) - RAISE_ERROR("invalid type: %d", type); + ERROR_UNLESS( + static_cast<int32_t>(type) >= -128 && static_cast<int32_t>(type) <= 127, + "invalid type: %d", type); *out_value = static_cast<Type>(type); + return Result::Ok; } -static void in_str(Context* ctx, StringSlice* out_str, const char* desc) { +Result BinaryReader::ReadStr(StringSlice* out_str, const char* desc) { uint32_t str_len = 0; - in_u32_leb128(ctx, &str_len, "string length"); + CHECK_RESULT(ReadU32Leb128(&str_len, "string length")); - if (ctx->state.offset + str_len > ctx->read_end) - RAISE_ERROR("unable to read string: %s", desc); + ERROR_UNLESS(state_.offset + str_len <= read_end_, + "unable to read string: %s", desc); - out_str->start = - reinterpret_cast<const char*>(ctx->state.data) + ctx->state.offset; + out_str->start = reinterpret_cast<const char*>(state_.data) + state_.offset; out_str->length = str_len; - ctx->state.offset += str_len; + state_.offset += str_len; - RAISE_ERROR_UNLESS(is_valid_utf8(out_str->start, out_str->length), - "invalid utf-8 encoding: %s", desc); + ERROR_UNLESS(is_valid_utf8(out_str->start, out_str->length), + "invalid utf-8 encoding: %s", desc); + return Result::Ok; } -static void in_bytes(Context* ctx, - const void** out_data, - Address* out_data_size, - const char* desc) { +Result BinaryReader::ReadBytes(const void** out_data, + Address* out_data_size, + const char* desc) { uint32_t data_size = 0; - in_u32_leb128(ctx, &data_size, "data size"); + CHECK_RESULT(ReadU32Leb128(&data_size, "data size")); - if (ctx->state.offset + data_size > ctx->read_end) - RAISE_ERROR("unable to read data: %s", desc); + ERROR_UNLESS(state_.offset + data_size <= read_end_, + "unable to read data: %s", desc); - *out_data = - static_cast<const uint8_t*>(ctx->state.data) + ctx->state.offset; + *out_data = static_cast<const uint8_t*>(state_.data) + state_.offset; *out_data_size = data_size; - ctx->state.offset += data_size; + state_.offset += data_size; + return Result::Ok; } -static void in_index(Context* ctx, Index* index, const char* desc) { +Result BinaryReader::ReadIndex(Index* index, const char* desc) { uint32_t value; - in_u32_leb128(ctx, &value, desc); + CHECK_RESULT(ReadU32Leb128(&value, desc)); *index = value; + return Result::Ok; } -static void in_file_offset(Context* ctx, Offset* offset, const char* desc) { +Result BinaryReader::ReadOffset(Offset* offset, const char* desc) { uint32_t value; - in_u32_leb128(ctx, &value, desc); + CHECK_RESULT(ReadU32Leb128(&value, desc)); *offset = value; + return Result::Ok; } static bool is_valid_external_kind(uint8_t kind) { @@ -360,140 +439,139 @@ static bool is_inline_sig_type(Type type) { return is_concrete_type(type) || type == Type::Void; } -static Index num_total_funcs(Context* ctx) { - return ctx->num_func_imports + ctx->num_function_signatures; +Index BinaryReader::NumTotalFuncs() { + return num_func_imports_ + num_function_signatures_; } -static Index num_total_tables(Context* ctx) { - return ctx->num_table_imports + ctx->num_tables; +Index BinaryReader::NumTotalTables() { + return num_table_imports_ + num_tables_; } -static Index num_total_memories(Context* ctx) { - return ctx->num_memory_imports + ctx->num_memories; +Index BinaryReader::NumTotalMemories() { + return num_memory_imports_ + num_memories_; } -static Index num_total_globals(Context* ctx) { - return ctx->num_global_imports + ctx->num_globals; +Index BinaryReader::NumTotalGlobals() { + return num_global_imports_ + num_globals_; } -static void read_init_expr(Context* ctx, Index index) { - uint8_t opcode; - in_u8(ctx, &opcode, "opcode"); +Result BinaryReader::ReadInitExpr(Index index) { + uint8_t opcode = 0; + CHECK_RESULT(ReadU8(&opcode, "opcode")); switch (static_cast<Opcode>(opcode)) { case Opcode::I32Const: { uint32_t value = 0; - in_i32_leb128(ctx, &value, "init_expr i32.const value"); + CHECK_RESULT(ReadI32Leb128(&value, "init_expr i32.const value")); CALLBACK(OnInitExprI32ConstExpr, index, value); break; } case Opcode::I64Const: { uint64_t value = 0; - in_i64_leb128(ctx, &value, "init_expr i64.const value"); + CHECK_RESULT(ReadI64Leb128(&value, "init_expr i64.const value")); CALLBACK(OnInitExprI64ConstExpr, index, value); break; } case Opcode::F32Const: { uint32_t value_bits = 0; - in_f32(ctx, &value_bits, "init_expr f32.const value"); + CHECK_RESULT(ReadF32(&value_bits, "init_expr f32.const value")); CALLBACK(OnInitExprF32ConstExpr, index, value_bits); break; } case Opcode::F64Const: { uint64_t value_bits = 0; - in_f64(ctx, &value_bits, "init_expr f64.const value"); + CHECK_RESULT(ReadF64(&value_bits, "init_expr f64.const value")); CALLBACK(OnInitExprF64ConstExpr, index, value_bits); break; } case Opcode::GetGlobal: { Index global_index; - in_index(ctx, &global_index, "init_expr get_global index"); + CHECK_RESULT(ReadIndex(&global_index, "init_expr get_global index")); CALLBACK(OnInitExprGetGlobalExpr, index, global_index); break; } case Opcode::End: - return; + return Result::Ok; default: - RAISE_ERROR("unexpected opcode in initializer expression: %d (0x%x)", - opcode, opcode); - break; + PrintError("unexpected opcode in initializer expression: %d (0x%x)", + opcode, opcode); + return Result::Error; } - in_u8(ctx, &opcode, "opcode"); - RAISE_ERROR_UNLESS(static_cast<Opcode>(opcode) == Opcode::End, - "expected END opcode after initializer expression"); + CHECK_RESULT(ReadU8(&opcode, "opcode")); + ERROR_UNLESS(static_cast<Opcode>(opcode) == Opcode::End, + "expected END opcode after initializer expression"); + return Result::Ok; } -static void read_table(Context* ctx, - Type* out_elem_type, - Limits* out_elem_limits) { - in_type(ctx, out_elem_type, "table elem type"); - RAISE_ERROR_UNLESS(*out_elem_type == Type::Anyfunc, - "table elem type must by anyfunc"); +Result BinaryReader::ReadTable(Type* out_elem_type, Limits* out_elem_limits) { + CHECK_RESULT(ReadType(out_elem_type, "table elem type")); + ERROR_UNLESS(*out_elem_type == Type::Anyfunc, + "table elem type must by anyfunc"); uint32_t flags; uint32_t initial; uint32_t max = 0; - in_u32_leb128(ctx, &flags, "table flags"); - in_u32_leb128(ctx, &initial, "table initial elem count"); + CHECK_RESULT(ReadU32Leb128(&flags, "table flags")); + CHECK_RESULT(ReadU32Leb128(&initial, "table initial elem count")); bool has_max = flags & WABT_BINARY_LIMITS_HAS_MAX_FLAG; if (has_max) { - in_u32_leb128(ctx, &max, "table max elem count"); - RAISE_ERROR_UNLESS(initial <= max, - "table initial elem count must be <= max elem count"); + CHECK_RESULT(ReadU32Leb128(&max, "table max elem count")); + ERROR_UNLESS(initial <= max, + "table initial elem count must be <= max elem count"); } out_elem_limits->has_max = has_max; out_elem_limits->initial = initial; out_elem_limits->max = max; + return Result::Ok; } -static void read_memory(Context* ctx, Limits* out_page_limits) { +Result BinaryReader::ReadMemory(Limits* out_page_limits) { uint32_t flags; uint32_t initial; uint32_t max = 0; - in_u32_leb128(ctx, &flags, "memory flags"); - in_u32_leb128(ctx, &initial, "memory initial page count"); + CHECK_RESULT(ReadU32Leb128(&flags, "memory flags")); + CHECK_RESULT(ReadU32Leb128(&initial, "memory initial page count")); bool has_max = flags & WABT_BINARY_LIMITS_HAS_MAX_FLAG; - RAISE_ERROR_UNLESS(initial <= WABT_MAX_PAGES, "invalid memory initial size"); + ERROR_UNLESS(initial <= WABT_MAX_PAGES, "invalid memory initial size"); if (has_max) { - in_u32_leb128(ctx, &max, "memory max page count"); - RAISE_ERROR_UNLESS(max <= WABT_MAX_PAGES, "invalid memory max size"); - RAISE_ERROR_UNLESS(initial <= max, - "memory initial size must be <= max size"); + CHECK_RESULT(ReadU32Leb128(&max, "memory max page count")); + ERROR_UNLESS(max <= WABT_MAX_PAGES, "invalid memory max size"); + ERROR_UNLESS(initial <= max, "memory initial size must be <= max size"); } out_page_limits->has_max = has_max; out_page_limits->initial = initial; out_page_limits->max = max; + return Result::Ok; } -static void read_global_header(Context* ctx, - Type* out_type, - bool* out_mutable) { - Type global_type; - uint8_t mutable_; - in_type(ctx, &global_type, "global type"); - RAISE_ERROR_UNLESS(is_concrete_type(global_type), - "invalid global type: %#x", static_cast<int>(global_type)); +Result BinaryReader::ReadGlobalHeader(Type* out_type, bool* out_mutable) { + Type global_type = Type::Void; + uint8_t mutable_ = 0; + CHECK_RESULT(ReadType(&global_type, "global type")); + ERROR_UNLESS(is_concrete_type(global_type), "invalid global type: %#x", + static_cast<int>(global_type)); - in_u8(ctx, &mutable_, "global mutability"); - RAISE_ERROR_UNLESS(mutable_ <= 1, "global mutability must be 0 or 1"); + CHECK_RESULT(ReadU8(&mutable_, "global mutability")); + ERROR_UNLESS(mutable_ <= 1, "global mutability must be 0 or 1"); *out_type = global_type; *out_mutable = mutable_; + return Result::Ok; } -static void read_function_body(Context* ctx, Offset end_offset) { +Result BinaryReader::ReadFunctionBody(Offset end_offset) { bool seen_end_opcode = false; - while (ctx->state.offset < end_offset) { - uint8_t opcode_u8; - in_u8(ctx, &opcode_u8, "opcode"); + while (state_.offset < end_offset) { + uint8_t opcode_u8 = 0; + CHECK_RESULT(ReadU8(&opcode_u8, "opcode")); Opcode opcode = static_cast<Opcode>(opcode_u8); CALLBACK(OnOpcode, opcode); switch (opcode) { @@ -504,9 +582,9 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::Block: { Type sig_type; - in_type(ctx, &sig_type, "block signature type"); - RAISE_ERROR_UNLESS(is_inline_sig_type(sig_type), - "expected valid block signature type"); + CHECK_RESULT(ReadType(&sig_type, "block signature type")); + ERROR_UNLESS(is_inline_sig_type(sig_type), + "expected valid block signature type"); Index num_types = sig_type == Type::Void ? 0 : 1; CALLBACK(OnBlockExpr, num_types, &sig_type); CALLBACK(OnOpcodeBlockSig, num_types, &sig_type); @@ -515,9 +593,9 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::Loop: { Type sig_type; - in_type(ctx, &sig_type, "loop signature type"); - RAISE_ERROR_UNLESS(is_inline_sig_type(sig_type), - "expected valid block signature type"); + CHECK_RESULT(ReadType(&sig_type, "loop signature type")); + ERROR_UNLESS(is_inline_sig_type(sig_type), + "expected valid block signature type"); Index num_types = sig_type == Type::Void ? 0 : 1; CALLBACK(OnLoopExpr, num_types, &sig_type); CALLBACK(OnOpcodeBlockSig, num_types, &sig_type); @@ -526,9 +604,9 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::If: { Type sig_type; - in_type(ctx, &sig_type, "if signature type"); - RAISE_ERROR_UNLESS(is_inline_sig_type(sig_type), - "expected valid block signature type"); + CHECK_RESULT(ReadType(&sig_type, "if signature type")); + ERROR_UNLESS(is_inline_sig_type(sig_type), + "expected valid block signature type"); Index num_types = sig_type == Type::Void ? 0 : 1; CALLBACK(OnIfExpr, num_types, &sig_type); CALLBACK(OnOpcodeBlockSig, num_types, &sig_type); @@ -547,7 +625,7 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::Br: { Index depth; - in_index(ctx, &depth, "br depth"); + CHECK_RESULT(ReadIndex(&depth, "br depth")); CALLBACK(OnBrExpr, depth); CALLBACK(OnOpcodeIndex, depth); break; @@ -555,7 +633,7 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::BrIf: { Index depth; - in_index(ctx, &depth, "br_if depth"); + CHECK_RESULT(ReadIndex(&depth, "br_if depth")); CALLBACK(OnBrIfExpr, depth); CALLBACK(OnOpcodeIndex, depth); break; @@ -563,20 +641,20 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::BrTable: { Index num_targets; - in_index(ctx, &num_targets, "br_table target count"); - ctx->target_depths.resize(num_targets); + CHECK_RESULT(ReadIndex(&num_targets, "br_table target count")); + target_depths_.resize(num_targets); for (Index i = 0; i < num_targets; ++i) { Index target_depth; - in_index(ctx, &target_depth, "br_table target depth"); - ctx->target_depths[i] = target_depth; + CHECK_RESULT(ReadIndex(&target_depth, "br_table target depth")); + target_depths_[i] = target_depth; } Index default_target_depth; - in_index(ctx, &default_target_depth, "br_table default target depth"); + CHECK_RESULT( + ReadIndex(&default_target_depth, "br_table default target depth")); - Index* target_depths = - num_targets ? ctx->target_depths.data() : nullptr; + Index* target_depths = num_targets ? target_depths_.data() : nullptr; CALLBACK(OnBrTableExpr, num_targets, target_depths, default_target_depth); @@ -599,7 +677,7 @@ static void read_function_body(Context* ctx, Offset end_offset) { break; case Opcode::End: - if (ctx->state.offset == end_offset) { + if (state_.offset == end_offset) { seen_end_opcode = true; CALLBACK0(OnEndFunc); } else { @@ -609,7 +687,7 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::I32Const: { uint32_t value; - in_i32_leb128(ctx, &value, "i32.const value"); + CHECK_RESULT(ReadI32Leb128(&value, "i32.const value")); CALLBACK(OnI32ConstExpr, value); CALLBACK(OnOpcodeUint32, value); break; @@ -617,7 +695,7 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::I64Const: { uint64_t value; - in_i64_leb128(ctx, &value, "i64.const value"); + CHECK_RESULT(ReadI64Leb128(&value, "i64.const value")); CALLBACK(OnI64ConstExpr, value); CALLBACK(OnOpcodeUint64, value); break; @@ -625,7 +703,7 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::F32Const: { uint32_t value_bits = 0; - in_f32(ctx, &value_bits, "f32.const value"); + CHECK_RESULT(ReadF32(&value_bits, "f32.const value")); CALLBACK(OnF32ConstExpr, value_bits); CALLBACK(OnOpcodeF32, value_bits); break; @@ -633,7 +711,7 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::F64Const: { uint64_t value_bits = 0; - in_f64(ctx, &value_bits, "f64.const value"); + CHECK_RESULT(ReadF64(&value_bits, "f64.const value")); CALLBACK(OnF64ConstExpr, value_bits); CALLBACK(OnOpcodeF64, value_bits); break; @@ -641,7 +719,7 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::GetGlobal: { Index global_index; - in_index(ctx, &global_index, "get_global global index"); + CHECK_RESULT(ReadIndex(&global_index, "get_global global index")); CALLBACK(OnGetGlobalExpr, global_index); CALLBACK(OnOpcodeIndex, global_index); break; @@ -649,7 +727,7 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::GetLocal: { Index local_index; - in_index(ctx, &local_index, "get_local local index"); + CHECK_RESULT(ReadIndex(&local_index, "get_local local index")); CALLBACK(OnGetLocalExpr, local_index); CALLBACK(OnOpcodeIndex, local_index); break; @@ -657,7 +735,7 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::SetGlobal: { Index global_index; - in_index(ctx, &global_index, "set_global global index"); + CHECK_RESULT(ReadIndex(&global_index, "set_global global index")); CALLBACK(OnSetGlobalExpr, global_index); CALLBACK(OnOpcodeIndex, global_index); break; @@ -665,7 +743,7 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::SetLocal: { Index local_index; - in_index(ctx, &local_index, "set_local local index"); + CHECK_RESULT(ReadIndex(&local_index, "set_local local index")); CALLBACK(OnSetLocalExpr, local_index); CALLBACK(OnOpcodeIndex, local_index); break; @@ -673,10 +751,9 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::Call: { Index func_index; - in_index(ctx, &func_index, "call function index"); - RAISE_ERROR_UNLESS(func_index < num_total_funcs(ctx), - "invalid call function index: %" PRIindex, - func_index); + CHECK_RESULT(ReadIndex(&func_index, "call function index")); + ERROR_UNLESS(func_index < NumTotalFuncs(), + "invalid call function index: %" PRIindex, func_index); CALLBACK(OnCallExpr, func_index); CALLBACK(OnOpcodeIndex, func_index); break; @@ -684,13 +761,12 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::CallIndirect: { Index sig_index; - in_index(ctx, &sig_index, "call_indirect signature index"); - RAISE_ERROR_UNLESS(sig_index < ctx->num_signatures, - "invalid call_indirect signature index"); + CHECK_RESULT(ReadIndex(&sig_index, "call_indirect signature index")); + ERROR_UNLESS(sig_index < num_signatures_, + "invalid call_indirect signature index"); uint32_t reserved; - in_u32_leb128(ctx, &reserved, "call_indirect reserved"); - RAISE_ERROR_UNLESS(reserved == 0, - "call_indirect reserved value must be 0"); + CHECK_RESULT(ReadU32Leb128(&reserved, "call_indirect reserved")); + ERROR_UNLESS(reserved == 0, "call_indirect reserved value must be 0"); CALLBACK(OnCallIndirectExpr, sig_index); CALLBACK(OnOpcodeUint32Uint32, sig_index, reserved); break; @@ -698,7 +774,7 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::TeeLocal: { Index local_index; - in_index(ctx, &local_index, "tee_local local index"); + CHECK_RESULT(ReadIndex(&local_index, "tee_local local index")); CALLBACK(OnTeeLocalExpr, local_index); CALLBACK(OnOpcodeIndex, local_index); break; @@ -719,9 +795,9 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::F32Load: case Opcode::F64Load: { uint32_t alignment_log2; - in_u32_leb128(ctx, &alignment_log2, "load alignment"); + CHECK_RESULT(ReadU32Leb128(&alignment_log2, "load alignment")); Address offset; - in_u32_leb128(ctx, &offset, "load offset"); + CHECK_RESULT(ReadU32Leb128(&offset, "load offset")); CALLBACK(OnLoadExpr, opcode, alignment_log2, offset); CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset); @@ -738,9 +814,9 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::F32Store: case Opcode::F64Store: { uint32_t alignment_log2; - in_u32_leb128(ctx, &alignment_log2, "store alignment"); + CHECK_RESULT(ReadU32Leb128(&alignment_log2, "store alignment")); Address offset; - in_u32_leb128(ctx, &offset, "store offset"); + CHECK_RESULT(ReadU32Leb128(&offset, "store offset")); CALLBACK(OnStoreExpr, opcode, alignment_log2, offset); CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset); @@ -749,9 +825,8 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::CurrentMemory: { uint32_t reserved; - in_u32_leb128(ctx, &reserved, "current_memory reserved"); - RAISE_ERROR_UNLESS(reserved == 0, - "current_memory reserved value must be 0"); + CHECK_RESULT(ReadU32Leb128(&reserved, "current_memory reserved")); + ERROR_UNLESS(reserved == 0, "current_memory reserved value must be 0"); CALLBACK0(OnCurrentMemoryExpr); CALLBACK(OnOpcodeUint32, reserved); break; @@ -759,9 +834,8 @@ static void read_function_body(Context* ctx, Offset end_offset) { case Opcode::GrowMemory: { uint32_t reserved; - in_u32_leb128(ctx, &reserved, "grow_memory reserved"); - RAISE_ERROR_UNLESS(reserved == 0, - "grow_memory reserved value must be 0"); + CHECK_RESULT(ReadU32Leb128(&reserved, "grow_memory reserved")); + ERROR_UNLESS(reserved == 0, "grow_memory reserved value must be 0"); CALLBACK0(OnGrowMemoryExpr); CALLBACK(OnOpcodeUint32, reserved); break; @@ -907,122 +981,123 @@ static void read_function_body(Context* ctx, Offset end_offset) { break; default: - RAISE_ERROR("unexpected opcode: %d (0x%x)", static_cast<int>(opcode), - static_cast<unsigned>(opcode)); + PrintError("unexpected opcode: %d (0x%x)", static_cast<int>(opcode), + static_cast<unsigned>(opcode)); + return Result::Error; } } - RAISE_ERROR_UNLESS(ctx->state.offset == end_offset, - "function body longer than given size"); - RAISE_ERROR_UNLESS(seen_end_opcode, "function body must end with END opcode"); + ERROR_UNLESS(state_.offset == end_offset, + "function body longer than given size"); + ERROR_UNLESS(seen_end_opcode, "function body must end with END opcode"); + return Result::Ok; } -static void read_names_section(Context* ctx, Offset section_size) { +Result BinaryReader::ReadNamesSection(Offset section_size) { CALLBACK(BeginNamesSection, section_size); Index i = 0; - Offset previous_read_end = ctx->read_end; + Offset previous_read_end = read_end_; uint32_t previous_subsection_type = 0; - while (ctx->state.offset < ctx->read_end) { + while (state_.offset < read_end_) { uint32_t name_type; Offset subsection_size; - in_u32_leb128(ctx, &name_type, "name type"); + CHECK_RESULT(ReadU32Leb128(&name_type, "name type")); if (i != 0) { - if (name_type == previous_subsection_type) - RAISE_ERROR("duplicate sub-section"); - if (name_type < previous_subsection_type) - RAISE_ERROR("out-of-order sub-section"); + ERROR_UNLESS(name_type != previous_subsection_type, + "duplicate sub-section"); + ERROR_UNLESS(name_type >= previous_subsection_type, + "out-of-order sub-section"); } previous_subsection_type = name_type; - in_file_offset(ctx, &subsection_size, "subsection size"); - size_t subsection_end = ctx->state.offset + subsection_size; - if (subsection_end > ctx->read_end) - RAISE_ERROR("invalid sub-section size: extends past end"); - ctx->read_end = subsection_end; + CHECK_RESULT(ReadOffset(&subsection_size, "subsection size")); + size_t subsection_end = state_.offset + subsection_size; + ERROR_UNLESS(subsection_end <= read_end_, + "invalid sub-section size: extends past end"); + read_end_ = subsection_end; switch (static_cast<NameSectionSubsection>(name_type)) { - case NameSectionSubsection::Function: - CALLBACK(OnFunctionNameSubsection, i, name_type, subsection_size); - if (subsection_size) { - Index num_names; - in_index(ctx, &num_names, "name count"); - CALLBACK(OnFunctionNamesCount, num_names); - for (Index j = 0; j < num_names; ++j) { - Index function_index; - StringSlice function_name; - - in_index(ctx, &function_index, "function index"); - RAISE_ERROR_UNLESS(function_index < num_total_funcs(ctx), - "invalid function index: %" PRIindex, - function_index); - in_str(ctx, &function_name, "function name"); - CALLBACK(OnFunctionName, function_index, function_name); + case NameSectionSubsection::Function: + CALLBACK(OnFunctionNameSubsection, i, name_type, subsection_size); + if (subsection_size) { + Index num_names; + CHECK_RESULT(ReadIndex(&num_names, "name count")); + CALLBACK(OnFunctionNamesCount, num_names); + for (Index j = 0; j < num_names; ++j) { + Index function_index; + StringSlice function_name; + + CHECK_RESULT(ReadIndex(&function_index, "function index")); + ERROR_UNLESS(function_index < NumTotalFuncs(), + "invalid function index: %" PRIindex, function_index); + CHECK_RESULT(ReadStr(&function_name, "function name")); + CALLBACK(OnFunctionName, function_index, function_name); + } } - } - break; - case NameSectionSubsection::Local: - CALLBACK(OnLocalNameSubsection, i, name_type, subsection_size); - if (subsection_size) { - Index num_funcs; - in_index(ctx, &num_funcs, "function count"); - CALLBACK(OnLocalNameFunctionCount, num_funcs); - for (Index j = 0; j < num_funcs; ++j) { - Index function_index; - in_index(ctx, &function_index, "function index"); - RAISE_ERROR_UNLESS(function_index < num_total_funcs(ctx), - "invalid function index: %u", function_index); - Index num_locals; - in_index(ctx, &num_locals, "local count"); - CALLBACK(OnLocalNameLocalCount, function_index, num_locals); - for (Index k = 0; k < num_locals; ++k) { - Index local_index; - StringSlice local_name; - - in_index(ctx, &local_index, "named index"); - in_str(ctx, &local_name, "name"); - CALLBACK(OnLocalName, function_index, local_index, local_name); + break; + case NameSectionSubsection::Local: + CALLBACK(OnLocalNameSubsection, i, name_type, subsection_size); + if (subsection_size) { + Index num_funcs; + CHECK_RESULT(ReadIndex(&num_funcs, "function count")); + CALLBACK(OnLocalNameFunctionCount, num_funcs); + for (Index j = 0; j < num_funcs; ++j) { + Index function_index; + CHECK_RESULT(ReadIndex(&function_index, "function index")); + ERROR_UNLESS(function_index < NumTotalFuncs(), + "invalid function index: %u", function_index); + Index num_locals; + CHECK_RESULT(ReadIndex(&num_locals, "local count")); + CALLBACK(OnLocalNameLocalCount, function_index, num_locals); + for (Index k = 0; k < num_locals; ++k) { + Index local_index; + StringSlice local_name; + + CHECK_RESULT(ReadIndex(&local_index, "named index")); + CHECK_RESULT(ReadStr(&local_name, "name")); + CALLBACK(OnLocalName, function_index, local_index, local_name); + } } } - } - break; - default: - /* unknown subsection, skip it */ - ctx->state.offset = subsection_end; - break; + break; + default: + /* unknown subsection, skip it */ + state_.offset = subsection_end; + break; } ++i; - if (ctx->state.offset != subsection_end) { - RAISE_ERROR("unfinished sub-section (expected end: 0x%" PRIzx ")", - subsection_end); - } - ctx->read_end = previous_read_end; + ERROR_UNLESS(state_.offset == subsection_end, + "unfinished sub-section (expected end: 0x%" PRIzx ")", + subsection_end); + read_end_ = previous_read_end; } CALLBACK0(EndNamesSection); + return Result::Ok; } -static void read_reloc_section(Context* ctx, Offset section_size) { +Result BinaryReader::ReadRelocSection(Offset section_size) { CALLBACK(BeginRelocSection, section_size); uint32_t section; - in_u32_leb128(ctx, §ion, "section"); + CHECK_RESULT(ReadU32Leb128(§ion, "section")); StringSlice section_name; WABT_ZERO_MEMORY(section_name); if (static_cast<BinarySection>(section) == BinarySection::Custom) - in_str(ctx, §ion_name, "section name"); + CHECK_RESULT(ReadStr(§ion_name, "section name")); Index num_relocs; - in_index(ctx, &num_relocs, "relocation count"); + CHECK_RESULT(ReadIndex(&num_relocs, "relocation count")); CALLBACK(OnRelocCount, num_relocs, static_cast<BinarySection>(section), section_name); for (Index i = 0; i < num_relocs; ++i) { Offset offset; Index index; uint32_t reloc_type, addend = 0; - in_u32_leb128(ctx, &reloc_type, "relocation type"); - in_file_offset(ctx, &offset, "offset"); - in_index(ctx, &index, "index"); + CHECK_RESULT(ReadU32Leb128(&reloc_type, "relocation type")); + CHECK_RESULT(ReadOffset(&offset, "offset")); + CHECK_RESULT(ReadIndex(&index, "index")); RelocType type = static_cast<RelocType>(reloc_type); switch (type) { case RelocType::GlobalAddressLEB: case RelocType::GlobalAddressSLEB: case RelocType::GlobalAddressI32: - in_i32_leb128(ctx, &addend, "addend"); + CHECK_RESULT(ReadI32Leb128(&addend, "addend")); break; default: break; @@ -1030,235 +1105,240 @@ static void read_reloc_section(Context* ctx, Offset section_size) { CALLBACK(OnReloc, type, offset, index, addend); } CALLBACK0(EndRelocSection); + return Result::Ok; } -static void read_custom_section(Context* ctx, Offset section_size) { +Result BinaryReader::ReadCustomSection(Offset section_size) { StringSlice section_name; - in_str(ctx, §ion_name, "section name"); + CHECK_RESULT(ReadStr(§ion_name, "section name")); CALLBACK(BeginCustomSection, section_size, section_name); - bool name_section_ok = ctx->last_known_section >= BinarySection::Import; - if (ctx->options->read_debug_names && name_section_ok && + bool name_section_ok = last_known_section_ >= BinarySection::Import; + if (options_->read_debug_names && name_section_ok && strncmp(section_name.start, WABT_BINARY_SECTION_NAME, section_name.length) == 0) { - read_names_section(ctx, section_size); + CHECK_RESULT(ReadNamesSection(section_size)); } else if (strncmp(section_name.start, WABT_BINARY_SECTION_RELOC, strlen(WABT_BINARY_SECTION_RELOC)) == 0) { - read_reloc_section(ctx, section_size); + CHECK_RESULT(ReadRelocSection(section_size)); } else { /* This is an unknown custom section, skip it. */ - ctx->state.offset = ctx->read_end; + state_.offset = read_end_; } CALLBACK0(EndCustomSection); + return Result::Ok; } -static void read_type_section(Context* ctx, Offset section_size) { +Result BinaryReader::ReadTypeSection(Offset section_size) { CALLBACK(BeginTypeSection, section_size); - in_index(ctx, &ctx->num_signatures, "type count"); - CALLBACK(OnTypeCount, ctx->num_signatures); + CHECK_RESULT(ReadIndex(&num_signatures_, "type count")); + CALLBACK(OnTypeCount, num_signatures_); - for (Index i = 0; i < ctx->num_signatures; ++i) { + for (Index i = 0; i < num_signatures_; ++i) { Type form; - in_type(ctx, &form, "type form"); - RAISE_ERROR_UNLESS(form == Type::Func, "unexpected type form: %d", - static_cast<int>(form)); + CHECK_RESULT(ReadType(&form, "type form")); + ERROR_UNLESS(form == Type::Func, "unexpected type form: %d", + static_cast<int>(form)); Index num_params; - in_index(ctx, &num_params, "function param count"); + CHECK_RESULT(ReadIndex(&num_params, "function param count")); - ctx->param_types.resize(num_params); + param_types_.resize(num_params); for (Index j = 0; j < num_params; ++j) { Type param_type; - in_type(ctx, ¶m_type, "function param type"); - RAISE_ERROR_UNLESS(is_concrete_type(param_type), - "expected valid param type (got %d)", - static_cast<int>(param_type)); - ctx->param_types[j] = param_type; + CHECK_RESULT(ReadType(¶m_type, "function param type")); + ERROR_UNLESS(is_concrete_type(param_type), + "expected valid param type (got %d)", + static_cast<int>(param_type)); + param_types_[j] = param_type; } Index num_results; - in_index(ctx, &num_results, "function result count"); - RAISE_ERROR_UNLESS(num_results <= 1, "result count must be 0 or 1"); + CHECK_RESULT(ReadIndex(&num_results, "function result count")); + ERROR_UNLESS(num_results <= 1, "result count must be 0 or 1"); Type result_type = Type::Void; if (num_results) { - in_type(ctx, &result_type, "function result type"); - RAISE_ERROR_UNLESS(is_concrete_type(result_type), - "expected valid result type: %d", - static_cast<int>(result_type)); + CHECK_RESULT(ReadType(&result_type, "function result type")); + ERROR_UNLESS(is_concrete_type(result_type), + "expected valid result type: %d", + static_cast<int>(result_type)); } - Type* param_types = num_params ? ctx->param_types.data() : nullptr; + Type* param_types = num_params ? param_types_.data() : nullptr; CALLBACK(OnType, i, num_params, param_types, num_results, &result_type); } CALLBACK0(EndTypeSection); + return Result::Ok; } -static void read_import_section(Context* ctx, Offset section_size) { +Result BinaryReader::ReadImportSection(Offset section_size) { CALLBACK(BeginImportSection, section_size); - in_index(ctx, &ctx->num_imports, "import count"); - CALLBACK(OnImportCount, ctx->num_imports); - for (Index i = 0; i < ctx->num_imports; ++i) { + CHECK_RESULT(ReadIndex(&num_imports_, "import count")); + CALLBACK(OnImportCount, num_imports_); + for (Index i = 0; i < num_imports_; ++i) { StringSlice module_name; - in_str(ctx, &module_name, "import module name"); + CHECK_RESULT(ReadStr(&module_name, "import module name")); StringSlice field_name; - in_str(ctx, &field_name, "import field name"); + CHECK_RESULT(ReadStr(&field_name, "import field name")); uint32_t kind; - in_u32_leb128(ctx, &kind, "import kind"); + CHECK_RESULT(ReadU32Leb128(&kind, "import kind")); switch (static_cast<ExternalKind>(kind)) { case ExternalKind::Func: { Index sig_index; - in_index(ctx, &sig_index, "import signature index"); - RAISE_ERROR_UNLESS(sig_index < ctx->num_signatures, - "invalid import signature index"); + CHECK_RESULT(ReadIndex(&sig_index, "import signature index")); + ERROR_UNLESS(sig_index < num_signatures_, + "invalid import signature index"); CALLBACK(OnImport, i, module_name, field_name); - CALLBACK(OnImportFunc, i, module_name, field_name, - ctx->num_func_imports, sig_index); - ctx->num_func_imports++; + CALLBACK(OnImportFunc, i, module_name, field_name, num_func_imports_, + sig_index); + num_func_imports_++; break; } case ExternalKind::Table: { Type elem_type; Limits elem_limits; - read_table(ctx, &elem_type, &elem_limits); + CHECK_RESULT(ReadTable(&elem_type, &elem_limits)); CALLBACK(OnImport, i, module_name, field_name); - CALLBACK(OnImportTable, i, module_name, field_name, - ctx->num_table_imports, elem_type, &elem_limits); - ctx->num_table_imports++; + CALLBACK(OnImportTable, i, module_name, field_name, num_table_imports_, + elem_type, &elem_limits); + num_table_imports_++; break; } case ExternalKind::Memory: { Limits page_limits; - read_memory(ctx, &page_limits); + CHECK_RESULT(ReadMemory(&page_limits)); CALLBACK(OnImport, i, module_name, field_name); CALLBACK(OnImportMemory, i, module_name, field_name, - ctx->num_memory_imports, &page_limits); - ctx->num_memory_imports++; + num_memory_imports_, &page_limits); + num_memory_imports_++; break; } case ExternalKind::Global: { Type type; bool mutable_; - read_global_header(ctx, &type, &mutable_); + CHECK_RESULT(ReadGlobalHeader(&type, &mutable_)); CALLBACK(OnImport, i, module_name, field_name); CALLBACK(OnImportGlobal, i, module_name, field_name, - ctx->num_global_imports, type, mutable_); - ctx->num_global_imports++; + num_global_imports_, type, mutable_); + num_global_imports_++; break; } default: - RAISE_ERROR("invalid import kind: %d", kind); + PrintError("invalid import kind: %d", kind); + return Result::Error; } } CALLBACK0(EndImportSection); + return Result::Ok; } -static void read_function_section(Context* ctx, Offset section_size) { +Result BinaryReader::ReadFunctionSection(Offset section_size) { CALLBACK(BeginFunctionSection, section_size); - in_index(ctx, &ctx->num_function_signatures, "function signature count"); - CALLBACK(OnFunctionCount, ctx->num_function_signatures); - for (Index i = 0; i < ctx->num_function_signatures; ++i) { - Index func_index = ctx->num_func_imports + i; + CHECK_RESULT( + ReadIndex(&num_function_signatures_, "function signature count")); + CALLBACK(OnFunctionCount, num_function_signatures_); + for (Index i = 0; i < num_function_signatures_; ++i) { + Index func_index = num_func_imports_ + i; Index sig_index; - in_index(ctx, &sig_index, "function signature index"); - RAISE_ERROR_UNLESS(sig_index < ctx->num_signatures, - "invalid function signature index: %" PRIindex, - sig_index); + CHECK_RESULT(ReadIndex(&sig_index, "function signature index")); + ERROR_UNLESS(sig_index < num_signatures_, + "invalid function signature index: %" PRIindex, sig_index); CALLBACK(OnFunction, func_index, sig_index); } CALLBACK0(EndFunctionSection); + return Result::Ok; } -static void read_table_section(Context* ctx, Offset section_size) { +Result BinaryReader::ReadTableSection(Offset section_size) { CALLBACK(BeginTableSection, section_size); - in_index(ctx, &ctx->num_tables, "table count"); - RAISE_ERROR_UNLESS(ctx->num_tables <= 1, - "table count (%" PRIindex ") must be 0 or 1", - ctx->num_tables); - CALLBACK(OnTableCount, ctx->num_tables); - for (Index i = 0; i < ctx->num_tables; ++i) { - Index table_index = ctx->num_table_imports + i; + CHECK_RESULT(ReadIndex(&num_tables_, "table count")); + ERROR_UNLESS(num_tables_ <= 1, "table count (%" PRIindex ") must be 0 or 1", + num_tables_); + CALLBACK(OnTableCount, num_tables_); + for (Index i = 0; i < num_tables_; ++i) { + Index table_index = num_table_imports_ + i; Type elem_type; Limits elem_limits; - read_table(ctx, &elem_type, &elem_limits); + CHECK_RESULT(ReadTable(&elem_type, &elem_limits)); CALLBACK(OnTable, table_index, elem_type, &elem_limits); } CALLBACK0(EndTableSection); + return Result::Ok; } -static void read_memory_section(Context* ctx, Offset section_size) { +Result BinaryReader::ReadMemorySection(Offset section_size) { CALLBACK(BeginMemorySection, section_size); - in_index(ctx, &ctx->num_memories, "memory count"); - RAISE_ERROR_UNLESS(ctx->num_memories <= 1, "memory count must be 0 or 1"); - CALLBACK(OnMemoryCount, ctx->num_memories); - for (Index i = 0; i < ctx->num_memories; ++i) { - Index memory_index = ctx->num_memory_imports + i; + CHECK_RESULT(ReadIndex(&num_memories_, "memory count")); + ERROR_UNLESS(num_memories_ <= 1, "memory count must be 0 or 1"); + CALLBACK(OnMemoryCount, num_memories_); + for (Index i = 0; i < num_memories_; ++i) { + Index memory_index = num_memory_imports_ + i; Limits page_limits; - read_memory(ctx, &page_limits); + CHECK_RESULT(ReadMemory(&page_limits)); CALLBACK(OnMemory, memory_index, &page_limits); } CALLBACK0(EndMemorySection); + return Result::Ok; } -static void read_global_section(Context* ctx, Offset section_size) { +Result BinaryReader::ReadGlobalSection(Offset section_size) { CALLBACK(BeginGlobalSection, section_size); - in_index(ctx, &ctx->num_globals, "global count"); - CALLBACK(OnGlobalCount, ctx->num_globals); - for (Index i = 0; i < ctx->num_globals; ++i) { - Index global_index = ctx->num_global_imports + i; + CHECK_RESULT(ReadIndex(&num_globals_, "global count")); + CALLBACK(OnGlobalCount, num_globals_); + for (Index i = 0; i < num_globals_; ++i) { + Index global_index = num_global_imports_ + i; Type global_type; bool mutable_; - read_global_header(ctx, &global_type, &mutable_); + CHECK_RESULT(ReadGlobalHeader(&global_type, &mutable_)); CALLBACK(BeginGlobal, global_index, global_type, mutable_); CALLBACK(BeginGlobalInitExpr, global_index); - read_init_expr(ctx, global_index); + CHECK_RESULT(ReadInitExpr(global_index)); CALLBACK(EndGlobalInitExpr, global_index); CALLBACK(EndGlobal, global_index); } CALLBACK0(EndGlobalSection); + return Result::Ok; } -static void read_export_section(Context* ctx, Offset section_size) { +Result BinaryReader::ReadExportSection(Offset section_size) { CALLBACK(BeginExportSection, section_size); - in_index(ctx, &ctx->num_exports, "export count"); - CALLBACK(OnExportCount, ctx->num_exports); - for (Index i = 0; i < ctx->num_exports; ++i) { + CHECK_RESULT(ReadIndex(&num_exports_, "export count")); + CALLBACK(OnExportCount, num_exports_); + for (Index i = 0; i < num_exports_; ++i) { StringSlice name; - in_str(ctx, &name, "export item name"); + CHECK_RESULT(ReadStr(&name, "export item name")); - uint8_t external_kind; - in_u8(ctx, &external_kind, "export external kind"); - RAISE_ERROR_UNLESS(is_valid_external_kind(external_kind), - "invalid export external kind: %d", external_kind); + uint8_t external_kind = 0; + CHECK_RESULT(ReadU8(&external_kind, "export external kind")); + ERROR_UNLESS(is_valid_external_kind(external_kind), + "invalid export external kind: %d", external_kind); Index item_index; - in_index(ctx, &item_index, "export item index"); + CHECK_RESULT(ReadIndex(&item_index, "export item index")); switch (static_cast<ExternalKind>(external_kind)) { case ExternalKind::Func: - RAISE_ERROR_UNLESS(item_index < num_total_funcs(ctx), - "invalid export func index: %" PRIindex, item_index); + ERROR_UNLESS(item_index < NumTotalFuncs(), + "invalid export func index: %" PRIindex, item_index); break; case ExternalKind::Table: - RAISE_ERROR_UNLESS(item_index < num_total_tables(ctx), - "invalid export table index: %" PRIindex, - item_index); + ERROR_UNLESS(item_index < NumTotalTables(), + "invalid export table index: %" PRIindex, item_index); break; case ExternalKind::Memory: - RAISE_ERROR_UNLESS(item_index < num_total_memories(ctx), - "invalid export memory index: %" PRIindex, - item_index); + ERROR_UNLESS(item_index < NumTotalMemories(), + "invalid export memory index: %" PRIindex, item_index); break; case ExternalKind::Global: - RAISE_ERROR_UNLESS(item_index < num_total_globals(ctx), - "invalid export global index: %" PRIindex, - item_index); + ERROR_UNLESS(item_index < NumTotalGlobals(), + "invalid export global index: %" PRIindex, item_index); break; } @@ -1266,137 +1346,142 @@ static void read_export_section(Context* ctx, Offset section_size) { name); } CALLBACK0(EndExportSection); + return Result::Ok; } -static void read_start_section(Context* ctx, Offset section_size) { +Result BinaryReader::ReadStartSection(Offset section_size) { CALLBACK(BeginStartSection, section_size); Index func_index; - in_index(ctx, &func_index, "start function index"); - RAISE_ERROR_UNLESS(func_index < num_total_funcs(ctx), - "invalid start function index: %" PRIindex, func_index); + CHECK_RESULT(ReadIndex(&func_index, "start function index")); + ERROR_UNLESS(func_index < NumTotalFuncs(), + "invalid start function index: %" PRIindex, func_index); CALLBACK(OnStartFunction, func_index); CALLBACK0(EndStartSection); + return Result::Ok; } -static void read_elem_section(Context* ctx, Offset section_size) { +Result BinaryReader::ReadElemSection(Offset section_size) { CALLBACK(BeginElemSection, section_size); Index num_elem_segments; - in_index(ctx, &num_elem_segments, "elem segment count"); + CHECK_RESULT(ReadIndex(&num_elem_segments, "elem segment count")); CALLBACK(OnElemSegmentCount, num_elem_segments); - RAISE_ERROR_UNLESS(num_elem_segments == 0 || num_total_tables(ctx) > 0, - "elem section without table section"); + ERROR_UNLESS(num_elem_segments == 0 || NumTotalTables() > 0, + "elem section without table section"); for (Index i = 0; i < num_elem_segments; ++i) { Index table_index; - in_index(ctx, &table_index, "elem segment table index"); + CHECK_RESULT(ReadIndex(&table_index, "elem segment table index")); CALLBACK(BeginElemSegment, i, table_index); CALLBACK(BeginElemSegmentInitExpr, i); - read_init_expr(ctx, i); + CHECK_RESULT(ReadInitExpr(i)); CALLBACK(EndElemSegmentInitExpr, i); Index num_function_indexes; - in_index(ctx, &num_function_indexes, "elem segment function index count"); + CHECK_RESULT( + ReadIndex(&num_function_indexes, "elem segment function index count")); CALLBACK(OnElemSegmentFunctionIndexCount, i, num_function_indexes); for (Index j = 0; j < num_function_indexes; ++j) { Index func_index; - in_index(ctx, &func_index, "elem segment function index"); + CHECK_RESULT(ReadIndex(&func_index, "elem segment function index")); CALLBACK(OnElemSegmentFunctionIndex, i, func_index); } CALLBACK(EndElemSegment, i); } CALLBACK0(EndElemSection); + return Result::Ok; } -static void read_code_section(Context* ctx, Offset section_size) { +Result BinaryReader::ReadCodeSection(Offset section_size) { CALLBACK(BeginCodeSection, section_size); - in_index(ctx, &ctx->num_function_bodies, "function body count"); - RAISE_ERROR_UNLESS(ctx->num_function_signatures == ctx->num_function_bodies, - "function signature count != function body count"); - CALLBACK(OnFunctionBodyCount, ctx->num_function_bodies); - for (Index i = 0; i < ctx->num_function_bodies; ++i) { - Index func_index = ctx->num_func_imports + i; - Offset func_offset = ctx->state.offset; - ctx->state.offset = func_offset; + CHECK_RESULT(ReadIndex(&num_function_bodies_, "function body count")); + ERROR_UNLESS(num_function_signatures_ == num_function_bodies_, + "function signature count != function body count"); + CALLBACK(OnFunctionBodyCount, num_function_bodies_); + for (Index i = 0; i < num_function_bodies_; ++i) { + Index func_index = num_func_imports_ + i; + Offset func_offset = state_.offset; + state_.offset = func_offset; CALLBACK(BeginFunctionBody, func_index); uint32_t body_size; - in_u32_leb128(ctx, &body_size, "function body size"); - Offset body_start_offset = ctx->state.offset; + CHECK_RESULT(ReadU32Leb128(&body_size, "function body size")); + Offset body_start_offset = state_.offset; Offset end_offset = body_start_offset + body_size; Index num_local_decls; - in_index(ctx, &num_local_decls, "local declaration count"); + CHECK_RESULT(ReadIndex(&num_local_decls, "local declaration count")); CALLBACK(OnLocalDeclCount, num_local_decls); for (Index k = 0; k < num_local_decls; ++k) { Index num_local_types; - in_index(ctx, &num_local_types, "local type count"); + CHECK_RESULT(ReadIndex(&num_local_types, "local type count")); Type local_type; - in_type(ctx, &local_type, "local type"); - RAISE_ERROR_UNLESS(is_concrete_type(local_type), - "expected valid local type"); + CHECK_RESULT(ReadType(&local_type, "local type")); + ERROR_UNLESS(is_concrete_type(local_type), "expected valid local type"); CALLBACK(OnLocalDecl, k, num_local_types, local_type); } - read_function_body(ctx, end_offset); + CHECK_RESULT(ReadFunctionBody(end_offset)); CALLBACK(EndFunctionBody, func_index); } CALLBACK0(EndCodeSection); + return Result::Ok; } -static void read_data_section(Context* ctx, Offset section_size) { +Result BinaryReader::ReadDataSection(Offset section_size) { CALLBACK(BeginDataSection, section_size); Index num_data_segments; - in_index(ctx, &num_data_segments, "data segment count"); + CHECK_RESULT(ReadIndex(&num_data_segments, "data segment count")); CALLBACK(OnDataSegmentCount, num_data_segments); - RAISE_ERROR_UNLESS(num_data_segments == 0 || num_total_memories(ctx) > 0, - "data section without memory section"); + ERROR_UNLESS(num_data_segments == 0 || NumTotalMemories() > 0, + "data section without memory section"); for (Index i = 0; i < num_data_segments; ++i) { Index memory_index; - in_index(ctx, &memory_index, "data segment memory index"); + CHECK_RESULT(ReadIndex(&memory_index, "data segment memory index")); CALLBACK(BeginDataSegment, i, memory_index); CALLBACK(BeginDataSegmentInitExpr, i); - read_init_expr(ctx, i); + CHECK_RESULT(ReadInitExpr(i)); CALLBACK(EndDataSegmentInitExpr, i); Address data_size; const void* data; - in_bytes(ctx, &data, &data_size, "data segment data"); + CHECK_RESULT(ReadBytes(&data, &data_size, "data segment data")); CALLBACK(OnDataSegmentData, i, data, data_size); CALLBACK(EndDataSegment, i); } CALLBACK0(EndDataSection); + return Result::Ok; } -static void read_sections(Context* ctx) { - while (ctx->state.offset < ctx->state.size) { +Result BinaryReader::ReadSections() { + while (state_.offset < state_.size) { uint32_t section_code; Offset section_size; - /* Temporarily reset read_end to the full data size so the next section + /* Temporarily reset read_end_ to the full data size so the next section * can be read. */ - ctx->read_end = ctx->state.size; - in_u32_leb128(ctx, §ion_code, "section code"); - in_file_offset(ctx, §ion_size, "section size"); - ctx->read_end = ctx->state.offset + section_size; + read_end_ = state_.size; + CHECK_RESULT(ReadU32Leb128(§ion_code, "section code")); + CHECK_RESULT(ReadOffset(§ion_size, "section size")); + read_end_ = state_.offset + section_size; if (section_code >= kBinarySectionCount) { - RAISE_ERROR("invalid section code: %u; max is %u", section_code, - kBinarySectionCount - 1); + PrintError("invalid section code: %u; max is %u", section_code, + kBinarySectionCount - 1); + return Result::Error; } BinarySection section = static_cast<BinarySection>(section_code); - if (ctx->read_end > ctx->state.size) - RAISE_ERROR("invalid section size: extends past end"); + ERROR_UNLESS(read_end_ <= state_.size, + "invalid section size: extends past end"); - if (ctx->last_known_section != BinarySection::Invalid && - section != BinarySection::Custom && - section <= ctx->last_known_section) { - RAISE_ERROR("section %s out of order", get_section_name(section)); - } + ERROR_UNLESS(last_known_section_ == BinarySection::Invalid || + section == BinarySection::Custom || + section > last_known_section_, + "section %s out of order", get_section_name(section)); CALLBACK(BeginSection, section, section_size); -#define V(Name, name, code) \ - case BinarySection::Name: \ - read_##name##_section(ctx, section_size); \ +#define V(Name, name, code) \ + case BinarySection::Name: \ + CHECK_RESULT(Read##Name##Section(section_size)); \ break; switch (section) { @@ -1409,50 +1494,40 @@ static void read_sections(Context* ctx) { #undef V - if (ctx->state.offset != ctx->read_end) { - RAISE_ERROR("unfinished section (expected end: 0x%" PRIzx ")", - ctx->read_end); - } + ERROR_UNLESS(state_.offset == read_end_, + "unfinished section (expected end: 0x%" PRIzx ")", read_end_); if (section != BinarySection::Custom) - ctx->last_known_section = section; + last_known_section_ = section; } + return Result::Ok; } -Result read_binary(const void* data, - size_t size, - BinaryReader* reader, - const ReadBinaryOptions* options) { - BinaryReaderLogging logging_reader(options->log_stream, reader); - Context context; - /* all the macros assume a Context* named ctx */ - Context* ctx = &context; - ctx->state.data = static_cast<const uint8_t*>(data); - ctx->state.size = ctx->read_end = size; - ctx->state.offset = 0; - ctx->reader = options->log_stream ? &logging_reader : reader; - ctx->options = options; - ctx->last_known_section = BinarySection::Invalid; - - if (setjmp(ctx->error_jmp_buf) == 1) { - return Result::Error; - } - - ctx->reader->OnSetState(&ctx->state); - - uint32_t magic; - in_u32(ctx, &magic, "magic"); - RAISE_ERROR_UNLESS(magic == WABT_BINARY_MAGIC, "bad magic value"); - uint32_t version; - in_u32(ctx, &version, "version"); - RAISE_ERROR_UNLESS(version == WABT_BINARY_VERSION, - "bad wasm file version: %#x (expected %#x)", version, - WABT_BINARY_VERSION); +Result BinaryReader::ReadModule() { + uint32_t magic = 0; + CHECK_RESULT(ReadU32(&magic, "magic")); + ERROR_UNLESS(magic == WABT_BINARY_MAGIC, "bad magic value"); + uint32_t version = 0; + CHECK_RESULT(ReadU32(&version, "version")); + ERROR_UNLESS(version == WABT_BINARY_VERSION, + "bad wasm file version: %#x (expected %#x)", version, + WABT_BINARY_VERSION); CALLBACK(BeginModule, version); - read_sections(ctx); + CHECK_RESULT(ReadSections()); CALLBACK0(EndModule); + return Result::Ok; } +} // namespace + +Result read_binary(const void* data, + size_t size, + BinaryReaderDelegate* delegate, + const ReadBinaryOptions* options) { + BinaryReader reader(data, size, delegate, options); + return reader.ReadModule(); +} + } // namespace wabt |