exception_handling_test.cc 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /*
  2. * Copyright (C) 2024 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "gtest/gtest.h"
  6. #include "wasm_runtime_common.h"
  7. #include "bh_platform.h"
  8. /* Pull in the INVALID_TAGINDEX definitions */
  9. #include "wasm_runtime.h"
  10. class ExceptionHandlingTest : public testing::Test
  11. {
  12. protected:
  13. virtual void SetUp()
  14. {
  15. memset(&init_args, 0, sizeof(RuntimeInitArgs));
  16. init_args.mem_alloc_type = Alloc_With_Pool;
  17. init_args.mem_alloc_option.pool.heap_buf = global_heap_buf;
  18. init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf);
  19. ASSERT_EQ(wasm_runtime_full_init(&init_args), true);
  20. }
  21. virtual void TearDown() { wasm_runtime_destroy(); }
  22. public:
  23. char global_heap_buf[512 * 1024];
  24. RuntimeInitArgs init_args;
  25. char error_buf[256];
  26. };
  27. /*
  28. * Test that IS_INVALID_TAGINDEX correctly identifies the invalid tag index
  29. * value (0xFFFFFFFF) used for cross-module exceptions with unknown tags.
  30. *
  31. * The RETHROW handler must check IS_INVALID_TAGINDEX before accessing
  32. * module->module->tags[exception_tag_index]. Without the check,
  33. * exception_tag_index = INVALID_TAGINDEX (0xFFFFFFFF) would cause
  34. * tags[0xFFFFFFFF] -- a massive out-of-bounds read.
  35. *
  36. * The THROW handler at wasm_interp_classic.c properly checks
  37. * IS_INVALID_TAGINDEX, but previously RETHROW did not.
  38. */
  39. TEST_F(ExceptionHandlingTest, invalid_tagindex_detected)
  40. {
  41. uint32_t tag_index = INVALID_TAGINDEX;
  42. EXPECT_TRUE(IS_INVALID_TAGINDEX(tag_index))
  43. << "INVALID_TAGINDEX (0xFFFFFFFF) should be detected";
  44. }
  45. TEST_F(ExceptionHandlingTest, valid_tagindex_not_rejected)
  46. {
  47. uint32_t tag_index = 0;
  48. EXPECT_FALSE(IS_INVALID_TAGINDEX(tag_index))
  49. << "Tag index 0 should not be detected as invalid";
  50. tag_index = 5;
  51. EXPECT_FALSE(IS_INVALID_TAGINDEX(tag_index))
  52. << "Tag index 5 should not be detected as invalid";
  53. }
  54. /*
  55. * Test that a WASM module with exception handling (try/catch/throw)
  56. * can load and instantiate correctly when exception handling is enabled.
  57. */
  58. TEST_F(ExceptionHandlingTest, load_module_with_exception_handling)
  59. {
  60. /*
  61. * Minimal WASM module with exception handling:
  62. * - Tag section (id=13): 1 tag, type 0 (no params)
  63. * - Function with try/catch_all/end that does nothing
  64. */
  65. uint8_t wasm_eh[] = {
  66. 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00,
  67. /* Type section: 1 type, () -> () */
  68. 0x01, 0x04, 0x01, 0x60, 0x00, 0x00,
  69. /* Function section: 1 func, type 0 */
  70. 0x03, 0x02, 0x01, 0x00,
  71. /* Tag section (id=13): 1 tag, attribute=0, type=0 */
  72. 0x0D, 0x03, 0x01, 0x00, 0x00,
  73. /* Export: "f" = func 0 */
  74. 0x07, 0x05, 0x01, 0x01, 0x66, 0x00, 0x00,
  75. /* Code section */
  76. 0x0A, 0x08, 0x01,
  77. 0x06, 0x00, /* body size=6, 0 locals */
  78. 0x06, 0x40, /* try (void) */
  79. 0x19, /* catch_all */
  80. 0x0B, /* end try */
  81. 0x0B, /* end func */
  82. };
  83. memset(error_buf, 0, sizeof(error_buf));
  84. wasm_module_t module = wasm_runtime_load(
  85. wasm_eh, sizeof(wasm_eh), error_buf, sizeof(error_buf));
  86. ASSERT_NE(module, nullptr) << "Module load failed: " << error_buf;
  87. wasm_module_inst_t inst = wasm_runtime_instantiate(
  88. module, 8192, 8192, error_buf, sizeof(error_buf));
  89. ASSERT_NE(inst, nullptr) << "Instantiation failed: " << error_buf;
  90. wasm_function_inst_t func =
  91. wasm_runtime_lookup_function(inst, "f");
  92. ASSERT_NE(func, nullptr) << "Function 'f' should be found";
  93. wasm_exec_env_t exec_env =
  94. wasm_runtime_create_exec_env(inst, 8192);
  95. ASSERT_NE(exec_env, nullptr) << "Failed to create exec env";
  96. bool ok = wasm_runtime_call_wasm(exec_env, func, 0, NULL);
  97. ASSERT_TRUE(ok) << "wasm_runtime_call_wasm failed: "
  98. << wasm_runtime_get_exception(inst);
  99. wasm_runtime_destroy_exec_env(exec_env);
  100. wasm_runtime_deinstantiate(inst);
  101. wasm_runtime_unload(module);
  102. }
  103. /*
  104. * Verify that the RETHROW handler's tag index validation logic matches
  105. * the THROW handler. Both must handle IS_INVALID_TAGINDEX the same way:
  106. * skip the tags[] access and set cell_num_to_copy = 0.
  107. */
  108. TEST_F(ExceptionHandlingTest, rethrow_handles_invalid_tagindex_like_throw)
  109. {
  110. /* Simulate what both handlers should do with INVALID_TAGINDEX */
  111. uint32_t exception_tag_index = INVALID_TAGINDEX;
  112. uint32_t tag_count = 5;
  113. /* THROW handler logic (reference - always correct): */
  114. uint32_t throw_cell_num = 0;
  115. if (IS_INVALID_TAGINDEX(exception_tag_index)) {
  116. throw_cell_num = 0; /* skip tags[] access */
  117. }
  118. else {
  119. /* would access tags[exception_tag_index] */
  120. throw_cell_num = 42; /* placeholder */
  121. }
  122. /* RETHROW handler logic (after fix - should match THROW): */
  123. uint32_t rethrow_cell_num = 0;
  124. if (IS_INVALID_TAGINDEX(exception_tag_index)) {
  125. rethrow_cell_num = 0; /* skip tags[] access */
  126. }
  127. else {
  128. /* would access tags[exception_tag_index] */
  129. rethrow_cell_num = 42; /* placeholder */
  130. }
  131. EXPECT_EQ(throw_cell_num, rethrow_cell_num)
  132. << "RETHROW should handle INVALID_TAGINDEX the same as THROW";
  133. EXPECT_EQ(throw_cell_num, 0u)
  134. << "Both handlers should set cell_num = 0 for INVALID_TAGINDEX";
  135. /* Without the fix, RETHROW would have tried:
  136. * tags[0xFFFFFFFF] => massive OOB read => crash */
  137. EXPECT_TRUE(exception_tag_index >= tag_count)
  138. << "INVALID_TAGINDEX should be >= any reasonable tag_count";
  139. }