diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binary-reader.cc | 52 | ||||
-rw-r--r-- | src/error.h | 1 | ||||
-rw-r--r-- | src/leb128.cc | 11 | ||||
-rw-r--r-- | src/leb128.h | 1 | ||||
-rw-r--r-- | src/opcode.cc | 16 | ||||
-rw-r--r-- | src/opcode.h | 8 | ||||
-rw-r--r-- | src/test-binary-reader.cc | 75 |
7 files changed, 129 insertions, 35 deletions
diff --git a/src/binary-reader.cc b/src/binary-reader.cc index d4f2037d..c36cca4e 100644 --- a/src/binary-reader.cc +++ b/src/binary-reader.cc @@ -202,19 +202,23 @@ void WABT_PRINTF_FORMAT(2, 3) BinaryReader::PrintError(const char* format, } Result BinaryReader::ReportUnexpectedOpcode(Opcode opcode, - const char* message) { - const char* maybe_space = " "; - if (!message) { - message = maybe_space = ""; + const char* where) { + std::string message = "unexpected opcode"; + if (where) { + message += ' '; + message += where; } - if (opcode.HasPrefix()) { - PrintError("unexpected opcode%s%s: %d %d (0x%x 0x%x)", maybe_space, message, - opcode.GetPrefix(), opcode.GetCode(), opcode.GetPrefix(), - opcode.GetCode()); - } else { - PrintError("unexpected opcode%s%s: %d (0x%x)", maybe_space, message, - opcode.GetCode(), opcode.GetCode()); + + message += ":"; + + std::vector<uint8_t> bytes = opcode.GetBytes(); + assert(bytes.size() > 0); + + for (uint8_t byte: bytes) { + message += StringPrintf(" 0x%x", byte); } + + PrintError("%s", message.c_str()); return Result::Error; } @@ -416,6 +420,7 @@ Result BinaryReader::ReadI32InitExpr(Index index) { Result BinaryReader::ReadInitExpr(Index index, bool require_i32) { Opcode opcode; CHECK_RESULT(ReadOpcode(&opcode, "opcode")); + ERROR_UNLESS_OPCODE_ENABLED(opcode); switch (opcode) { case Opcode::I32Const: { @@ -447,7 +452,6 @@ Result BinaryReader::ReadInitExpr(Index index, bool require_i32) { } case Opcode::V128Const: { - ERROR_UNLESS_OPCODE_ENABLED(opcode); v128 value_bits; ZeroMemory(value_bits); CHECK_RESULT(ReadV128(&value_bits, "init_expr v128.const value")); @@ -550,6 +554,8 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { Opcode opcode; CHECK_RESULT(ReadOpcode(&opcode, "opcode")); CALLBACK(OnOpcode, opcode); + ERROR_UNLESS_OPCODE_ENABLED(opcode); + switch (opcode) { case Opcode::Unreachable: CALLBACK0(OnUnreachableExpr); @@ -691,7 +697,6 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { } case Opcode::V128Const: { - ERROR_UNLESS_OPCODE_ENABLED(opcode); v128 value_bits; ZeroMemory(value_bits); CHECK_RESULT(ReadV128(&value_bits, "v128.const value")); @@ -756,7 +761,6 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { } case Opcode::ReturnCall: { - ERROR_UNLESS_OPCODE_ENABLED(opcode); Index func_index; CHECK_RESULT(ReadIndex(&func_index, "return_call")); ERROR_UNLESS(func_index < NumTotalFuncs(), @@ -768,7 +772,6 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { } case Opcode::ReturnCallIndirect: { - ERROR_UNLESS_OPCODE_ENABLED(opcode); Index sig_index; CHECK_RESULT(ReadIndex(&sig_index, "return_call_indirect")); @@ -944,7 +947,6 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { case Opcode::F64X2Div: case Opcode::F32X4Mul: case Opcode::F64X2Mul: - ERROR_UNLESS_OPCODE_ENABLED(opcode); CALLBACK(OnBinaryExpr, opcode); CALLBACK0(OnOpcodeBare); break; @@ -1023,7 +1025,6 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { case Opcode::I32X4GeU: case Opcode::F32X4Ge: case Opcode::F64X2Ge: - ERROR_UNLESS_OPCODE_ENABLED(opcode); CALLBACK(OnCompareExpr, opcode); CALLBACK0(OnOpcodeBare); break; @@ -1073,13 +1074,11 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { case Opcode::F64X2Abs: case Opcode::F32X4Sqrt: case Opcode::F64X2Sqrt: - ERROR_UNLESS_OPCODE_ENABLED(opcode); CALLBACK(OnUnaryExpr, opcode); CALLBACK0(OnOpcodeBare); break; case Opcode::V128BitSelect: - ERROR_UNLESS_OPCODE_ENABLED(opcode); CALLBACK(OnTernaryExpr, opcode); CALLBACK0(OnOpcodeBare); break; @@ -1098,7 +1097,6 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { case Opcode::I64X2ReplaceLane: case Opcode::F32X4ReplaceLane: case Opcode::F64X2ReplaceLane: { - ERROR_UNLESS_OPCODE_ENABLED(opcode); uint8_t lane_val; CHECK_RESULT(ReadU8(&lane_val, "Lane idx")); CALLBACK(OnSimdLaneOpExpr, opcode, lane_val); @@ -1107,7 +1105,6 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { } case Opcode::V8X16Shuffle: { - ERROR_UNLESS_OPCODE_ENABLED(opcode); v128 value; CHECK_RESULT(ReadV128(&value, "Lane idx [16]")); CALLBACK(OnSimdShuffleOpExpr, opcode, value); @@ -1150,13 +1147,11 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { case Opcode::I32X4TruncUF32X4Sat: case Opcode::I64X2TruncSF64X2Sat: case Opcode::I64X2TruncUF64X2Sat: - ERROR_UNLESS_OPCODE_ENABLED(opcode); CALLBACK(OnConvertExpr, opcode); CALLBACK0(OnOpcodeBare); break; case Opcode::Try: { - ERROR_UNLESS_OPCODE_ENABLED(opcode); Type sig_type; CHECK_RESULT(ReadType(&sig_type, "try signature type")); ERROR_UNLESS(IsBlockType(sig_type), @@ -1167,21 +1162,18 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { } case Opcode::Catch: { - ERROR_UNLESS_OPCODE_ENABLED(opcode); CALLBACK0(OnCatchExpr); CALLBACK0(OnOpcodeBare); break; } case Opcode::Rethrow: { - ERROR_UNLESS_OPCODE_ENABLED(opcode); CALLBACK0(OnRethrowExpr); CALLBACK0(OnOpcodeBare); break; } case Opcode::Throw: { - ERROR_UNLESS_OPCODE_ENABLED(opcode); Index index; CHECK_RESULT(ReadIndex(&index, "exception index")); CALLBACK(OnThrowExpr, index); @@ -1190,7 +1182,6 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { } case Opcode::IfExcept: { - ERROR_UNLESS_OPCODE_ENABLED(opcode); Type sig_type; CHECK_RESULT(ReadType(&sig_type, "if signature type")); ERROR_UNLESS(IsBlockType(sig_type), @@ -1206,7 +1197,6 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { case Opcode::I64Extend8S: case Opcode::I64Extend16S: case Opcode::I64Extend32S: - ERROR_UNLESS_OPCODE_ENABLED(opcode); CALLBACK(OnUnaryExpr, opcode); CALLBACK0(OnOpcodeBare); break; @@ -1219,7 +1209,6 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { case Opcode::I64TruncUSatF32: case Opcode::I64TruncSSatF64: case Opcode::I64TruncUSatF64: - ERROR_UNLESS_OPCODE_ENABLED(opcode); CALLBACK(OnConvertExpr, opcode); CALLBACK0(OnOpcodeBare); break; @@ -1351,7 +1340,6 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { } case Opcode::TableInit: { - ERROR_UNLESS_OPCODE_ENABLED(opcode); uint8_t reserved; CHECK_RESULT(ReadU8(&reserved, "reserved table index")); ERROR_UNLESS(reserved == 0, "reserved value must be 0"); @@ -1363,7 +1351,6 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { } case Opcode::MemoryInit: { - ERROR_UNLESS_OPCODE_ENABLED(opcode); uint8_t reserved; CHECK_RESULT(ReadU8(&reserved, "reserved memory index")); ERROR_UNLESS(reserved == 0, "reserved value must be 0"); @@ -1376,7 +1363,6 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { case Opcode::MemoryDrop: case Opcode::TableDrop: { - ERROR_UNLESS_OPCODE_ENABLED(opcode); Index segment; CHECK_RESULT(ReadIndex(&segment, "segment index")); if (opcode == Opcode::MemoryDrop) { @@ -1390,7 +1376,6 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { case Opcode::MemoryCopy: case Opcode::MemoryFill: { - ERROR_UNLESS_OPCODE_ENABLED(opcode); uint8_t reserved; CHECK_RESULT(ReadU8(&reserved, "reserved memory index")); ERROR_UNLESS(reserved == 0, "reserved value must be 0"); @@ -1404,7 +1389,6 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { } case Opcode::TableCopy: { - ERROR_UNLESS_OPCODE_ENABLED(opcode); uint8_t reserved; CHECK_RESULT(ReadU8(&reserved, "reserved table index")); ERROR_UNLESS(reserved == 0, "reserved value must be 0"); diff --git a/src/error.h b/src/error.h index 5c0d1ee5..cffca1e5 100644 --- a/src/error.h +++ b/src/error.h @@ -42,6 +42,7 @@ static WABT_INLINE const char* GetErrorLevelName(ErrorLevel error_level) { class Error { public: + Error() : error_level(ErrorLevel::Error) {} Error(ErrorLevel error_level, Location loc, string_view message) : error_level(error_level), loc(loc), message(message.to_string()) {} diff --git a/src/leb128.cc b/src/leb128.cc index 1f550b05..796c4e29 100644 --- a/src/leb128.cc +++ b/src/leb128.cc @@ -83,6 +83,17 @@ Offset WriteU32Leb128At(Stream* stream, return length; } +Offset WriteU32Leb128Raw(uint8_t* dest, uint8_t* dest_end, uint32_t value) { + uint8_t data[MAX_U32_LEB128_BYTES]; + Offset length = 0; + LEB128_LOOP_UNTIL(value == 0); + if (static_cast<Offset>(dest_end - dest) < length) { + return 0; + } + memcpy(dest, data, length); + return length; +} + Offset WriteFixedU32Leb128Raw(uint8_t* data, uint8_t* end, uint32_t value) { if (end - data < MAX_U32_LEB128_BYTES) { return 0; diff --git a/src/leb128.h b/src/leb128.h index 2fa0b4ec..33eb544a 100644 --- a/src/leb128.h +++ b/src/leb128.h @@ -43,6 +43,7 @@ Offset WriteFixedU32Leb128At(Stream* stream, uint32_t value, const char* desc); +Offset WriteU32Leb128Raw(uint8_t* data, uint8_t* end, uint32_t value); Offset WriteFixedU32Leb128Raw(uint8_t* data, uint8_t* end, uint32_t value); // Convenience functions for writing enums as LEB128s. diff --git a/src/opcode.cc b/src/opcode.cc index 78c197d0..10df4e2e 100644 --- a/src/opcode.cc +++ b/src/opcode.cc @@ -353,4 +353,20 @@ uint32_t Opcode::GetSimdLaneCount() const { } } +// Get the byte sequence for this opcode, including prefix. +std::vector<uint8_t> Opcode::GetBytes() const { + std::vector<uint8_t> result; + if (HasPrefix()) { + result.push_back(GetPrefix()); + uint8_t buffer[5]; + Offset length = + WriteU32Leb128Raw(buffer, buffer + sizeof(buffer), GetCode()); + assert(length != 0); + result.insert(result.end(), buffer, buffer + length); + } else { + result.push_back(GetCode()); + } + return result; +} + } // namespace wabt diff --git a/src/opcode.h b/src/opcode.h index 2a4d7d74..bdf1b589 100644 --- a/src/opcode.h +++ b/src/opcode.h @@ -17,8 +17,11 @@ #ifndef WABT_OPCODE_H_ #define WABT_OPCODE_H_ +#include <vector> + #include "src/common.h" #include "src/opcode-code-table.h" +#include "src/leb128.h" namespace wabt { @@ -54,7 +57,7 @@ struct Opcode { bool HasPrefix() const { return GetInfo().prefix != 0; } uint8_t GetPrefix() const { return GetInfo().prefix; } uint32_t GetCode() const { return GetInfo().code; } - size_t GetLength() const { return HasPrefix() ? 2 : 1; } + size_t GetLength() const { return GetBytes().size(); } const char* GetName() const { return GetInfo().name; } Type GetResultType() const { return GetInfo().result_type; } Type GetParamType1() const { return GetInfo().param1_type; } @@ -62,6 +65,9 @@ struct Opcode { Type GetParamType3() const { return GetInfo().param3_type; } Address GetMemorySize() const { return GetInfo().memory_size; } + // Get the byte sequence for this opcode, including prefix. + std::vector<uint8_t> GetBytes() const; + // Get the lane count of an extract/replace simd op. uint32_t GetSimdLaneCount() const; diff --git a/src/test-binary-reader.cc b/src/test-binary-reader.cc new file mode 100644 index 00000000..a96ccdb7 --- /dev/null +++ b/src/test-binary-reader.cc @@ -0,0 +1,75 @@ +/* + * Copyright 2018 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "gtest/gtest.h" + +#include "src/binary-reader.h" +#include "src/binary-reader-nop.h" +#include "src/leb128.h" +#include "src/opcode.h" + +using namespace wabt; + +namespace { + +struct BinaryReaderError : BinaryReaderNop { + bool OnError(const Error& error) override { + first_error = error; + return true; // Error handled. + } + + Error first_error; +}; + +} // End of anonymous namespace + +TEST(BinaryReader, DisabledOpcodes) { + // Use the default features. + ReadBinaryOptions options; + + // Loop through all opcodes. + for (uint32_t i = 0; i < static_cast<uint32_t>(Opcode::Invalid); ++i) { + Opcode opcode(static_cast<Opcode::Enum>(i)); + if (opcode.IsEnabled(options.features)) { + continue; + } + + // Use a shorter name to make the clang-formatted table below look nicer. + std::vector<uint8_t> b = opcode.GetBytes(); + assert(b.size() <= 3); + b.resize(3); + + uint8_t data[] = { + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, // magic + version + 0x01, 0x04, 0x01, 0x60, 0x00, 0x00, // type section: 1 type, (func) + 0x03, 0x02, 0x01, 0x00, // func section: 1 func, type 0 + 0x0a, 0x07, 0x01, 0x05, 0x00, // code section: 1 func, 0 locals + b[0], b[1], b[2], // The instruction, padded with zeroes + 0x0b, // end + }; + const size_t size = sizeof(data); + + BinaryReaderError reader; + Result result = ReadBinary(data, size, &reader, options); + EXPECT_EQ(Result::Error, result); + + // This relies on the binary reader checking whether the opcode is allowed + // before reading any further data needed by the instruction. + const std::string& message = reader.first_error.message; + EXPECT_EQ(0u, message.find("unexpected opcode")) + << "Got error message: " << message; + } +} |