wasm_memory.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "wasm_runtime_common.h"
  6. #include "../interpreter/wasm_runtime.h"
  7. #include "bh_platform.h"
  8. #include "mem_alloc.h"
  9. typedef enum Memory_Mode {
  10. MEMORY_MODE_UNKNOWN = 0,
  11. MEMORY_MODE_POOL,
  12. MEMORY_MODE_ALLOCATOR
  13. } Memory_Mode;
  14. static Memory_Mode memory_mode = MEMORY_MODE_UNKNOWN;
  15. static mem_allocator_t pool_allocator = NULL;
  16. static void *(*malloc_func)(unsigned int size) = NULL;
  17. static void *(*realloc_func)(void *ptr, unsigned int size) = NULL;
  18. static void (*free_func)(void *ptr) = NULL;
  19. static unsigned int global_pool_size;
  20. static bool
  21. wasm_memory_init_with_pool(void *mem, unsigned int bytes)
  22. {
  23. mem_allocator_t _allocator = mem_allocator_create(mem, bytes);
  24. if (_allocator) {
  25. memory_mode = MEMORY_MODE_POOL;
  26. pool_allocator = _allocator;
  27. global_pool_size = bytes;
  28. return true;
  29. }
  30. LOG_ERROR("Init memory with pool (%p, %u) failed.\n", mem, bytes);
  31. return false;
  32. }
  33. static bool
  34. wasm_memory_init_with_allocator(void *_malloc_func, void *_realloc_func,
  35. void *_free_func)
  36. {
  37. if (_malloc_func && _free_func && _malloc_func != _free_func) {
  38. memory_mode = MEMORY_MODE_ALLOCATOR;
  39. malloc_func = _malloc_func;
  40. realloc_func = _realloc_func;
  41. free_func = _free_func;
  42. return true;
  43. }
  44. LOG_ERROR("Init memory with allocator (%p, %p, %p) failed.\n", _malloc_func,
  45. _realloc_func, _free_func);
  46. return false;
  47. }
  48. bool
  49. wasm_runtime_memory_init(mem_alloc_type_t mem_alloc_type,
  50. const MemAllocOption *alloc_option)
  51. {
  52. if (mem_alloc_type == Alloc_With_Pool)
  53. return wasm_memory_init_with_pool(alloc_option->pool.heap_buf,
  54. alloc_option->pool.heap_size);
  55. else if (mem_alloc_type == Alloc_With_Allocator)
  56. return wasm_memory_init_with_allocator(
  57. alloc_option->allocator.malloc_func,
  58. alloc_option->allocator.realloc_func,
  59. alloc_option->allocator.free_func);
  60. else if (mem_alloc_type == Alloc_With_System_Allocator)
  61. return wasm_memory_init_with_allocator(os_malloc, os_realloc, os_free);
  62. else
  63. return false;
  64. }
  65. void
  66. wasm_runtime_memory_destroy()
  67. {
  68. if (memory_mode == MEMORY_MODE_POOL) {
  69. #if BH_ENABLE_GC_VERIFY == 0
  70. (void)mem_allocator_destroy(pool_allocator);
  71. #else
  72. int ret = mem_allocator_destroy(pool_allocator);
  73. if (ret != 0) {
  74. /* Memory leak detected */
  75. exit(-1);
  76. }
  77. #endif
  78. }
  79. memory_mode = MEMORY_MODE_UNKNOWN;
  80. }
  81. unsigned
  82. wasm_runtime_memory_pool_size()
  83. {
  84. if (memory_mode == MEMORY_MODE_POOL)
  85. return global_pool_size;
  86. else
  87. return UINT32_MAX;
  88. }
  89. static inline void *
  90. wasm_runtime_malloc_internal(unsigned int size)
  91. {
  92. if (memory_mode == MEMORY_MODE_UNKNOWN) {
  93. LOG_WARNING(
  94. "wasm_runtime_malloc failed: memory hasn't been initialize.\n");
  95. return NULL;
  96. }
  97. else if (memory_mode == MEMORY_MODE_POOL) {
  98. return mem_allocator_malloc(pool_allocator, size);
  99. }
  100. else {
  101. return malloc_func(size);
  102. }
  103. }
  104. static inline void *
  105. wasm_runtime_realloc_internal(void *ptr, unsigned int size)
  106. {
  107. if (memory_mode == MEMORY_MODE_UNKNOWN) {
  108. LOG_WARNING(
  109. "wasm_runtime_realloc failed: memory hasn't been initialize.\n");
  110. return NULL;
  111. }
  112. else if (memory_mode == MEMORY_MODE_POOL) {
  113. return mem_allocator_realloc(pool_allocator, ptr, size);
  114. }
  115. else {
  116. if (realloc_func)
  117. return realloc_func(ptr, size);
  118. else
  119. return NULL;
  120. }
  121. }
  122. static inline void
  123. wasm_runtime_free_internal(void *ptr)
  124. {
  125. if (!ptr) {
  126. LOG_WARNING("warning: wasm_runtime_free with NULL pointer\n");
  127. #if BH_ENABLE_GC_VERIFY != 0
  128. exit(-1);
  129. #endif
  130. return;
  131. }
  132. if (memory_mode == MEMORY_MODE_UNKNOWN) {
  133. LOG_WARNING("warning: wasm_runtime_free failed: "
  134. "memory hasn't been initialize.\n");
  135. }
  136. else if (memory_mode == MEMORY_MODE_POOL) {
  137. mem_allocator_free(pool_allocator, ptr);
  138. }
  139. else {
  140. free_func(ptr);
  141. }
  142. }
  143. void *
  144. wasm_runtime_malloc(unsigned int size)
  145. {
  146. if (size == 0) {
  147. LOG_WARNING("warning: wasm_runtime_malloc with size zero\n");
  148. /* At lease alloc 1 byte to avoid malloc failed */
  149. size = 1;
  150. #if BH_ENABLE_GC_VERIFY != 0
  151. exit(-1);
  152. #endif
  153. }
  154. return wasm_runtime_malloc_internal(size);
  155. }
  156. void *
  157. wasm_runtime_realloc(void *ptr, unsigned int size)
  158. {
  159. return wasm_runtime_realloc_internal(ptr, size);
  160. }
  161. void
  162. wasm_runtime_free(void *ptr)
  163. {
  164. wasm_runtime_free_internal(ptr);
  165. }
  166. bool
  167. wasm_runtime_get_mem_alloc_info(mem_alloc_info_t *mem_alloc_info)
  168. {
  169. if (memory_mode == MEMORY_MODE_POOL) {
  170. return mem_allocator_get_alloc_info(pool_allocator, mem_alloc_info);
  171. }
  172. return false;
  173. }
  174. bool
  175. wasm_runtime_validate_app_addr(WASMModuleInstanceCommon *module_inst_comm,
  176. uint32 app_offset, uint32 size)
  177. {
  178. WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
  179. WASMMemoryInstance *memory_inst;
  180. bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
  181. || module_inst_comm->module_type == Wasm_Module_AoT);
  182. memory_inst = wasm_get_default_memory(module_inst);
  183. if (!memory_inst) {
  184. goto fail;
  185. }
  186. /* integer overflow check */
  187. if (app_offset > UINT32_MAX - size) {
  188. goto fail;
  189. }
  190. if (app_offset + size <= memory_inst->memory_data_size) {
  191. return true;
  192. }
  193. fail:
  194. wasm_set_exception(module_inst, "out of bounds memory access");
  195. return false;
  196. }
  197. bool
  198. wasm_runtime_validate_app_str_addr(WASMModuleInstanceCommon *module_inst_comm,
  199. uint32 app_str_offset)
  200. {
  201. WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
  202. uint32 app_end_offset;
  203. char *str, *str_end;
  204. bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
  205. || module_inst_comm->module_type == Wasm_Module_AoT);
  206. if (!wasm_runtime_get_app_addr_range(module_inst_comm, app_str_offset, NULL,
  207. &app_end_offset))
  208. goto fail;
  209. str = wasm_runtime_addr_app_to_native(module_inst_comm, app_str_offset);
  210. str_end = str + (app_end_offset - app_str_offset);
  211. while (str < str_end && *str != '\0')
  212. str++;
  213. if (str == str_end)
  214. goto fail;
  215. return true;
  216. fail:
  217. wasm_set_exception(module_inst, "out of bounds memory access");
  218. return false;
  219. }
  220. bool
  221. wasm_runtime_validate_native_addr(WASMModuleInstanceCommon *module_inst_comm,
  222. void *native_ptr, uint32 size)
  223. {
  224. WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
  225. WASMMemoryInstance *memory_inst;
  226. uint8 *addr = (uint8 *)native_ptr;
  227. bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
  228. || module_inst_comm->module_type == Wasm_Module_AoT);
  229. memory_inst = wasm_get_default_memory(module_inst);
  230. if (!memory_inst) {
  231. goto fail;
  232. }
  233. /* integer overflow check */
  234. if ((uintptr_t)addr > UINTPTR_MAX - size) {
  235. goto fail;
  236. }
  237. if (memory_inst->memory_data <= addr
  238. && addr + size <= memory_inst->memory_data_end) {
  239. return true;
  240. }
  241. fail:
  242. wasm_set_exception(module_inst, "out of bounds memory access");
  243. return false;
  244. }
  245. void *
  246. wasm_runtime_addr_app_to_native(WASMModuleInstanceCommon *module_inst_comm,
  247. uint32 app_offset)
  248. {
  249. WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
  250. WASMMemoryInstance *memory_inst;
  251. uint8 *addr;
  252. bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
  253. || module_inst_comm->module_type == Wasm_Module_AoT);
  254. memory_inst = wasm_get_default_memory(module_inst);
  255. if (!memory_inst) {
  256. return NULL;
  257. }
  258. addr = memory_inst->memory_data + app_offset;
  259. if (memory_inst->memory_data <= addr && addr < memory_inst->memory_data_end)
  260. return addr;
  261. return NULL;
  262. }
  263. uint32
  264. wasm_runtime_addr_native_to_app(WASMModuleInstanceCommon *module_inst_comm,
  265. void *native_ptr)
  266. {
  267. WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
  268. WASMMemoryInstance *memory_inst;
  269. uint8 *addr = (uint8 *)native_ptr;
  270. bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
  271. || module_inst_comm->module_type == Wasm_Module_AoT);
  272. memory_inst = wasm_get_default_memory(module_inst);
  273. if (!memory_inst) {
  274. return 0;
  275. }
  276. if (memory_inst->memory_data <= addr && addr < memory_inst->memory_data_end)
  277. return (uint32)(addr - memory_inst->memory_data);
  278. return 0;
  279. }
  280. bool
  281. wasm_runtime_get_app_addr_range(WASMModuleInstanceCommon *module_inst_comm,
  282. uint32 app_offset, uint32 *p_app_start_offset,
  283. uint32 *p_app_end_offset)
  284. {
  285. WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
  286. WASMMemoryInstance *memory_inst;
  287. uint32 memory_data_size;
  288. bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
  289. || module_inst_comm->module_type == Wasm_Module_AoT);
  290. memory_inst = wasm_get_default_memory(module_inst);
  291. if (!memory_inst) {
  292. return false;
  293. }
  294. memory_data_size = memory_inst->memory_data_size;
  295. if (app_offset < memory_data_size) {
  296. if (p_app_start_offset)
  297. *p_app_start_offset = 0;
  298. if (p_app_end_offset)
  299. *p_app_end_offset = memory_data_size;
  300. return true;
  301. }
  302. return false;
  303. }
  304. bool
  305. wasm_runtime_get_native_addr_range(WASMModuleInstanceCommon *module_inst_comm,
  306. uint8 *native_ptr,
  307. uint8 **p_native_start_addr,
  308. uint8 **p_native_end_addr)
  309. {
  310. WASMModuleInstance *module_inst = (WASMModuleInstance *)module_inst_comm;
  311. WASMMemoryInstance *memory_inst;
  312. uint8 *addr = (uint8 *)native_ptr;
  313. bh_assert(module_inst_comm->module_type == Wasm_Module_Bytecode
  314. || module_inst_comm->module_type == Wasm_Module_AoT);
  315. memory_inst = wasm_get_default_memory(module_inst);
  316. if (!memory_inst) {
  317. return false;
  318. }
  319. if (memory_inst->memory_data <= addr
  320. && addr < memory_inst->memory_data_end) {
  321. if (p_native_start_addr)
  322. *p_native_start_addr = memory_inst->memory_data;
  323. if (p_native_end_addr)
  324. *p_native_end_addr = memory_inst->memory_data_end;
  325. return true;
  326. }
  327. return false;
  328. }
  329. bool
  330. wasm_check_app_addr_and_convert(WASMModuleInstance *module_inst, bool is_str,
  331. uint32 app_buf_addr, uint32 app_buf_size,
  332. void **p_native_addr)
  333. {
  334. WASMMemoryInstance *memory_inst = wasm_get_default_memory(module_inst);
  335. uint8 *native_addr;
  336. if (!memory_inst) {
  337. goto fail;
  338. }
  339. native_addr = memory_inst->memory_data + app_buf_addr;
  340. /* No need to check the app_offset and buf_size if memory access
  341. boundary check with hardware trap is enabled */
  342. #ifndef OS_ENABLE_HW_BOUND_CHECK
  343. if (app_buf_addr >= memory_inst->memory_data_size) {
  344. goto fail;
  345. }
  346. if (!is_str) {
  347. if (app_buf_size > memory_inst->memory_data_size - app_buf_addr) {
  348. goto fail;
  349. }
  350. }
  351. else {
  352. const char *str, *str_end;
  353. /* The whole string must be in the linear memory */
  354. str = (const char *)native_addr;
  355. str_end = (const char *)memory_inst->memory_data_end;
  356. while (str < str_end && *str != '\0')
  357. str++;
  358. if (str == str_end)
  359. goto fail;
  360. }
  361. #endif
  362. *p_native_addr = (void *)native_addr;
  363. return true;
  364. fail:
  365. wasm_set_exception(module_inst, "out of bounds memory access");
  366. return false;
  367. }
  368. WASMMemoryInstance *
  369. wasm_get_default_memory(WASMModuleInstance *module_inst)
  370. {
  371. if (module_inst->memories)
  372. return module_inst->memories[0];
  373. else
  374. return NULL;
  375. }
  376. #ifndef OS_ENABLE_HW_BOUND_CHECK
  377. bool
  378. wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
  379. {
  380. WASMMemoryInstance *memory = wasm_get_default_memory(module);
  381. uint8 *memory_data_old, *memory_data_new, *heap_data_old;
  382. uint32 num_bytes_per_page, heap_size, total_size_old;
  383. uint32 cur_page_count, max_page_count, total_page_count;
  384. uint64 total_size_new;
  385. bool ret = true;
  386. if (!memory)
  387. return false;
  388. heap_data_old = memory->heap_data;
  389. heap_size = (uint32)(memory->heap_data_end - memory->heap_data);
  390. memory_data_old = memory->memory_data;
  391. total_size_old = memory->memory_data_size;
  392. num_bytes_per_page = memory->num_bytes_per_page;
  393. cur_page_count = memory->cur_page_count;
  394. max_page_count = memory->max_page_count;
  395. total_page_count = inc_page_count + cur_page_count;
  396. total_size_new = num_bytes_per_page * (uint64)total_page_count;
  397. if (inc_page_count <= 0)
  398. /* No need to enlarge memory */
  399. return true;
  400. if (total_page_count < cur_page_count /* integer overflow */
  401. || total_page_count > max_page_count) {
  402. return false;
  403. }
  404. bh_assert(total_size_new <= 4 * (uint64)BH_GB);
  405. if (total_size_new > UINT32_MAX) {
  406. /* Resize to 1 page with size 4G-1 */
  407. num_bytes_per_page = UINT32_MAX;
  408. total_page_count = max_page_count = 1;
  409. total_size_new = UINT32_MAX;
  410. }
  411. #if WASM_ENABLE_SHARED_MEMORY != 0
  412. if (memory->is_shared) {
  413. memory->num_bytes_per_page = num_bytes_per_page;
  414. memory->cur_page_count = total_page_count;
  415. memory->max_page_count = max_page_count;
  416. /* No need to update memory->memory_data_size as it is
  417. initialized with the maximum memory data size for
  418. shared memory */
  419. return true;
  420. }
  421. #endif
  422. if (heap_size > 0) {
  423. if (mem_allocator_is_heap_corrupted(memory->heap_handle)) {
  424. wasm_runtime_show_app_heap_corrupted_prompt();
  425. return false;
  426. }
  427. }
  428. if (!(memory_data_new =
  429. wasm_runtime_realloc(memory_data_old, (uint32)total_size_new))) {
  430. if (!(memory_data_new = wasm_runtime_malloc((uint32)total_size_new))) {
  431. return false;
  432. }
  433. if (memory_data_old) {
  434. bh_memcpy_s(memory_data_new, (uint32)total_size_new,
  435. memory_data_old, total_size_old);
  436. wasm_runtime_free(memory_data_old);
  437. }
  438. }
  439. memset(memory_data_new + total_size_old, 0,
  440. (uint32)total_size_new - total_size_old);
  441. if (heap_size > 0) {
  442. if (mem_allocator_migrate(memory->heap_handle,
  443. (char *)heap_data_old
  444. + (memory_data_new - memory_data_old),
  445. heap_size)
  446. != 0) {
  447. /* Don't return here as memory->memory_data is obsolete and
  448. must be updated to be correctly used later. */
  449. ret = false;
  450. }
  451. }
  452. memory->heap_data = memory_data_new + (heap_data_old - memory_data_old);
  453. memory->heap_data_end = memory->heap_data + heap_size;
  454. memory->num_bytes_per_page = num_bytes_per_page;
  455. memory->cur_page_count = total_page_count;
  456. memory->max_page_count = max_page_count;
  457. memory->memory_data_size = (uint32)total_size_new;
  458. memory->memory_data = memory_data_new;
  459. memory->memory_data_end = memory_data_new + (uint32)total_size_new;
  460. #if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 || WASM_ENABLE_AOT != 0
  461. #if UINTPTR_MAX == UINT64_MAX
  462. memory->mem_bound_check_1byte.u64 = total_size_new - 1;
  463. memory->mem_bound_check_2bytes.u64 = total_size_new - 2;
  464. memory->mem_bound_check_4bytes.u64 = total_size_new - 4;
  465. memory->mem_bound_check_8bytes.u64 = total_size_new - 8;
  466. memory->mem_bound_check_16bytes.u64 = total_size_new - 16;
  467. #else
  468. memory->mem_bound_check_1byte.u32[0] = (uint32)total_size_new - 1;
  469. memory->mem_bound_check_2bytes.u32[0] = (uint32)total_size_new - 2;
  470. memory->mem_bound_check_4bytes.u32[0] = (uint32)total_size_new - 4;
  471. memory->mem_bound_check_8bytes.u32[0] = (uint32)total_size_new - 8;
  472. memory->mem_bound_check_16bytes.u32[0] = (uint32)total_size_new - 16;
  473. #endif
  474. #endif
  475. return ret;
  476. }
  477. #else
  478. bool
  479. wasm_enlarge_memory(WASMModuleInstance *module, uint32 inc_page_count)
  480. {
  481. WASMMemoryInstance *memory = wasm_get_default_memory(module);
  482. uint32 num_bytes_per_page, total_size_old;
  483. uint32 cur_page_count, max_page_count, total_page_count;
  484. uint64 total_size_new;
  485. if (!memory)
  486. return false;
  487. num_bytes_per_page = memory->num_bytes_per_page;
  488. cur_page_count = memory->cur_page_count;
  489. max_page_count = memory->max_page_count;
  490. total_size_old = num_bytes_per_page * cur_page_count;
  491. total_page_count = inc_page_count + cur_page_count;
  492. total_size_new = num_bytes_per_page * (uint64)total_page_count;
  493. if (inc_page_count <= 0)
  494. /* No need to enlarge memory */
  495. return true;
  496. if (total_page_count < cur_page_count /* integer overflow */
  497. || total_page_count > max_page_count) {
  498. return false;
  499. }
  500. bh_assert(total_size_new <= 4 * (uint64)BH_GB);
  501. if (total_size_new > UINT32_MAX) {
  502. /* Resize to 1 page with size 4G-1 */
  503. num_bytes_per_page = UINT32_MAX;
  504. total_page_count = max_page_count = 1;
  505. total_size_new = UINT32_MAX;
  506. }
  507. #ifdef BH_PLATFORM_WINDOWS
  508. if (!os_mem_commit(memory->memory_data_end,
  509. (uint32)total_size_new - total_size_old,
  510. MMAP_PROT_READ | MMAP_PROT_WRITE)) {
  511. return false;
  512. }
  513. #endif
  514. if (os_mprotect(memory->memory_data_end,
  515. (uint32)total_size_new - total_size_old,
  516. MMAP_PROT_READ | MMAP_PROT_WRITE)
  517. != 0) {
  518. #ifdef BH_PLATFORM_WINDOWS
  519. os_mem_decommit(memory->memory_data_end,
  520. (uint32)total_size_new - total_size_old);
  521. #endif
  522. return false;
  523. }
  524. /* The increased pages are filled with zero by the OS when os_mmap,
  525. no need to memset it again here */
  526. memory->num_bytes_per_page = num_bytes_per_page;
  527. memory->cur_page_count = total_page_count;
  528. memory->max_page_count = max_page_count;
  529. memory->memory_data_size = (uint32)total_size_new;
  530. memory->memory_data_end = memory->memory_data + (uint32)total_size_new;
  531. #if WASM_ENABLE_FAST_JIT != 0 || WASM_ENABLE_JIT != 0 || WASM_ENABLE_AOT != 0
  532. memory->mem_bound_check_1byte.u64 = total_size_new - 1;
  533. memory->mem_bound_check_2bytes.u64 = total_size_new - 2;
  534. memory->mem_bound_check_4bytes.u64 = total_size_new - 4;
  535. memory->mem_bound_check_8bytes.u64 = total_size_new - 8;
  536. memory->mem_bound_check_16bytes.u64 = total_size_new - 16;
  537. #endif
  538. return true;
  539. }
  540. #endif /* end of OS_ENABLE_HW_BOUND_CHECK */