summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/binary-reader.cc52
-rw-r--r--src/error.h1
-rw-r--r--src/leb128.cc11
-rw-r--r--src/leb128.h1
-rw-r--r--src/opcode.cc16
-rw-r--r--src/opcode.h8
-rw-r--r--src/test-binary-reader.cc75
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;
+ }
+}