1 /* 2 * Copyright 2018 WebAssembly Community Group participants 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef WASM_RT_H_ 18 #define WASM_RT_H_ 19 20 #include <stdbool.h> 21 #include <stdint.h> 22 #include <stddef.h> 23 #include <setjmp.h> 24 25 #if defined(_WIN32) 26 #define WASM2C_FUNC_EXPORT __declspec(dllexport) 27 #else 28 #define WASM2C_FUNC_EXPORT 29 #endif 30 31 #ifdef __cplusplus 32 extern "C" { 33 #endif 34 35 /** Maximum stack depth before trapping. This can be configured by defining 36 * this symbol before including wasm-rt when building the generated c files, 37 * for example: 38 * 39 * ``` 40 * cc -c -DWASM_RT_MAX_CALL_STACK_DEPTH=100 my_module.c -o my_module.o 41 * ``` 42 * */ 43 #ifndef WASM_RT_MAX_CALL_STACK_DEPTH 44 #define WASM_RT_MAX_CALL_STACK_DEPTH 500 45 #endif 46 47 /** Check if we should use guard page model. 48 * This is enabled by default unless WASM_USE_EXPLICIT_BOUNDS_CHECKS is defined. 49 */ 50 #if defined(WASM_USE_GUARD_PAGES) && defined(WASM_USE_EXPLICIT_BOUNDS_CHECKS) 51 # error "Cannot define both WASM_USE_GUARD_PAGES and WASM_USE_EXPLICIT_BOUNDS_CHECKS" 52 #elif !defined(WASM_USE_GUARD_PAGES) && !defined(WASM_USE_EXPLICIT_BOUNDS_CHECKS) 53 // default to guard pages 54 # define WASM_USE_GUARD_PAGES 55 #endif 56 57 /** Define WASM_USE_INCREMENTAL_MOVEABLE_MEMORY_ALLOC if you want the runtime to incrementally allocate heap/linear memory 58 * Note that this memory may be moved when it needs to expand 59 */ 60 61 #if defined(_MSC_VER) 62 #define WASM_RT_NO_RETURN __declspec(noreturn) 63 #else 64 #define WASM_RT_NO_RETURN __attribute__((noreturn)) 65 #endif 66 67 /** Reason a trap occurred. Provide this to `wasm_rt_trap`. 68 * If you update this enum also update the error message in wasm_rt_trap. 69 */ 70 typedef enum { 71 WASM_RT_TRAP_NONE, /** No error. */ 72 WASM_RT_TRAP_OOB, /** Out-of-bounds access in linear memory. */ 73 WASM_RT_TRAP_INT_OVERFLOW, /** Integer overflow on divide or truncation. */ 74 WASM_RT_TRAP_DIV_BY_ZERO, /** Integer divide by zero. */ 75 WASM_RT_TRAP_INVALID_CONVERSION, /** Conversion from NaN to integer. */ 76 WASM_RT_TRAP_UNREACHABLE, /** Unreachable instruction executed. */ 77 WASM_RT_TRAP_CALL_INDIRECT_TABLE_EXPANSION, /** Invalid call_indirect, as func table cannot grow/grow further. */ 78 WASM_RT_TRAP_CALL_INDIRECT_OOB_INDEX, /** Invalid call_indirect, due to index larger than func table. */ 79 WASM_RT_TRAP_CALL_INDIRECT_NULL_PTR, /** Invalid call_indirect, as function being invoked is null. */ 80 WASM_RT_TRAP_CALL_INDIRECT_TYPE_MISMATCH, /** Invalid call_indirect, as function being invoked has an unexpected type. */ 81 WASM_RT_TRAP_CALL_INDIRECT_UNKNOWN_ERR, /** Invalid call_indirect, for other reason. */ 82 WASM_RT_TRAP_EXHAUSTION, /** Call stack exhausted. */ 83 WASM_RT_TRAP_SHADOW_MEM, /** Trap due to shadow memory mismatch */ 84 WASM_RT_TRAP_WASI, /** Trap due to WASI error */ 85 } wasm_rt_trap_t; 86 87 /** Value types. Used to define function signatures. */ 88 typedef enum { 89 WASM_RT_I32, 90 WASM_RT_I64, 91 WASM_RT_F32, 92 WASM_RT_F64, 93 } wasm_rt_type_t; 94 95 /** A function type for all `anyfunc` functions in a Table. All functions are 96 * stored in this canonical form, but must be cast to their proper signature to 97 * call. */ 98 typedef void (*wasm_rt_anyfunc_t)(void); 99 100 /** 101 * The class of the indirect function being invoked 102 */ 103 typedef enum { 104 WASM_RT_INTERNAL_FUNCTION, 105 WASM_RT_EXTERNAL_FUNCTION 106 } wasm_rt_elem_target_class_t; 107 108 /** A single element of a Table. */ 109 typedef struct { 110 wasm_rt_elem_target_class_t func_class; 111 /** The index as returned from `wasm_rt_register_func_type`. */ 112 uint32_t func_type; 113 /** The function. The embedder must know the actual C signature of the 114 * function and cast to it before calling. */ 115 wasm_rt_anyfunc_t func; 116 } wasm_rt_elem_t; 117 118 typedef uint8_t wasm2c_shadow_memory_cell_t; 119 120 typedef struct { 121 wasm2c_shadow_memory_cell_t* data; 122 size_t data_size; 123 void* allocation_sizes_map; 124 uint32_t heap_base; 125 } wasm2c_shadow_memory_t; 126 127 /** A Memory object. */ 128 typedef struct { 129 /** The linear memory data, with a byte length of `size`. */ 130 #if defined(WASM_USE_GUARD_PAGES) || !defined(WASM_USE_INCREMENTAL_MOVEABLE_MEMORY_ALLOC) 131 uint8_t* const data; 132 #else 133 uint8_t* data; 134 #endif 135 /** The current and maximum page count for this Memory object. If there is no 136 * maximum, `max_pages` is 0xffffffffu (i.e. UINT32_MAX). */ 137 uint32_t pages, max_pages; 138 /** The current size of the linear memory, in bytes. */ 139 uint32_t size; 140 141 /** 32-bit platforms use masking for sandboxing. This sets the mask, which is 142 * computed based on the heap size */ 143 #if UINTPTR_MAX == 0xffffffff 144 const uint32_t mem_mask; 145 #endif 146 147 #if defined(WASM_CHECK_SHADOW_MEMORY) 148 wasm2c_shadow_memory_t shadow_memory; 149 #endif 150 } wasm_rt_memory_t; 151 152 /** A Table object. */ 153 typedef struct { 154 /** The table element data, with an element count of `size`. */ 155 wasm_rt_elem_t* data; 156 /** The maximum element count of this Table object. If there is no maximum, 157 * `max_size` is 0xffffffffu (i.e. UINT32_MAX). */ 158 uint32_t max_size; 159 /** The current element count of the table. */ 160 uint32_t size; 161 } wasm_rt_table_t; 162 163 typedef struct wasm_func_type_t { 164 wasm_rt_type_t* params; 165 wasm_rt_type_t* results; 166 uint32_t param_count; 167 uint32_t result_count; 168 } wasm_func_type_t; 169 170 #define WASM2C_WASI_MAX_SETJMP_STACK 32 171 #define WASM2C_WASI_MAX_FDS 32 172 typedef struct wasm_sandbox_wasi_data { 173 wasm_rt_memory_t* heap_memory; 174 175 uint32_t tempRet0; 176 177 uint32_t next_setjmp_index; 178 jmp_buf setjmp_stack[WASM2C_WASI_MAX_SETJMP_STACK]; 179 180 uint32_t main_argc; 181 char** main_argv; 182 183 int wasm_fd_to_native[WASM2C_WASI_MAX_FDS]; 184 uint32_t next_wasm_fd; 185 186 void* clock_data; 187 188 } wasm_sandbox_wasi_data; 189 190 typedef void (*wasm_rt_sys_init_t)(void); 191 typedef void* (*create_wasm2c_sandbox_t)(uint32_t max_wasm_pages); 192 typedef void (*destroy_wasm2c_sandbox_t)(void* sbx_ptr); 193 typedef void* (*lookup_wasm2c_nonfunc_export_t)(void* sbx_ptr, const char* name); 194 typedef uint32_t (*lookup_wasm2c_func_index_t)(void* sbx_ptr, uint32_t param_count, uint32_t result_count, wasm_rt_type_t* types); 195 typedef uint32_t (*add_wasm2c_callback_t)(void* sbx_ptr, uint32_t func_type_idx, void* func_ptr, wasm_rt_elem_target_class_t func_class); 196 typedef void (*remove_wasm2c_callback_t)(void* sbx_ptr, uint32_t callback_idx); 197 198 typedef struct wasm2c_sandbox_funcs_t { 199 wasm_rt_sys_init_t wasm_rt_sys_init; 200 create_wasm2c_sandbox_t create_wasm2c_sandbox; 201 destroy_wasm2c_sandbox_t destroy_wasm2c_sandbox; 202 lookup_wasm2c_nonfunc_export_t lookup_wasm2c_nonfunc_export; 203 lookup_wasm2c_func_index_t lookup_wasm2c_func_index; 204 add_wasm2c_callback_t add_wasm2c_callback; 205 remove_wasm2c_callback_t remove_wasm2c_callback; 206 } wasm2c_sandbox_funcs_t; 207 208 /** Stop execution immediately and jump back to the call to `wasm_rt_try`. 209 * The result of `wasm_rt_try` will be the provided trap reason. 210 * 211 * This is typically called by the generated code, and not the embedder. */ 212 WASM_RT_NO_RETURN extern void wasm_rt_trap(wasm_rt_trap_t); 213 214 /** An indirect callback function failed. 215 * Deduce the reason for the failure and then call trap. 216 * 217 * This is typically called by the generated code, and not the embedder. */ 218 WASM_RT_NO_RETURN extern void wasm_rt_callback_error_trap(wasm_rt_table_t* table, uint32_t func_index, uint32_t expected_func_type); 219 220 /** Register a function type with the given signature. The returned function 221 * index is guaranteed to be the same for all calls with the same signature. 222 * The following varargs must all be of type `wasm_rt_type_t`, first the 223 * params` and then the `results`. 224 * 225 * ``` 226 * // Register (func (param i32 f32) (result i64)). 227 * wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_I64); 228 * => returns 1 229 * 230 * // Register (func (result i64)). 231 * wasm_rt_register_func_type(0, 1, WASM_RT_I32); 232 * => returns 2 233 * 234 * // Register (func (param i32 f32) (result i64)) again. 235 * wasm_rt_register_func_type(2, 1, WASM_RT_I32, WASM_RT_F32, WASM_RT_I64); 236 * => returns 1 237 * ``` */ 238 extern uint32_t wasm_rt_register_func_type(wasm_func_type_t** p_func_type_structs, 239 uint32_t* p_func_type_count, 240 uint32_t params, 241 uint32_t results, 242 wasm_rt_type_t* types); 243 244 extern void wasm_rt_cleanup_func_types(wasm_func_type_t** p_func_type_structs, 245 uint32_t* p_func_type_count); 246 247 /** 248 * Return the default value of the maximum size allowed for wasm memory. 249 */ 250 extern uint64_t wasm_rt_get_default_max_linear_memory_size(); 251 252 /** Initialize a Memory object with an initial page size of `initial_pages` and 253 * a maximum page size of `max_pages`. 254 * 255 * ``` 256 * wasm_rt_memory_t my_memory; 257 * // 1 initial page (65536 bytes), and a maximum of 2 pages. 258 * wasm_rt_allocate_memory(&my_memory, 1, 2); 259 * ``` */ 260 extern bool wasm_rt_allocate_memory(wasm_rt_memory_t*, 261 uint32_t initial_pages, 262 uint32_t max_pages); 263 264 extern void wasm_rt_deallocate_memory(wasm_rt_memory_t*); 265 266 /** Grow a Memory object by `pages`, and return the previous page count. If 267 * this new page count is greater than the maximum page count, the grow fails 268 * and 0xffffffffu (UINT32_MAX) is returned instead. 269 * 270 * ``` 271 * wasm_rt_memory_t my_memory; 272 * ... 273 * // Grow memory by 10 pages. 274 * uint32_t old_page_size = wasm_rt_grow_memory(&my_memory, 10); 275 * if (old_page_size == UINT32_MAX) { 276 * // Failed to grow memory. 277 * } 278 * ``` */ 279 extern uint32_t wasm_rt_grow_memory(wasm_rt_memory_t*, uint32_t pages); 280 281 /** Initialize a Table object with an element count of `elements` and a maximum 282 * page size of `max_elements`. 283 * 284 * ``` 285 * wasm_rt_table_t my_table; 286 * // 5 elemnets and a maximum of 10 elements. 287 * wasm_rt_allocate_table(&my_table, 5, 10); 288 * ``` */ 289 extern void wasm_rt_allocate_table(wasm_rt_table_t*, 290 uint32_t elements, 291 uint32_t max_elements); 292 293 extern void wasm_rt_deallocate_table(wasm_rt_table_t*); 294 295 extern void wasm_rt_expand_table(wasm_rt_table_t*); 296 297 // One time init function for wasm runtime. Should be called once for the current process 298 extern void wasm_rt_sys_init(); 299 300 // Initialize wasi for the given sandbox. Called prior to sandbox execution. 301 extern void wasm_rt_init_wasi(wasm_sandbox_wasi_data*); 302 303 extern void wasm_rt_cleanup_wasi(wasm_sandbox_wasi_data*); 304 305 // Helper function that host can use to ensure wasm2c code is loaded correctly when using dynamic libraries 306 extern void wasm2c_ensure_linked(); 307 308 // Runtime functions for shadow memory 309 310 // Create the shadow memory 311 extern void wasm2c_shadow_memory_create(wasm_rt_memory_t* mem); 312 // Expand the shadow memory to match wasm memory 313 extern void wasm2c_shadow_memory_expand(wasm_rt_memory_t* mem); 314 // Cleanup 315 extern void wasm2c_shadow_memory_destroy(wasm_rt_memory_t* mem); 316 // Perform checks for the load operation that completed 317 WASM2C_FUNC_EXPORT extern void wasm2c_shadow_memory_load(wasm_rt_memory_t* mem, const char* func_name, uint32_t ptr, uint32_t ptr_size); 318 // Perform checks for the store operation that completed 319 WASM2C_FUNC_EXPORT extern void wasm2c_shadow_memory_store(wasm_rt_memory_t* mem, const char* func_name, uint32_t ptr, uint32_t ptr_size); 320 // Mark an area as allocated, if it is currently unused. If already used, this is a noop. 321 extern void wasm2c_shadow_memory_reserve(wasm_rt_memory_t* mem, uint32_t ptr, uint32_t ptr_size); 322 // Perform checks for the malloc operation that completed 323 extern void wasm2c_shadow_memory_dlmalloc(wasm_rt_memory_t* mem, uint32_t ptr, uint32_t ptr_size); 324 // Perform checks for the free operation that will be run 325 extern void wasm2c_shadow_memory_dlfree(wasm_rt_memory_t* mem, uint32_t ptr); 326 // Pass on information about the boundary between wasm globals and heap 327 // Shadow asan will check that all malloc metadata structures below this boundary are only accessed by malloc related functions 328 extern void wasm2c_shadow_memory_mark_globals_heap_boundary(wasm_rt_memory_t* mem, uint32_t ptr); 329 // Print a list of all allocations currently active 330 WASM2C_FUNC_EXPORT extern void wasm2c_shadow_memory_print_allocations(wasm_rt_memory_t* mem); 331 // Print the size of allocations currently active 332 WASM2C_FUNC_EXPORT uint64_t wasm2c_shadow_memory_print_total_allocations(wasm_rt_memory_t* mem); 333 334 #ifdef __cplusplus 335 } 336 #endif 337 338 #endif /* WASM_RT_H_ */ 339