|
|
@@ -0,0 +1,161 @@
|
|
|
+/*
|
|
|
+ * Copyright (C) 2024 Intel Corporation. All rights reserved.
|
|
|
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
+ */
|
|
|
+
|
|
|
+#include "gtest/gtest.h"
|
|
|
+#include "wasm_runtime_common.h"
|
|
|
+#include "bh_platform.h"
|
|
|
+
|
|
|
+/* Pull in the INVALID_TAGINDEX definitions */
|
|
|
+#include "wasm_runtime.h"
|
|
|
+
|
|
|
+class ExceptionHandlingTest : public testing::Test
|
|
|
+{
|
|
|
+ protected:
|
|
|
+ virtual void SetUp()
|
|
|
+ {
|
|
|
+ memset(&init_args, 0, sizeof(RuntimeInitArgs));
|
|
|
+ init_args.mem_alloc_type = Alloc_With_Pool;
|
|
|
+ init_args.mem_alloc_option.pool.heap_buf = global_heap_buf;
|
|
|
+ init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf);
|
|
|
+ ASSERT_EQ(wasm_runtime_full_init(&init_args), true);
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void TearDown() { wasm_runtime_destroy(); }
|
|
|
+
|
|
|
+ public:
|
|
|
+ char global_heap_buf[512 * 1024];
|
|
|
+ RuntimeInitArgs init_args;
|
|
|
+ char error_buf[256];
|
|
|
+};
|
|
|
+
|
|
|
+/*
|
|
|
+ * Test that IS_INVALID_TAGINDEX correctly identifies the invalid tag index
|
|
|
+ * value (0xFFFFFFFF) used for cross-module exceptions with unknown tags.
|
|
|
+ *
|
|
|
+ * The RETHROW handler must check IS_INVALID_TAGINDEX before accessing
|
|
|
+ * module->module->tags[exception_tag_index]. Without the check,
|
|
|
+ * exception_tag_index = INVALID_TAGINDEX (0xFFFFFFFF) would cause
|
|
|
+ * tags[0xFFFFFFFF] -- a massive out-of-bounds read.
|
|
|
+ *
|
|
|
+ * The THROW handler at wasm_interp_classic.c properly checks
|
|
|
+ * IS_INVALID_TAGINDEX, but previously RETHROW did not.
|
|
|
+ */
|
|
|
+TEST_F(ExceptionHandlingTest, invalid_tagindex_detected)
|
|
|
+{
|
|
|
+ uint32_t tag_index = INVALID_TAGINDEX;
|
|
|
+ EXPECT_TRUE(IS_INVALID_TAGINDEX(tag_index))
|
|
|
+ << "INVALID_TAGINDEX (0xFFFFFFFF) should be detected";
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(ExceptionHandlingTest, valid_tagindex_not_rejected)
|
|
|
+{
|
|
|
+ uint32_t tag_index = 0;
|
|
|
+ EXPECT_FALSE(IS_INVALID_TAGINDEX(tag_index))
|
|
|
+ << "Tag index 0 should not be detected as invalid";
|
|
|
+
|
|
|
+ tag_index = 5;
|
|
|
+ EXPECT_FALSE(IS_INVALID_TAGINDEX(tag_index))
|
|
|
+ << "Tag index 5 should not be detected as invalid";
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Test that a WASM module with exception handling (try/catch/throw)
|
|
|
+ * can load and instantiate correctly when exception handling is enabled.
|
|
|
+ */
|
|
|
+TEST_F(ExceptionHandlingTest, load_module_with_exception_handling)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * Minimal WASM module with exception handling:
|
|
|
+ * - Tag section (id=13): 1 tag, type 0 (no params)
|
|
|
+ * - Function with try/catch_all/end that does nothing
|
|
|
+ */
|
|
|
+ uint8_t wasm_eh[] = {
|
|
|
+ 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00,
|
|
|
+ /* Type section: 1 type, () -> () */
|
|
|
+ 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
|
|
|
+ /* Function section: 1 func, type 0 */
|
|
|
+ 0x03, 0x02, 0x01, 0x00,
|
|
|
+ /* Tag section (id=13): 1 tag, attribute=0, type=0 */
|
|
|
+ 0x0D, 0x03, 0x01, 0x00, 0x00,
|
|
|
+ /* Export: "f" = func 0 */
|
|
|
+ 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00,
|
|
|
+ /* Code section */
|
|
|
+ 0x0A, 0x08, 0x01,
|
|
|
+ 0x06, 0x00, /* body size=6, 0 locals */
|
|
|
+ 0x06, 0x40, /* try (void) */
|
|
|
+ 0x19, /* catch_all */
|
|
|
+ 0x0B, /* end try */
|
|
|
+ 0x0B, /* end func */
|
|
|
+ };
|
|
|
+
|
|
|
+ memset(error_buf, 0, sizeof(error_buf));
|
|
|
+ wasm_module_t module = wasm_runtime_load(
|
|
|
+ wasm_eh, sizeof(wasm_eh), error_buf, sizeof(error_buf));
|
|
|
+
|
|
|
+ ASSERT_NE(module, nullptr) << "Module load failed: " << error_buf;
|
|
|
+
|
|
|
+ wasm_module_inst_t inst = wasm_runtime_instantiate(
|
|
|
+ module, 8192, 8192, error_buf, sizeof(error_buf));
|
|
|
+ ASSERT_NE(inst, nullptr) << "Instantiation failed: " << error_buf;
|
|
|
+
|
|
|
+ wasm_function_inst_t func =
|
|
|
+ wasm_runtime_lookup_function(inst, "f");
|
|
|
+ ASSERT_NE(func, nullptr) << "Function 'f' should be found";
|
|
|
+
|
|
|
+ wasm_exec_env_t exec_env =
|
|
|
+ wasm_runtime_create_exec_env(inst, 8192);
|
|
|
+ ASSERT_NE(exec_env, nullptr) << "Failed to create exec env";
|
|
|
+
|
|
|
+ bool ok = wasm_runtime_call_wasm(exec_env, func, 0, NULL);
|
|
|
+ ASSERT_TRUE(ok) << "wasm_runtime_call_wasm failed: "
|
|
|
+ << wasm_runtime_get_exception(inst);
|
|
|
+
|
|
|
+ wasm_runtime_destroy_exec_env(exec_env);
|
|
|
+ wasm_runtime_deinstantiate(inst);
|
|
|
+ wasm_runtime_unload(module);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Verify that the RETHROW handler's tag index validation logic matches
|
|
|
+ * the THROW handler. Both must handle IS_INVALID_TAGINDEX the same way:
|
|
|
+ * skip the tags[] access and set cell_num_to_copy = 0.
|
|
|
+ */
|
|
|
+TEST_F(ExceptionHandlingTest, rethrow_handles_invalid_tagindex_like_throw)
|
|
|
+{
|
|
|
+ /* Simulate what both handlers should do with INVALID_TAGINDEX */
|
|
|
+ uint32_t exception_tag_index = INVALID_TAGINDEX;
|
|
|
+ uint32_t tag_count = 5;
|
|
|
+
|
|
|
+ /* THROW handler logic (reference - always correct): */
|
|
|
+ uint32_t throw_cell_num = 0;
|
|
|
+ if (IS_INVALID_TAGINDEX(exception_tag_index)) {
|
|
|
+ throw_cell_num = 0; /* skip tags[] access */
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ /* would access tags[exception_tag_index] */
|
|
|
+ throw_cell_num = 42; /* placeholder */
|
|
|
+ }
|
|
|
+
|
|
|
+ /* RETHROW handler logic (after fix - should match THROW): */
|
|
|
+ uint32_t rethrow_cell_num = 0;
|
|
|
+ if (IS_INVALID_TAGINDEX(exception_tag_index)) {
|
|
|
+ rethrow_cell_num = 0; /* skip tags[] access */
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ /* would access tags[exception_tag_index] */
|
|
|
+ rethrow_cell_num = 42; /* placeholder */
|
|
|
+ }
|
|
|
+
|
|
|
+ EXPECT_EQ(throw_cell_num, rethrow_cell_num)
|
|
|
+ << "RETHROW should handle INVALID_TAGINDEX the same as THROW";
|
|
|
+
|
|
|
+ EXPECT_EQ(throw_cell_num, 0u)
|
|
|
+ << "Both handlers should set cell_num = 0 for INVALID_TAGINDEX";
|
|
|
+
|
|
|
+ /* Without the fix, RETHROW would have tried:
|
|
|
+ * tags[0xFFFFFFFF] => massive OOB read => crash */
|
|
|
+ EXPECT_TRUE(exception_tag_index >= tag_count)
|
|
|
+ << "INVALID_TAGINDEX should be >= any reasonable tag_count";
|
|
|
+}
|