interpreter_test_enhance.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. /*
  2. * Copyright (C) 2024 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "test_helper.h"
  6. #include "gtest/gtest.h"
  7. #include <unistd.h>
  8. #include <fstream>
  9. #include "wasm_runtime_common.h"
  10. #include "wasm_runtime.h"
  11. #include "wasm_interp.h"
  12. #include "wasm_loader.h"
  13. static std::string CWD;
  14. static std::string WASM_FILE;
  15. static constexpr uint32_t STACK_SIZE = 8092;
  16. static constexpr uint32_t HEAP_SIZE = 8092;
  17. static int
  18. test_import_add_impl(wasm_exec_env_t exec_env, int32_t a, int32_t b)
  19. {
  20. return a + b;
  21. }
  22. static int
  23. test_import_mul_impl(wasm_exec_env_t exec_env, int32_t a, int32_t b)
  24. {
  25. return a * b;
  26. }
  27. static int
  28. malloc_impl(wasm_exec_env_t exec_env, int32_t size)
  29. {
  30. return wasm_runtime_module_malloc(
  31. wasm_runtime_get_module_inst(exec_env), size, NULL);
  32. }
  33. static void
  34. free_impl(wasm_exec_env_t exec_env, int32_t ptr)
  35. {
  36. wasm_runtime_module_free(
  37. wasm_runtime_get_module_inst(exec_env), ptr);
  38. }
  39. static int
  40. native_func_impl(wasm_exec_env_t exec_env, int32_t a)
  41. {
  42. return a * 2;
  43. }
  44. static NativeSymbol native_symbols[] = {
  45. { "test_import_add", (void*)test_import_add_impl, "(ii)i", NULL },
  46. { "test_import_mul", (void*)test_import_mul_impl, "(ii)i", NULL },
  47. { "malloc", (void*)malloc_impl, "(i)i", NULL },
  48. { "free", (void*)free_impl, "(i)", NULL },
  49. { "native_func", (void*)native_func_impl, "(i)i", NULL }
  50. };
  51. /**
  52. * Test fixture for Step 3: Function Invocation and Stack Operations
  53. * Targets 6 functions: call_indirect, wasm_call_indirect, wasm_interp_call_func_import,
  54. * copy_stack_values, execute_malloc_function, execute_free_function
  55. */
  56. class FunctionInvocationTest : public testing::Test
  57. {
  58. protected:
  59. void SetUp() override
  60. {
  61. char *current_dir = getcwd(NULL, 0);
  62. CWD = std::string(current_dir);
  63. free(current_dir);
  64. WASM_FILE = CWD + "/function_invocation_test.wasm";
  65. memset(&init_args, 0, sizeof(RuntimeInitArgs));
  66. init_args.mem_alloc_type = Alloc_With_System_Allocator;
  67. ASSERT_TRUE(wasm_runtime_full_init(&init_args));
  68. // Register native symbols for import testing
  69. ASSERT_TRUE(wasm_runtime_register_natives("env", native_symbols,
  70. sizeof(native_symbols) / sizeof(NativeSymbol)));
  71. load_wasm_file();
  72. instantiate_module();
  73. }
  74. void TearDown() override
  75. {
  76. if (exec_env) {
  77. wasm_runtime_destroy_exec_env(exec_env);
  78. }
  79. if (module_inst) {
  80. wasm_runtime_deinstantiate(module_inst);
  81. }
  82. if (module) {
  83. wasm_runtime_unload(module);
  84. }
  85. if (wasm_file_buf) {
  86. delete[] wasm_file_buf;
  87. }
  88. wasm_runtime_destroy();
  89. }
  90. void load_wasm_file()
  91. {
  92. std::ifstream wasm_file(WASM_FILE, std::ios::binary);
  93. ASSERT_TRUE(wasm_file.is_open()) << "Failed to open WASM file: " << WASM_FILE;
  94. std::vector<uint8_t> buffer(std::istreambuf_iterator<char>(wasm_file), {});
  95. wasm_file_size = buffer.size();
  96. wasm_file_buf = new unsigned char[wasm_file_size];
  97. std::copy(buffer.begin(), buffer.end(), wasm_file_buf);
  98. module = wasm_runtime_load(wasm_file_buf, wasm_file_size, error_buf,
  99. sizeof(error_buf));
  100. ASSERT_NE(module, nullptr) << "Load module failed: " << error_buf;
  101. }
  102. void instantiate_module()
  103. {
  104. module_inst = wasm_runtime_instantiate(
  105. module, STACK_SIZE, HEAP_SIZE, error_buf, sizeof(error_buf));
  106. ASSERT_NE(module_inst, nullptr) << "Instantiate module failed: " << error_buf;
  107. exec_env = wasm_runtime_create_exec_env(module_inst, STACK_SIZE);
  108. ASSERT_NE(exec_env, nullptr);
  109. }
  110. RuntimeInitArgs init_args;
  111. wasm_module_t module = nullptr;
  112. wasm_module_inst_t module_inst = nullptr;
  113. wasm_exec_env_t exec_env = nullptr;
  114. unsigned char *wasm_file_buf = nullptr;
  115. uint32_t wasm_file_size = 0;
  116. char error_buf[128] = { 0 };
  117. };
  118. /**
  119. * Test Function 1: call_indirect() - Valid function call
  120. * Target: core/iwasm/interpreter/wasm_runtime.c:call_indirect()
  121. * Expected Coverage: ~15 lines (success path)
  122. */
  123. TEST_F(FunctionInvocationTest, CallIndirect_ValidFunction_ReturnsCorrectResult)
  124. {
  125. wasm_function_inst_t func = wasm_runtime_lookup_function(
  126. module_inst, "test_call_indirect_valid");
  127. ASSERT_NE(func, nullptr);
  128. uint32_t wasm_argv[2];
  129. wasm_argv[0] = 0; // table index 0 (points to $add_func)
  130. wasm_argv[1] = 15; // parameter value
  131. bool success = wasm_runtime_call_wasm(exec_env, func, 2, wasm_argv);
  132. ASSERT_TRUE(success);
  133. // $add_func adds 10 to input: 15 + 10 = 25
  134. ASSERT_EQ(wasm_argv[0], 25);
  135. }
  136. /**
  137. * Test Function 1: call_indirect() - Invalid index
  138. * Target: core/iwasm/interpreter/wasm_runtime.c:call_indirect()
  139. * Expected Coverage: ~15 lines (error path)
  140. */
  141. TEST_F(FunctionInvocationTest, CallIndirect_InvalidIndex_FailsGracefully)
  142. {
  143. wasm_function_inst_t func = wasm_runtime_lookup_function(
  144. module_inst, "test_call_indirect_invalid_index");
  145. ASSERT_NE(func, nullptr);
  146. uint32_t wasm_argv[1];
  147. wasm_argv[0] = 42; // input value
  148. bool success = wasm_runtime_call_wasm(exec_env, func, 1, wasm_argv);
  149. ASSERT_FALSE(success);
  150. ASSERT_TRUE(wasm_runtime_get_exception(module_inst) != NULL);
  151. }
  152. /**
  153. * Test Function 2: wasm_call_indirect() - Type mismatch error handling
  154. * Target: core/iwasm/interpreter/wasm_runtime.c:wasm_call_indirect()
  155. * Expected Coverage: ~13 lines (error path)
  156. */
  157. TEST_F(FunctionInvocationTest, WasmCallIndirect_TypeMismatch_ReturnsFailure)
  158. {
  159. wasm_function_inst_t func = wasm_runtime_lookup_function(
  160. module_inst, "test_call_indirect_type_mismatch");
  161. ASSERT_NE(func, nullptr);
  162. uint32_t wasm_argv[1];
  163. wasm_argv[0] = 100; // input value
  164. bool success = wasm_runtime_call_wasm(exec_env, func, 1, wasm_argv);
  165. ASSERT_FALSE(success);
  166. ASSERT_TRUE(wasm_runtime_get_exception(module_inst) != NULL);
  167. }
  168. /**
  169. * Test Function 3: wasm_interp_call_func_import() - Success path
  170. * Target: core/iwasm/interpreter/wasm_interp_fast.c:wasm_interp_call_func_import()
  171. * Expected Coverage: ~12 lines (success path)
  172. */
  173. TEST_F(FunctionInvocationTest, CallFuncImport_Success_CallsNativeFunction)
  174. {
  175. wasm_function_inst_t func = wasm_runtime_lookup_function(
  176. module_inst, "test_import_function_call");
  177. ASSERT_NE(func, nullptr);
  178. uint32_t wasm_argv[2];
  179. wasm_argv[0] = 15; // first parameter
  180. wasm_argv[1] = 25; // second parameter
  181. bool success = wasm_runtime_call_wasm(exec_env, func, 2, wasm_argv);
  182. ASSERT_TRUE(success);
  183. // test_import_add_impl adds two values: 15 + 25 = 40
  184. ASSERT_EQ(wasm_argv[0], 40);
  185. }
  186. /**
  187. * Test Function 3: wasm_interp_call_func_import() - Multiple import calls
  188. * Target: core/iwasm/interpreter/wasm_interp_fast.c:wasm_interp_call_func_import()
  189. * Expected Coverage: ~13 lines (additional path)
  190. */
  191. TEST_F(FunctionInvocationTest, CallFuncImport_MultipleImports_HandlesCorrectly)
  192. {
  193. wasm_function_inst_t func = wasm_runtime_lookup_function(
  194. module_inst, "test_import_function_mul");
  195. ASSERT_NE(func, nullptr);
  196. uint32_t wasm_argv[2];
  197. wasm_argv[0] = 6; // first parameter
  198. wasm_argv[1] = 7; // second parameter
  199. bool success = wasm_runtime_call_wasm(exec_env, func, 2, wasm_argv);
  200. ASSERT_TRUE(success);
  201. // test_import_mul_impl multiplies two values: 6 * 7 = 42
  202. ASSERT_EQ(wasm_argv[0], 42);
  203. }
  204. /**
  205. * Test Function 4: copy_stack_values() - Normal operation
  206. * Target: core/iwasm/interpreter/wasm_interp_fast.c:copy_stack_values()
  207. * Expected Coverage: ~20 lines (normal operation)
  208. */
  209. TEST_F(FunctionInvocationTest, CopyStackValues_Normal_CopiesValuesCorrectly)
  210. {
  211. wasm_function_inst_t func = wasm_runtime_lookup_function(
  212. module_inst, "test_stack_operations");
  213. ASSERT_NE(func, nullptr);
  214. uint32_t wasm_argv[2];
  215. wasm_argv[0] = 10; // val1
  216. wasm_argv[1] = 20; // val2
  217. bool success = wasm_runtime_call_wasm(exec_env, func, 2, wasm_argv);
  218. ASSERT_TRUE(success);
  219. // Complex calculation: (10+20) + (5+10) + (20*3) = 30 + 15 + 60 = 105
  220. ASSERT_EQ(wasm_argv[0], 105);
  221. }
  222. /**
  223. * Test Function 4: copy_stack_values() - Large parameter count
  224. * Target: core/iwasm/interpreter/wasm_interp_fast.c:copy_stack_values()
  225. * Expected Coverage: Additional lines for large stack operations
  226. */
  227. TEST_F(FunctionInvocationTest, CopyStackValues_LargeParams_HandlesCorrectly)
  228. {
  229. wasm_function_inst_t func = wasm_runtime_lookup_function(
  230. module_inst, "test_large_param_stack");
  231. ASSERT_NE(func, nullptr);
  232. uint32_t wasm_argv[8];
  233. wasm_argv[0] = 1;
  234. wasm_argv[1] = 2;
  235. wasm_argv[2] = 3;
  236. wasm_argv[3] = 4;
  237. wasm_argv[4] = 5;
  238. wasm_argv[5] = 6;
  239. wasm_argv[6] = 7;
  240. wasm_argv[7] = 8;
  241. bool success = wasm_runtime_call_wasm(exec_env, func, 8, wasm_argv);
  242. ASSERT_TRUE(success);
  243. // (1+2) + (3+4) + (5+6) + (7+8) = 3 + 7 + 11 + 15 = 36
  244. ASSERT_EQ(wasm_argv[0], 36);
  245. }
  246. /**
  247. * Test Function 5: execute_malloc_function() - Success path
  248. * Target: core/iwasm/interpreter/wasm_runtime.c:execute_malloc_function()
  249. * Expected Coverage: ~20 lines (success path)
  250. */
  251. TEST_F(FunctionInvocationTest, ExecuteMalloc_Success_AllocatesMemory)
  252. {
  253. wasm_function_inst_t func = wasm_runtime_lookup_function(
  254. module_inst, "test_malloc_operation");
  255. ASSERT_NE(func, nullptr);
  256. uint32_t wasm_argv[1];
  257. wasm_argv[0] = 1024; // allocate 1KB
  258. bool success = wasm_runtime_call_wasm(exec_env, func, 1, wasm_argv);
  259. ASSERT_TRUE(success);
  260. // Should return a valid memory offset (> 0)
  261. ASSERT_GT(wasm_argv[0], 0);
  262. }
  263. /**
  264. * Test Function 5: execute_malloc_function() - Failure path
  265. * Target: core/iwasm/interpreter/wasm_runtime.c:execute_malloc_function()
  266. * Expected Coverage: ~20 lines (failure path)
  267. */
  268. TEST_F(FunctionInvocationTest, ExecuteMalloc_Failure_HandlesLargeAllocation)
  269. {
  270. wasm_function_inst_t func = wasm_runtime_lookup_function(
  271. module_inst, "test_malloc_operation");
  272. ASSERT_NE(func, nullptr);
  273. uint32_t wasm_argv[1];
  274. wasm_argv[0] = 0x10000000; // try to allocate large amount (256MB)
  275. bool success = wasm_runtime_call_wasm(exec_env, func, 1, wasm_argv);
  276. // The call should succeed (no crash), but malloc should return 0
  277. ASSERT_TRUE(success);
  278. ASSERT_EQ(wasm_argv[0], 0);
  279. }
  280. /**
  281. * Test Function 6: execute_free_function() - Success path
  282. * Target: core/iwasm/interpreter/wasm_runtime.c:execute_free_function()
  283. * Expected Coverage: ~20 lines (success path)
  284. */
  285. TEST_F(FunctionInvocationTest, ExecuteFree_Success_FreesMemory)
  286. {
  287. // First allocate memory
  288. wasm_function_inst_t malloc_func = wasm_runtime_lookup_function(
  289. module_inst, "test_malloc_operation");
  290. ASSERT_NE(malloc_func, nullptr);
  291. uint32_t malloc_argv[1];
  292. malloc_argv[0] = 512;
  293. bool success = wasm_runtime_call_wasm(exec_env, malloc_func, 1, malloc_argv);
  294. ASSERT_TRUE(success);
  295. ASSERT_GT(malloc_argv[0], 0);
  296. // Now free the allocated memory
  297. wasm_function_inst_t free_func = wasm_runtime_lookup_function(
  298. module_inst, "test_free_operation");
  299. ASSERT_NE(free_func, nullptr);
  300. uint32_t free_argv[1];
  301. free_argv[0] = malloc_argv[0]; // use allocated pointer
  302. success = wasm_runtime_call_wasm(exec_env, free_func, 1, free_argv);
  303. ASSERT_TRUE(success);
  304. }
  305. /**
  306. * Test Function 6: execute_free_function() - Error handling
  307. * Target: core/iwasm/interpreter/wasm_runtime.c:execute_free_function()
  308. * Expected Coverage: ~20 lines (error path)
  309. */
  310. TEST_F(FunctionInvocationTest, ExecuteFree_ErrorHandling_HandlesInvalidPointer)
  311. {
  312. wasm_function_inst_t func = wasm_runtime_lookup_function(
  313. module_inst, "test_free_operation");
  314. ASSERT_NE(func, nullptr);
  315. uint32_t wasm_argv[1];
  316. wasm_argv[0] = 0; // try to free NULL pointer
  317. bool success = wasm_runtime_call_wasm(exec_env, func, 1, wasm_argv);
  318. ASSERT_TRUE(success); // free(NULL) is valid and should succeed
  319. }
  320. /**
  321. * Test malloc/free cycle to exercise both functions together
  322. */
  323. TEST_F(FunctionInvocationTest, MallocFreeCycle_Complete_WorksCorrectly)
  324. {
  325. wasm_function_inst_t func = wasm_runtime_lookup_function(
  326. module_inst, "test_malloc_free_cycle");
  327. ASSERT_NE(func, nullptr);
  328. uint32_t wasm_argv[1];
  329. wasm_argv[0] = 256; // allocation size
  330. bool success = wasm_runtime_call_wasm(exec_env, func, 1, wasm_argv);
  331. ASSERT_TRUE(success);
  332. // Should return the value that was stored (42)
  333. ASSERT_EQ(wasm_argv[0], 42);
  334. }
  335. /**
  336. * Test complex indirect call scenarios
  337. */
  338. TEST_F(FunctionInvocationTest, ComplexIndirectCalls_MultipleSelectors_HandlesCorrectly)
  339. {
  340. wasm_function_inst_t func = wasm_runtime_lookup_function(
  341. module_inst, "test_complex_indirect_calls");
  342. ASSERT_NE(func, nullptr);
  343. // Test selector 0 (add_func)
  344. uint32_t wasm_argv[2];
  345. wasm_argv[0] = 0; // selector
  346. wasm_argv[1] = 30; // value
  347. bool success = wasm_runtime_call_wasm(exec_env, func, 2, wasm_argv);
  348. ASSERT_TRUE(success);
  349. ASSERT_EQ(wasm_argv[0], 40); // 30 + 10 = 40
  350. // Test selector 1 (mul_func)
  351. wasm_argv[0] = 1; // selector
  352. wasm_argv[1] = 15; // value
  353. success = wasm_runtime_call_wasm(exec_env, func, 2, wasm_argv);
  354. ASSERT_TRUE(success);
  355. ASSERT_EQ(wasm_argv[0], 30); // 15 * 2 = 30
  356. // Test selector 2 (identity_func)
  357. wasm_argv[0] = 2; // selector
  358. wasm_argv[1] = 99; // value
  359. success = wasm_runtime_call_wasm(exec_env, func, 2, wasm_argv);
  360. ASSERT_TRUE(success);
  361. ASSERT_EQ(wasm_argv[0], 99); // identity returns same value
  362. }
  363. /**
  364. * Additional test for function invocation edge cases
  365. */
  366. TEST_F(FunctionInvocationTest, FunctionInvocation_EdgeCases_HandlesCorrectly)
  367. {
  368. // Test with maximum parameter values
  369. wasm_function_inst_t func = wasm_runtime_lookup_function(
  370. module_inst, "test_stack_operations");
  371. ASSERT_NE(func, nullptr);
  372. uint32_t wasm_argv[2];
  373. wasm_argv[0] = 0xFFFFFFFF; // max uint32
  374. wasm_argv[1] = 1;
  375. bool success = wasm_runtime_call_wasm(exec_env, func, 2, wasm_argv);
  376. ASSERT_TRUE(success);
  377. }