wasm_host.c (39783B)
1 #include <kit/wasm.h> 2 #include <stddef.h> 3 #include <stdint.h> 4 #include <string.h> 5 6 typedef struct KitWasmMemoryRecord { 7 uint8_t* data; 8 uint64_t pages; 9 uint64_t max_pages; 10 uint32_t flags; 11 } KitWasmMemoryRecord; 12 13 #define KIT_WASM_HOST_MAX_FDS 64u 14 15 typedef struct KitWasmOpenFd { 16 uint32_t used; 17 uint32_t is_dir; 18 KitFileData data; 19 const KitFileIO* io; 20 uint64_t pos; 21 void* dir_handle; 22 char* host_path; 23 size_t host_path_size; /* 0=borrowed (KIT_WASM_FS_FILE), >0=heap-owned */ 24 } KitWasmOpenFd; 25 26 struct KitWasmHost { 27 KitWasmHostConfig config; 28 }; 29 30 typedef struct KitWasmRuntimeInstance { 31 KitWasmHost* host; 32 const KitWasmMemoryLayout* memory_layouts; 33 uint64_t allocation_bytes; 34 uint64_t instance_bytes; 35 uint64_t total_memory_bytes; 36 uint8_t** memories; 37 uint64_t* memory_bytes; 38 uint32_t nmemories; 39 int exit_called; 40 int exit_code; 41 KitWasmOpenFd fds[KIT_WASM_HOST_MAX_FDS]; 42 uint8_t instance[]; 43 } KitWasmRuntimeInstance; 44 45 enum { 46 WASI_ESUCCESS = 0, 47 WASI_EACCES = 2, 48 WASI_EBADF = 8, 49 WASI_EISDIR = 31, 50 WASI_EINVAL = 28, 51 WASI_EIO = 29, 52 WASI_ENOMEM = 34, 53 WASI_ENOENT = 44, 54 WASI_ENOSYS = 52, 55 WASI_ENOTDIR = 54, 56 WASI_ENOTCAPABLE = 76, 57 }; 58 59 static KitWasmRuntimeInstance* wasm_wrap_from_instance(KitWasmInstance* inst) { 60 return (KitWasmRuntimeInstance*)((uint8_t*)inst - 61 offsetof(KitWasmRuntimeInstance, instance)); 62 } 63 64 static KitWasmInstance* wasm_instance_from_wrap(KitWasmRuntimeInstance* w) { 65 return (KitWasmInstance*)w->instance; 66 } 67 68 static size_t wasm_cstrlen(const char* s) { 69 size_t n = 0; 70 if (!s) return 0; 71 while (s[n]) ++n; 72 return n; 73 } 74 75 static int wasm_streq(const char* a, const char* b) { 76 size_t i = 0; 77 if (!a || !b) return 0; 78 while (a[i] && b[i]) { 79 if (a[i] != b[i]) return 0; 80 ++i; 81 } 82 return a[i] == b[i]; 83 } 84 85 static KitStatus wasm_u64_to_size(uint64_t n, size_t* out) { 86 if (n > (uint64_t)SIZE_MAX) return KIT_INVALID; 87 *out = (size_t)n; 88 return KIT_OK; 89 } 90 91 static KitStatus wasm_page_bytes(uint64_t pages, uint64_t* out) { 92 if (pages > UINT64_MAX / (uint64_t)KIT_WASM_PAGE_SIZE) return KIT_INVALID; 93 *out = pages * (uint64_t)KIT_WASM_PAGE_SIZE; 94 return KIT_OK; 95 } 96 97 static uint32_t wasm_preopen_count(const KitWasmHost* host) { 98 return host ? host->config.nmounts : 0u; 99 } 100 101 static const KitWasmFsMount* wasm_preopen_for_fd(KitWasmRuntimeInstance* w, 102 uint32_t fd) { 103 uint32_t index; 104 if (!w || !w->host || fd < 3u) return NULL; 105 index = fd - 3u; 106 if (index >= w->host->config.nmounts) return NULL; 107 return &w->host->config.mounts[index]; 108 } 109 110 static size_t wasm_guest_parent_len(const char* path) { 111 size_t i; 112 size_t last = 0; 113 if (!path || path[0] != '/') return 0; 114 for (i = 1; path[i]; ++i) { 115 if (path[i] == '/') last = i; 116 } 117 return last ? last : 1u; 118 } 119 120 static const char* wasm_guest_basename(const char* path) { 121 size_t i; 122 size_t last = 0; 123 if (!path) return NULL; 124 for (i = 0; path[i]; ++i) { 125 if (path[i] == '/') last = i + 1u; 126 } 127 return path + last; 128 } 129 130 static int wasm_bytes_eq_cstr(const uint8_t* a, uint32_t alen, 131 const char* b) { 132 uint32_t i; 133 if (!a || !b) return 0; 134 for (i = 0; i < alen; ++i) { 135 if (b[i] == '\0' || a[i] != (uint8_t)b[i]) return 0; 136 } 137 return b[alen] == '\0'; 138 } 139 140 static KitWasmMemoryRecord* wasm_memory0(KitWasmRuntimeInstance* w) { 141 if (!w || w->nmemories == 0 || !w->memory_layouts) return NULL; 142 if (w->memory_layouts[0].offset > w->instance_bytes) return NULL; 143 if (w->instance_bytes - w->memory_layouts[0].offset < 144 sizeof(KitWasmMemoryRecord)) 145 return NULL; 146 return (KitWasmMemoryRecord*)(w->instance + w->memory_layouts[0].offset); 147 } 148 149 static int wasm_mem_ptr(KitWasmInstance* inst, uint32_t addr, uint32_t n, 150 uint8_t** out) { 151 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 152 KitWasmMemoryRecord* mem = wasm_memory0(w); 153 uint64_t end; 154 uint64_t size; 155 if (!out || !mem || !mem->data) return 0; 156 if (addr > UINT32_MAX - n) return 0; 157 end = (uint64_t)addr + (uint64_t)n; 158 if (wasm_page_bytes(mem->pages, &size) != KIT_OK) return 0; 159 if (end > size) return 0; 160 *out = mem->data + addr; 161 return 1; 162 } 163 164 static int wasm_read_u32(KitWasmInstance* inst, uint32_t addr, uint32_t* out) { 165 uint8_t* p; 166 if (!wasm_mem_ptr(inst, addr, 4u, &p)) return 0; 167 *out = ((uint32_t)p[0]) | ((uint32_t)p[1] << 8) | 168 ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); 169 return 1; 170 } 171 172 static int wasm_write_u32(KitWasmInstance* inst, uint32_t addr, uint32_t v) { 173 uint8_t* p; 174 if (!wasm_mem_ptr(inst, addr, 4u, &p)) return 0; 175 p[0] = (uint8_t)(v & 0xffu); 176 p[1] = (uint8_t)((v >> 8) & 0xffu); 177 p[2] = (uint8_t)((v >> 16) & 0xffu); 178 p[3] = (uint8_t)((v >> 24) & 0xffu); 179 return 1; 180 } 181 182 static int wasm_write_u64(KitWasmInstance* inst, uint32_t addr, uint64_t v) { 183 uint8_t* p; 184 if (!wasm_mem_ptr(inst, addr, 8u, &p)) return 0; 185 p[0] = (uint8_t)(v & 0xffu); 186 p[1] = (uint8_t)((v >> 8) & 0xffu); 187 p[2] = (uint8_t)((v >> 16) & 0xffu); 188 p[3] = (uint8_t)((v >> 24) & 0xffu); 189 p[4] = (uint8_t)((v >> 32) & 0xffu); 190 p[5] = (uint8_t)((v >> 40) & 0xffu); 191 p[6] = (uint8_t)((v >> 48) & 0xffu); 192 p[7] = (uint8_t)((v >> 56) & 0xffu); 193 return 1; 194 } 195 196 static void wasm_put_u64_le(uint8_t* buf, uint32_t off, uint64_t v) { 197 buf[off+0] = (uint8_t)(v); buf[off+1] = (uint8_t)(v >> 8); 198 buf[off+2] = (uint8_t)(v >> 16); buf[off+3] = (uint8_t)(v >> 24); 199 buf[off+4] = (uint8_t)(v >> 32); buf[off+5] = (uint8_t)(v >> 40); 200 buf[off+6] = (uint8_t)(v >> 48); buf[off+7] = (uint8_t)(v >> 56); 201 } 202 203 static void wasm_put_u32_le(uint8_t* buf, uint32_t off, uint32_t v) { 204 buf[off+0] = (uint8_t)(v); buf[off+1] = (uint8_t)(v >> 8); 205 buf[off+2] = (uint8_t)(v >> 16); buf[off+3] = (uint8_t)(v >> 24); 206 } 207 208 /* wasi_filestat_t: dev(u64@0) ino(u64@8) filetype(u8@16)+7pad nlink(u64@24) 209 * size(u64@32) atim(u64@40) mtim(u64@48) ctim(u64@56) — 64 bytes total */ 210 static int wasm_write_filestat(KitWasmInstance* inst, uint32_t ptr, 211 uint8_t filetype, uint64_t size, 212 uint64_t mtime_ns) { 213 uint8_t* p; 214 if (!wasm_mem_ptr(inst, ptr, 64u, &p)) return 0; 215 memset(p, 0, 64u); 216 p[16] = filetype; 217 wasm_put_u64_le(p, 32u, size); 218 wasm_put_u64_le(p, 40u, mtime_ns); 219 wasm_put_u64_le(p, 48u, mtime_ns); 220 wasm_put_u64_le(p, 56u, mtime_ns); 221 return 1; 222 } 223 224 static int wasm_status_errno(KitStatus st) { 225 switch (st) { 226 case KIT_OK: 227 return WASI_ESUCCESS; 228 case KIT_NOMEM: 229 return WASI_ENOMEM; 230 case KIT_NOT_FOUND: 231 return WASI_ENOENT; 232 case KIT_IO: 233 return WASI_EIO; 234 case KIT_UNSUPPORTED: 235 return WASI_ENOSYS; 236 case KIT_INVALID: 237 case KIT_MALFORMED: 238 case KIT_AMBIGUOUS: 239 case KIT_ERR: 240 default: 241 return WASI_EINVAL; 242 } 243 } 244 245 static int wasm_sig(const KitWasmImportType* t, const KitWasmValType* params, 246 uint32_t nparams, const KitWasmValType* results, 247 uint32_t nresults) { 248 uint32_t i; 249 if (!t || t->nparams != nparams || t->nresults != nresults) return 0; 250 for (i = 0; i < nparams; ++i) 251 if (!t->params || t->params[i] != params[i]) return 0; 252 for (i = 0; i < nresults; ++i) 253 if (!t->results || t->results[i] != results[i]) return 0; 254 return 1; 255 } 256 257 static void wasi_proc_exit(KitWasmInstance* inst, int32_t code) { 258 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 259 w->exit_called = 1; 260 w->exit_code = code; 261 } 262 263 static int32_t wasi_fd_write(KitWasmInstance* inst, int32_t fd_i, 264 int32_t iovs_i, int32_t iovs_len_i, 265 int32_t nwritten_i) { 266 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 267 uint32_t fd = (uint32_t)fd_i; 268 uint32_t iovs = (uint32_t)iovs_i; 269 uint32_t iovs_len = (uint32_t)iovs_len_i; 270 uint32_t nwritten = (uint32_t)nwritten_i; 271 uint32_t total = 0; 272 uint32_t i; 273 if (fd != 1u && fd != 2u) return WASI_EBADF; 274 for (i = 0; i < iovs_len; ++i) { 275 uint32_t ptr; 276 uint32_t len; 277 uint8_t* data; 278 uint32_t off; 279 uint32_t rec; 280 size_t wrote = 0; 281 KitStatus st; 282 if (i > UINT32_MAX / 8u) return WASI_EINVAL; 283 off = i * 8u; 284 if (iovs > UINT32_MAX - off) return WASI_EINVAL; 285 rec = iovs + off; 286 if (!wasm_read_u32(inst, rec, &ptr) || 287 !wasm_read_u32(inst, rec + 4u, &len) || 288 !wasm_mem_ptr(inst, ptr, len, &data)) 289 return WASI_EINVAL; 290 if (w->host->config.write) { 291 st = w->host->config.write(w->host->config.user, fd, data, len, &wrote); 292 if (st != KIT_OK) return wasm_status_errno(st); 293 if (wrote > len) wrote = len; 294 } else { 295 wrote = len; 296 } 297 if (total > UINT32_MAX - (uint32_t)wrote) return WASI_EINVAL; 298 total += (uint32_t)wrote; 299 if (wrote < len) break; 300 } 301 if (!wasm_write_u32(inst, nwritten, total)) return WASI_EINVAL; 302 return WASI_ESUCCESS; 303 } 304 305 static int wasm_strings_size(const char* const* items, uint32_t n, 306 uint32_t* bytes_out) { 307 uint64_t total = 0; 308 uint32_t i; 309 for (i = 0; i < n; ++i) { 310 total += (uint64_t)wasm_cstrlen(items ? items[i] : NULL) + 1u; 311 if (total > UINT32_MAX) return 0; 312 } 313 *bytes_out = (uint32_t)total; 314 return 1; 315 } 316 317 static int32_t wasi_environ_sizes_get(KitWasmInstance* inst, int32_t count_i, 318 int32_t size_i) { 319 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 320 uint32_t bytes; 321 if (!wasm_strings_size(w->host->config.env, w->host->config.nenv, &bytes)) 322 return WASI_EINVAL; 323 if (!wasm_write_u32(inst, (uint32_t)count_i, w->host->config.nenv) || 324 !wasm_write_u32(inst, (uint32_t)size_i, bytes)) 325 return WASI_EINVAL; 326 return WASI_ESUCCESS; 327 } 328 329 static int wasm_write_strings(KitWasmInstance* inst, const char* const* items, 330 uint32_t nitems, uint32_t ptrs_addr, 331 uint32_t buf_addr) { 332 uint32_t total; 333 uint8_t* ptrs; 334 uint8_t* buf; 335 uint32_t off = 0; 336 uint32_t i; 337 if (!wasm_strings_size(items, nitems, &total)) return 0; 338 if (nitems > UINT32_MAX / 4u) return 0; 339 if (!wasm_mem_ptr(inst, ptrs_addr, nitems * 4u, &ptrs) || 340 !wasm_mem_ptr(inst, buf_addr, total, &buf)) 341 return 0; 342 (void)ptrs; 343 for (i = 0; i < nitems; ++i) { 344 const char* s = items ? items[i] : NULL; 345 size_t len = wasm_cstrlen(s); 346 if (len > (size_t)(UINT32_MAX - off - 1u)) return 0; 347 if (!wasm_write_u32(inst, ptrs_addr + i * 4u, buf_addr + off)) return 0; 348 if (len) memcpy(buf + off, s, len); 349 buf[off + (uint32_t)len] = 0; 350 off += (uint32_t)len + 1u; 351 } 352 return 1; 353 } 354 355 static int32_t wasi_environ_get(KitWasmInstance* inst, int32_t env_i, 356 int32_t buf_i) { 357 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 358 return wasm_write_strings(inst, w->host->config.env, w->host->config.nenv, 359 (uint32_t)env_i, 360 (uint32_t)buf_i) 361 ? WASI_ESUCCESS 362 : WASI_EINVAL; 363 } 364 365 static int32_t wasi_args_sizes_get(KitWasmInstance* inst, int32_t count_i, 366 int32_t size_i) { 367 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 368 uint32_t bytes; 369 if (!wasm_strings_size(w->host->config.args, w->host->config.nargs, &bytes)) 370 return WASI_EINVAL; 371 if (!wasm_write_u32(inst, (uint32_t)count_i, w->host->config.nargs) || 372 !wasm_write_u32(inst, (uint32_t)size_i, bytes)) 373 return WASI_EINVAL; 374 return WASI_ESUCCESS; 375 } 376 377 static int32_t wasi_args_get(KitWasmInstance* inst, int32_t args_i, 378 int32_t buf_i) { 379 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 380 return wasm_write_strings(inst, w->host->config.args, w->host->config.nargs, 381 (uint32_t)args_i, 382 (uint32_t)buf_i) 383 ? WASI_ESUCCESS 384 : WASI_EINVAL; 385 } 386 387 static int32_t wasi_random_get(KitWasmInstance* inst, int32_t ptr_i, 388 int32_t len_i) { 389 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 390 uint8_t* dst; 391 KitStatus st; 392 if (!w->host->config.random) return WASI_ENOSYS; 393 if (!wasm_mem_ptr(inst, (uint32_t)ptr_i, (uint32_t)len_i, &dst)) 394 return WASI_EINVAL; 395 st = w->host->config.random(w->host->config.user, dst, (size_t)len_i); 396 return wasm_status_errno(st); 397 } 398 399 static int32_t wasi_clock_time_get(KitWasmInstance* inst, int32_t clock_id_i, 400 int64_t precision_i, int32_t time_i) { 401 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 402 uint64_t ns = 0; 403 KitStatus st; 404 (void)precision_i; 405 if (!w->host->config.clock) return WASI_ENOSYS; 406 st = w->host->config.clock(w->host->config.user, (uint32_t)clock_id_i, &ns); 407 if (st != KIT_OK) return wasm_status_errno(st); 408 return wasm_write_u64(inst, (uint32_t)time_i, ns) ? WASI_ESUCCESS 409 : WASI_EINVAL; 410 } 411 412 static int32_t wasi_fd_prestat_get(KitWasmInstance* inst, int32_t fd_i, 413 int32_t prestat_i) { 414 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 415 const KitWasmFsMount* m = wasm_preopen_for_fd(w, (uint32_t)fd_i); 416 uint8_t* p; 417 uint32_t len; 418 if (!m) return WASI_EBADF; 419 len = (m->flags & KIT_WASM_FS_FILE) 420 ? (uint32_t)wasm_guest_parent_len(m->guest_path) 421 : (uint32_t)wasm_cstrlen(m->guest_path); 422 if (!wasm_mem_ptr(inst, (uint32_t)prestat_i, 8u, &p)) return WASI_EINVAL; 423 p[0] = 0; 424 p[1] = 0; 425 p[2] = 0; 426 p[3] = 0; 427 p[4] = (uint8_t)(len & 0xffu); 428 p[5] = (uint8_t)((len >> 8) & 0xffu); 429 p[6] = (uint8_t)((len >> 16) & 0xffu); 430 p[7] = (uint8_t)((len >> 24) & 0xffu); 431 return WASI_ESUCCESS; 432 } 433 434 static int32_t wasi_fd_prestat_dir_name(KitWasmInstance* inst, int32_t fd_i, 435 int32_t path_i, int32_t path_len_i) { 436 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 437 const KitWasmFsMount* m = wasm_preopen_for_fd(w, (uint32_t)fd_i); 438 uint8_t* dst; 439 size_t len; 440 if (!m) return WASI_EBADF; 441 len = (m->flags & KIT_WASM_FS_FILE) ? wasm_guest_parent_len(m->guest_path) 442 : wasm_cstrlen(m->guest_path); 443 if ((uint32_t)path_len_i < len) return WASI_EINVAL; 444 if (!wasm_mem_ptr(inst, (uint32_t)path_i, (uint32_t)len, &dst)) 445 return WASI_EINVAL; 446 if (len) memcpy(dst, m->guest_path, len); 447 return WASI_ESUCCESS; 448 } 449 450 static int wasm_guest_path_safe(const uint8_t* path, uint32_t len) { 451 uint32_t i = 0; 452 if (!path || len == 0 || path[0] == '/') return 0; 453 while (i < len) { 454 uint32_t start = i; 455 while (i < len && path[i] != '/') { 456 if (path[i] == '\\') return 0; 457 ++i; 458 } 459 if (i == start) return 0; 460 if (i - start == 2u && path[start] == '.' && path[start + 1u] == '.') 461 return 0; 462 if (i < len) ++i; 463 } 464 return 1; 465 } 466 467 static KitStatus wasm_join_path(KitHeap* heap, const char* base, 468 const uint8_t* rel, uint32_t rel_len, 469 char** out, size_t* out_size) { 470 size_t base_len = wasm_cstrlen(base); 471 size_t need; 472 char* p; 473 int slash; 474 if (!base || !rel || !out || !out_size) return KIT_INVALID; 475 slash = base_len && base[base_len - 1u] != '/' && base[base_len - 1u] != '\\'; 476 if (base_len > SIZE_MAX - (size_t)rel_len - (slash ? 2u : 1u)) 477 return KIT_INVALID; 478 need = base_len + (slash ? 1u : 0u) + (size_t)rel_len + 1u; 479 p = (char*)heap->alloc(heap, need, 1u); 480 if (!p) return KIT_NOMEM; 481 if (base_len) memcpy(p, base, base_len); 482 if (slash) p[base_len++] = '/'; 483 if (rel_len) memcpy(p + base_len, rel, rel_len); 484 p[base_len + (size_t)rel_len] = 0; 485 *out = p; 486 *out_size = need; 487 return KIT_OK; 488 } 489 490 static int wasm_find_free_fd(KitWasmRuntimeInstance* w, uint32_t* out) { 491 uint32_t start = 3u + wasm_preopen_count(w->host); 492 uint32_t fd; 493 if (start >= KIT_WASM_HOST_MAX_FDS) return 0; 494 for (fd = start; fd < KIT_WASM_HOST_MAX_FDS; ++fd) { 495 if (!w->fds[fd].used) { 496 *out = fd; 497 return 1; 498 } 499 } 500 return 0; 501 } 502 503 static void wasm_fd_close_slot(KitWasmRuntimeInstance* w, uint32_t fd) { 504 KitHeap* heap = w->host->config.heap; 505 if (!w->fds[fd].used) return; 506 if (w->fds[fd].is_dir) { 507 if (w->fds[fd].dir_handle && w->host->config.close_dir) 508 w->host->config.close_dir(w->host->config.user, w->fds[fd].dir_handle); 509 } else { 510 if (w->fds[fd].io && w->fds[fd].io->release) 511 w->fds[fd].io->release(w->fds[fd].io->user, &w->fds[fd].data); 512 } 513 if (w->fds[fd].host_path_size > 0) 514 heap->free(heap, w->fds[fd].host_path, w->fds[fd].host_path_size); 515 memset(&w->fds[fd], 0, sizeof w->fds[fd]); 516 } 517 518 static int32_t wasi_path_open(KitWasmInstance* inst, int32_t dirfd_i, 519 int32_t dirflags_i, int32_t path_i, 520 int32_t path_len_i, int32_t oflags_i, 521 int64_t rights_base_i, 522 int64_t rights_inheriting_i, 523 int32_t fdflags_i, int32_t opened_fd_i) { 524 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 525 const KitWasmFsMount* m = wasm_preopen_for_fd(w, (uint32_t)dirfd_i); 526 uint8_t* guest_path; 527 char* host_path = NULL; 528 size_t host_path_size = 0; 529 uint32_t fd; 530 KitStatus st; 531 int open_as_dir; 532 (void)dirflags_i; 533 (void)rights_base_i; 534 (void)rights_inheriting_i; 535 (void)fdflags_i; 536 if (!m) return WASI_EBADF; 537 if (!(m->flags & KIT_WASM_FS_READ)) return WASI_EACCES; 538 /* OFLAGS_DIRECTORY=4; CREAT/EXCL/TRUNC not supported */ 539 if (oflags_i & ~4) return WASI_ENOSYS; 540 open_as_dir = (oflags_i & 4) != 0; 541 if (!open_as_dir && 542 (!w->host->config.file_io || !w->host->config.file_io->read_all)) 543 return WASI_ENOSYS; 544 if (!wasm_mem_ptr(inst, (uint32_t)path_i, (uint32_t)path_len_i, 545 &guest_path)) 546 return WASI_EINVAL; 547 if (!wasm_guest_path_safe(guest_path, (uint32_t)path_len_i)) 548 return WASI_ENOTCAPABLE; 549 if (m->flags & KIT_WASM_FS_FILE) { 550 const char* base = wasm_guest_basename(m->guest_path); 551 if (!base || !*base || 552 !wasm_bytes_eq_cstr(guest_path, (uint32_t)path_len_i, base)) 553 return WASI_ENOENT; 554 host_path = (char*)m->host_path; /* borrowed */ 555 } else { 556 st = wasm_join_path(w->host->config.heap, m->host_path, guest_path, 557 (uint32_t)path_len_i, &host_path, &host_path_size); 558 if (st != KIT_OK) return wasm_status_errno(st); 559 } 560 if (open_as_dir) { 561 void* dir_handle = NULL; 562 if (!w->host->config.open_dir) { 563 if (host_path_size > 0) 564 w->host->config.heap->free(w->host->config.heap, host_path, 565 host_path_size); 566 return WASI_ENOSYS; 567 } 568 st = w->host->config.open_dir(w->host->config.user, host_path, 569 &dir_handle); 570 if (st != KIT_OK) { 571 if (host_path_size > 0) 572 w->host->config.heap->free(w->host->config.heap, host_path, 573 host_path_size); 574 return wasm_status_errno(st); 575 } 576 if (!wasm_find_free_fd(w, &fd)) { 577 if (w->host->config.close_dir) 578 w->host->config.close_dir(w->host->config.user, dir_handle); 579 if (host_path_size > 0) 580 w->host->config.heap->free(w->host->config.heap, host_path, 581 host_path_size); 582 return WASI_ENOMEM; 583 } 584 w->fds[fd].used = 1; 585 w->fds[fd].is_dir = 1; 586 w->fds[fd].dir_handle = dir_handle; 587 w->fds[fd].host_path = host_path; 588 w->fds[fd].host_path_size = host_path_size; 589 if (!wasm_write_u32(inst, (uint32_t)opened_fd_i, fd)) return WASI_EINVAL; 590 return WASI_ESUCCESS; 591 } else { 592 KitFileData data; 593 memset(&data, 0, sizeof data); 594 st = w->host->config.file_io->read_all(w->host->config.file_io->user, 595 host_path, &data); 596 if (st != KIT_OK) { 597 if (host_path_size > 0) 598 w->host->config.heap->free(w->host->config.heap, host_path, 599 host_path_size); 600 return wasm_status_errno(st); 601 } 602 if (!wasm_find_free_fd(w, &fd)) { 603 if (w->host->config.file_io->release) 604 w->host->config.file_io->release(w->host->config.file_io->user, &data); 605 if (host_path_size > 0) 606 w->host->config.heap->free(w->host->config.heap, host_path, 607 host_path_size); 608 return WASI_ENOMEM; 609 } 610 w->fds[fd].used = 1; 611 w->fds[fd].data = data; 612 w->fds[fd].io = w->host->config.file_io; 613 w->fds[fd].pos = 0; 614 w->fds[fd].host_path = host_path; 615 w->fds[fd].host_path_size = host_path_size; 616 if (!wasm_write_u32(inst, (uint32_t)opened_fd_i, fd)) return WASI_EINVAL; 617 return WASI_ESUCCESS; 618 } 619 } 620 621 static int32_t wasi_fd_read(KitWasmInstance* inst, int32_t fd_i, 622 int32_t iovs_i, int32_t iovs_len_i, 623 int32_t nread_i) { 624 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 625 uint32_t fd = (uint32_t)fd_i; 626 uint32_t iovs = (uint32_t)iovs_i; 627 uint32_t iovs_len = (uint32_t)iovs_len_i; 628 uint32_t total = 0; 629 uint32_t i; 630 if (fd >= KIT_WASM_HOST_MAX_FDS || !w->fds[fd].used) return WASI_EBADF; 631 if (w->fds[fd].is_dir) return WASI_EISDIR; 632 for (i = 0; i < iovs_len; ++i) { 633 uint32_t ptr; 634 uint32_t len; 635 uint8_t* dst; 636 uint32_t off; 637 uint32_t rec; 638 uint64_t remain64; 639 uint32_t ncopy; 640 if (i > UINT32_MAX / 8u) return WASI_EINVAL; 641 off = i * 8u; 642 if (iovs > UINT32_MAX - off) return WASI_EINVAL; 643 rec = iovs + off; 644 if (!wasm_read_u32(inst, rec, &ptr) || 645 !wasm_read_u32(inst, rec + 4u, &len) || 646 !wasm_mem_ptr(inst, ptr, len, &dst)) 647 return WASI_EINVAL; 648 if (w->fds[fd].pos >= (uint64_t)w->fds[fd].data.size) break; 649 remain64 = (uint64_t)w->fds[fd].data.size - w->fds[fd].pos; 650 ncopy = len; 651 if ((uint64_t)ncopy > remain64) ncopy = (uint32_t)remain64; 652 if (ncopy) 653 memcpy(dst, w->fds[fd].data.data + (size_t)w->fds[fd].pos, ncopy); 654 w->fds[fd].pos += ncopy; 655 if (total > UINT32_MAX - ncopy) return WASI_EINVAL; 656 total += ncopy; 657 if (ncopy < len) break; 658 } 659 if (!wasm_write_u32(inst, (uint32_t)nread_i, total)) return WASI_EINVAL; 660 return WASI_ESUCCESS; 661 } 662 663 static int32_t wasi_fd_close(KitWasmInstance* inst, int32_t fd_i) { 664 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 665 uint32_t fd = (uint32_t)fd_i; 666 if (fd >= KIT_WASM_HOST_MAX_FDS || !w->fds[fd].used) return WASI_EBADF; 667 wasm_fd_close_slot(w, fd); 668 return WASI_ESUCCESS; 669 } 670 671 static int32_t wasi_fd_seek(KitWasmInstance* inst, int32_t fd_i, 672 int64_t offset, int32_t whence_i, 673 int32_t newoffset_i) { 674 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 675 uint32_t fd = (uint32_t)fd_i; 676 int64_t base; 677 int64_t newpos; 678 if (fd >= KIT_WASM_HOST_MAX_FDS || !w->fds[fd].used) return WASI_EBADF; 679 if (w->fds[fd].is_dir) return WASI_EISDIR; 680 switch (whence_i) { 681 case 0: base = 0; break; 682 case 1: base = (int64_t)w->fds[fd].pos; break; 683 case 2: base = (int64_t)(uint64_t)w->fds[fd].data.size; break; 684 default: return WASI_EINVAL; 685 } 686 if (offset < 0 && (uint64_t)(-offset) > (uint64_t)base) return WASI_EINVAL; 687 newpos = base + offset; 688 if (newpos < 0) return WASI_EINVAL; 689 if ((uint64_t)newpos > (uint64_t)w->fds[fd].data.size) 690 newpos = (int64_t)(uint64_t)w->fds[fd].data.size; 691 w->fds[fd].pos = (uint64_t)newpos; 692 return wasm_write_u64(inst, (uint32_t)newoffset_i, (uint64_t)newpos) 693 ? WASI_ESUCCESS 694 : WASI_EINVAL; 695 } 696 697 static int32_t wasi_fd_tell(KitWasmInstance* inst, int32_t fd_i, 698 int32_t offset_i) { 699 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 700 uint32_t fd = (uint32_t)fd_i; 701 if (fd >= KIT_WASM_HOST_MAX_FDS || !w->fds[fd].used) return WASI_EBADF; 702 if (w->fds[fd].is_dir) return WASI_EISDIR; 703 return wasm_write_u64(inst, (uint32_t)offset_i, w->fds[fd].pos) 704 ? WASI_ESUCCESS 705 : WASI_EINVAL; 706 } 707 708 static int32_t wasi_fd_filestat_get(KitWasmInstance* inst, int32_t fd_i, 709 int32_t filestat_i) { 710 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 711 uint32_t fd = (uint32_t)fd_i; 712 uint32_t npreopen = wasm_preopen_count(w->host); 713 uint64_t size = 0, mtime_ns = 0; 714 uint8_t ft; 715 if (fd <= 2u) 716 return wasm_write_filestat(inst, (uint32_t)filestat_i, 717 KIT_WASM_FILETYPE_CHARACTER_DEVICE, 0u, 0u) 718 ? WASI_ESUCCESS 719 : WASI_EINVAL; 720 if (fd >= 3u && fd < 3u + npreopen) { 721 const KitWasmFsMount* m = wasm_preopen_for_fd(w, fd); 722 ft = (m && (m->flags & KIT_WASM_FS_FILE)) ? KIT_WASM_FILETYPE_REGULAR_FILE 723 : KIT_WASM_FILETYPE_DIRECTORY; 724 return wasm_write_filestat(inst, (uint32_t)filestat_i, ft, 0u, 0u) 725 ? WASI_ESUCCESS 726 : WASI_EINVAL; 727 } 728 if (fd >= KIT_WASM_HOST_MAX_FDS || !w->fds[fd].used) return WASI_EBADF; 729 ft = w->fds[fd].is_dir ? KIT_WASM_FILETYPE_DIRECTORY 730 : KIT_WASM_FILETYPE_REGULAR_FILE; 731 if (w->host->config.stat_path && w->fds[fd].host_path) { 732 w->host->config.stat_path(w->host->config.user, w->fds[fd].host_path, 733 &size, &mtime_ns, &ft); 734 } else if (!w->fds[fd].is_dir) { 735 size = (uint64_t)w->fds[fd].data.size; 736 } 737 return wasm_write_filestat(inst, (uint32_t)filestat_i, ft, size, mtime_ns) 738 ? WASI_ESUCCESS 739 : WASI_EINVAL; 740 } 741 742 static int32_t wasi_path_filestat_get(KitWasmInstance* inst, int32_t dirfd_i, 743 int32_t flags_i, int32_t path_i, 744 int32_t path_len_i, 745 int32_t filestat_i) { 746 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 747 const KitWasmFsMount* m = wasm_preopen_for_fd(w, (uint32_t)dirfd_i); 748 uint8_t* guest_path; 749 char* host_path = NULL; 750 size_t host_path_size = 0; 751 uint64_t size = 0, mtime_ns = 0; 752 uint8_t ft = KIT_WASM_FILETYPE_UNKNOWN; 753 KitStatus st; 754 (void)flags_i; 755 if (!m) return WASI_EBADF; 756 if (!w->host->config.stat_path) return WASI_ENOSYS; 757 if (!wasm_mem_ptr(inst, (uint32_t)path_i, (uint32_t)path_len_i, &guest_path)) 758 return WASI_EINVAL; 759 if (!wasm_guest_path_safe(guest_path, (uint32_t)path_len_i)) 760 return WASI_ENOTCAPABLE; 761 if (m->flags & KIT_WASM_FS_FILE) { 762 const char* base = wasm_guest_basename(m->guest_path); 763 if (!base || !*base || 764 !wasm_bytes_eq_cstr(guest_path, (uint32_t)path_len_i, base)) 765 return WASI_ENOENT; 766 host_path = (char*)m->host_path; 767 } else { 768 st = wasm_join_path(w->host->config.heap, m->host_path, guest_path, 769 (uint32_t)path_len_i, &host_path, &host_path_size); 770 if (st != KIT_OK) return wasm_status_errno(st); 771 } 772 st = w->host->config.stat_path(w->host->config.user, host_path, 773 &size, &mtime_ns, &ft); 774 if (host_path_size > 0) 775 w->host->config.heap->free(w->host->config.heap, host_path, host_path_size); 776 if (st != KIT_OK) return wasm_status_errno(st); 777 return wasm_write_filestat(inst, (uint32_t)filestat_i, ft, size, mtime_ns) 778 ? WASI_ESUCCESS 779 : WASI_EINVAL; 780 } 781 782 /* wasi_dirent_t: d_next(u64@0) ino(u64@8) namlen(u32@16) type(u8@20) 3pad 783 * then namlen bytes of name (no NUL). Cookie = zero-based entry index. */ 784 static int32_t wasi_fd_readdir(KitWasmInstance* inst, int32_t fd_i, 785 int32_t buf_i, int32_t buf_len_i, 786 int64_t cookie_i, int32_t bufused_i) { 787 KitWasmRuntimeInstance* w = wasm_wrap_from_instance(inst); 788 uint32_t fd = (uint32_t)fd_i; 789 uint32_t buf_len = (uint32_t)buf_len_i; 790 uint64_t cookie = (uint64_t)cookie_i; 791 uint8_t* buf; 792 uint32_t written = 0; 793 if (fd >= KIT_WASM_HOST_MAX_FDS || !w->fds[fd].used) return WASI_EBADF; 794 if (!w->fds[fd].is_dir) return WASI_ENOTDIR; 795 if (!w->host->config.read_dir_entry) return WASI_ENOSYS; 796 if (!wasm_mem_ptr(inst, (uint32_t)buf_i, buf_len, &buf)) return WASI_EINVAL; 797 while (written < buf_len) { 798 KitWasmDirEntry entry; 799 uint8_t hdr[24]; 800 uint32_t remain = buf_len - written; 801 uint32_t to_write; 802 KitStatus st = w->host->config.read_dir_entry( 803 w->host->config.user, w->fds[fd].dir_handle, cookie, &entry); 804 if (st == KIT_NOT_FOUND) break; 805 if (st != KIT_OK) return wasm_status_errno(st); 806 memset(hdr, 0, 24u); 807 wasm_put_u64_le(hdr, 0u, cookie + 1u); 808 wasm_put_u64_le(hdr, 8u, entry.ino); 809 wasm_put_u32_le(hdr, 16u, entry.name_len); 810 hdr[20] = entry.filetype; 811 to_write = (remain < 24u) ? remain : 24u; 812 memcpy(buf + written, hdr, to_write); 813 written += to_write; 814 remain -= to_write; 815 if (remain > 0u && entry.name_len > 0u && entry.name) { 816 to_write = (remain < entry.name_len) ? remain : entry.name_len; 817 memcpy(buf + written, entry.name, to_write); 818 written += to_write; 819 } 820 ++cookie; 821 } 822 return wasm_write_u32(inst, (uint32_t)bufused_i, written) ? WASI_ESUCCESS 823 : WASI_EINVAL; 824 } 825 826 static void* wasm_wasi_resolve(void* user, const char* module, 827 const char* field, 828 const KitWasmImportType* type) { 829 KitWasmHost* host = (KitWasmHost*)user; 830 KitWasmValType r_i32[1] = {KIT_WASM_VAL_I32}; 831 KitWasmValType p_proc_exit[1] = {KIT_WASM_VAL_I32}; 832 KitWasmValType p2_i32[2] = {KIT_WASM_VAL_I32, KIT_WASM_VAL_I32}; 833 KitWasmValType p4_i32[4] = {KIT_WASM_VAL_I32, KIT_WASM_VAL_I32, 834 KIT_WASM_VAL_I32, KIT_WASM_VAL_I32}; 835 KitWasmValType p5_i32[5] = {KIT_WASM_VAL_I32, KIT_WASM_VAL_I32, 836 KIT_WASM_VAL_I32, KIT_WASM_VAL_I32, 837 KIT_WASM_VAL_I32}; 838 KitWasmValType p_clock[3] = {KIT_WASM_VAL_I32, KIT_WASM_VAL_I64, 839 KIT_WASM_VAL_I32}; 840 KitWasmValType p_path_open[9] = { 841 KIT_WASM_VAL_I32, KIT_WASM_VAL_I32, KIT_WASM_VAL_I32, 842 KIT_WASM_VAL_I32, KIT_WASM_VAL_I32, KIT_WASM_VAL_I64, 843 KIT_WASM_VAL_I64, KIT_WASM_VAL_I32, KIT_WASM_VAL_I32}; 844 KitWasmValType p_fd_seek[4] = {KIT_WASM_VAL_I32, KIT_WASM_VAL_I64, 845 KIT_WASM_VAL_I32, KIT_WASM_VAL_I32}; 846 KitWasmValType p_fd_readdir[5] = {KIT_WASM_VAL_I32, KIT_WASM_VAL_I32, 847 KIT_WASM_VAL_I32, KIT_WASM_VAL_I64, 848 KIT_WASM_VAL_I32}; 849 if (!host || !(host->config.flags & KIT_WASM_HOST_WASI_PREVIEW1)) 850 return NULL; 851 if (!wasm_streq(module, "wasi_snapshot_preview1")) return NULL; 852 if (wasm_streq(field, "proc_exit") && 853 wasm_sig(type, p_proc_exit, 1u, NULL, 0u)) 854 return (void*)(uintptr_t)wasi_proc_exit; 855 if (wasm_streq(field, "fd_write") && 856 wasm_sig(type, p4_i32, 4u, r_i32, 1u)) 857 return (void*)(uintptr_t)wasi_fd_write; 858 if (wasm_streq(field, "environ_sizes_get") && 859 wasm_sig(type, p2_i32, 2u, r_i32, 1u)) 860 return (void*)(uintptr_t)wasi_environ_sizes_get; 861 if (wasm_streq(field, "environ_get") && 862 wasm_sig(type, p2_i32, 2u, r_i32, 1u)) 863 return (void*)(uintptr_t)wasi_environ_get; 864 if (wasm_streq(field, "args_sizes_get") && 865 wasm_sig(type, p2_i32, 2u, r_i32, 1u)) 866 return (void*)(uintptr_t)wasi_args_sizes_get; 867 if (wasm_streq(field, "args_get") && 868 wasm_sig(type, p2_i32, 2u, r_i32, 1u)) 869 return (void*)(uintptr_t)wasi_args_get; 870 if (wasm_streq(field, "random_get") && 871 wasm_sig(type, p2_i32, 2u, r_i32, 1u)) 872 return (void*)(uintptr_t)wasi_random_get; 873 if (wasm_streq(field, "clock_time_get") && 874 wasm_sig(type, p_clock, 3u, r_i32, 1u)) 875 return (void*)(uintptr_t)wasi_clock_time_get; 876 if (wasm_streq(field, "fd_prestat_get") && 877 wasm_sig(type, p2_i32, 2u, r_i32, 1u)) 878 return (void*)(uintptr_t)wasi_fd_prestat_get; 879 if (wasm_streq(field, "fd_prestat_dir_name") && 880 wasm_sig(type, p4_i32, 4u, r_i32, 1u)) 881 return (void*)(uintptr_t)wasi_fd_prestat_dir_name; 882 if (wasm_streq(field, "path_open") && 883 wasm_sig(type, p_path_open, 9u, r_i32, 1u)) 884 return (void*)(uintptr_t)wasi_path_open; 885 if (wasm_streq(field, "fd_read") && 886 wasm_sig(type, p4_i32, 4u, r_i32, 1u)) 887 return (void*)(uintptr_t)wasi_fd_read; 888 if (wasm_streq(field, "fd_close") && 889 wasm_sig(type, p_proc_exit, 1u, r_i32, 1u)) 890 return (void*)(uintptr_t)wasi_fd_close; 891 if (wasm_streq(field, "fd_seek") && 892 wasm_sig(type, p_fd_seek, 4u, r_i32, 1u)) 893 return (void*)(uintptr_t)wasi_fd_seek; 894 if (wasm_streq(field, "fd_tell") && 895 wasm_sig(type, p2_i32, 2u, r_i32, 1u)) 896 return (void*)(uintptr_t)wasi_fd_tell; 897 if (wasm_streq(field, "fd_filestat_get") && 898 wasm_sig(type, p2_i32, 2u, r_i32, 1u)) 899 return (void*)(uintptr_t)wasi_fd_filestat_get; 900 if (wasm_streq(field, "path_filestat_get") && 901 wasm_sig(type, p5_i32, 5u, r_i32, 1u)) 902 return (void*)(uintptr_t)wasi_path_filestat_get; 903 if (wasm_streq(field, "fd_readdir") && 904 wasm_sig(type, p_fd_readdir, 5u, r_i32, 1u)) 905 return (void*)(uintptr_t)wasi_fd_readdir; 906 return NULL; 907 } 908 909 KIT_API KitStatus kit_wasm_host_new(const KitWasmHostConfig* config, 910 KitWasmHost** out) { 911 KitWasmHost* host; 912 uint32_t i; 913 if (!out || !config || !config->heap) return KIT_INVALID; 914 *out = NULL; 915 if (config->nmounts && !config->mounts) return KIT_INVALID; 916 if (config->nmounts > KIT_WASM_HOST_MAX_FDS - 3u) return KIT_INVALID; 917 for (i = 0; i < config->nmounts; ++i) { 918 const KitWasmFsMount* m = &config->mounts[i]; 919 if (!m->host_path || !m->guest_path || m->guest_path[0] != '/') 920 return KIT_INVALID; 921 if ((m->flags & KIT_WASM_FS_FILE) && 922 (!*wasm_guest_basename(m->guest_path))) 923 return KIT_INVALID; 924 } 925 host = (KitWasmHost*)config->heap->alloc(config->heap, sizeof(*host), 926 _Alignof(KitWasmHost)); 927 if (!host) return KIT_NOMEM; 928 host->config = *config; 929 *out = host; 930 return KIT_OK; 931 } 932 933 KIT_API void kit_wasm_host_free(KitWasmHost* host) { 934 KitHeap* heap; 935 if (!host) return; 936 heap = host->config.heap; 937 heap->free(heap, host, sizeof(*host)); 938 } 939 940 KIT_API KitStatus kit_wasm_instance_new(KitWasmHost* host, KitJit* jit, 941 KitWasmInstance** out) { 942 KitWasmRuntimeLayout layout; 943 KitWasmRuntimeInstance* w; 944 KitHeap* heap; 945 uint64_t instance_bytes; 946 uint64_t allocation_bytes; 947 size_t allocation_size; 948 uint64_t total_memory = 0; 949 KitStatus st; 950 uint32_t i; 951 if (!out || !host || !host->config.heap || !jit) return KIT_INVALID; 952 *out = NULL; 953 heap = host->config.heap; 954 st = kit_wasm_get_runtime_layout(jit, &layout); 955 if (st != KIT_OK) return st; 956 if (layout.nmemories > host->config.max_memories) return KIT_INVALID; 957 instance_bytes = layout.instance_size ? layout.instance_size : 1u; 958 if (instance_bytes > host->config.max_instance_bytes) return KIT_INVALID; 959 if (instance_bytes > UINT64_MAX - offsetof(KitWasmRuntimeInstance, instance)) 960 return KIT_INVALID; 961 allocation_bytes = 962 (uint64_t)offsetof(KitWasmRuntimeInstance, instance) + instance_bytes; 963 st = wasm_u64_to_size(allocation_bytes, &allocation_size); 964 if (st != KIT_OK) return st; 965 w = (KitWasmRuntimeInstance*)heap->alloc(heap, allocation_size, 966 _Alignof(KitWasmRuntimeInstance)); 967 if (!w) return KIT_NOMEM; 968 memset(w, 0, allocation_size); 969 w->host = host; 970 w->memory_layouts = layout.memories; 971 w->allocation_bytes = allocation_bytes; 972 w->instance_bytes = instance_bytes; 973 w->nmemories = layout.nmemories; 974 if (layout.nmemories) { 975 size_t ptr_bytes; 976 size_t bytes_bytes; 977 if ((uint64_t)layout.nmemories > (uint64_t)SIZE_MAX / sizeof(uint8_t*) || 978 (uint64_t)layout.nmemories > (uint64_t)SIZE_MAX / sizeof(uint64_t)) { 979 heap->free(heap, w, allocation_size); 980 return KIT_INVALID; 981 } 982 ptr_bytes = (size_t)layout.nmemories * sizeof(uint8_t*); 983 bytes_bytes = (size_t)layout.nmemories * sizeof(uint64_t); 984 w->memories = (uint8_t**)heap->alloc(heap, ptr_bytes, _Alignof(uint8_t*)); 985 w->memory_bytes = 986 (uint64_t*)heap->alloc(heap, bytes_bytes, _Alignof(uint64_t)); 987 if (!w->memories || !w->memory_bytes) { 988 if (w->memory_bytes) heap->free(heap, w->memory_bytes, bytes_bytes); 989 if (w->memories) heap->free(heap, w->memories, ptr_bytes); 990 heap->free(heap, w, allocation_size); 991 return KIT_NOMEM; 992 } 993 memset(w->memories, 0, ptr_bytes); 994 memset(w->memory_bytes, 0, bytes_bytes); 995 } 996 for (i = 0; i < layout.nmemories; ++i) { 997 const KitWasmMemoryLayout* ml = &layout.memories[i]; 998 KitWasmMemoryRecord* rec; 999 uint64_t mem_bytes; 1000 size_t mem_size; 1001 if (ml->max_pages < ml->min_pages) { 1002 kit_wasm_instance_free(wasm_instance_from_wrap(w)); 1003 return KIT_MALFORMED; 1004 } 1005 if (ml->offset > instance_bytes || 1006 instance_bytes - ml->offset < sizeof(KitWasmMemoryRecord)) { 1007 kit_wasm_instance_free(wasm_instance_from_wrap(w)); 1008 return KIT_MALFORMED; 1009 } 1010 st = wasm_page_bytes(ml->max_pages, &mem_bytes); 1011 if (st != KIT_OK) { 1012 kit_wasm_instance_free(wasm_instance_from_wrap(w)); 1013 return st; 1014 } 1015 if (mem_bytes > host->config.max_total_memory_bytes || 1016 total_memory > host->config.max_total_memory_bytes - mem_bytes) { 1017 kit_wasm_instance_free(wasm_instance_from_wrap(w)); 1018 return KIT_INVALID; 1019 } 1020 total_memory += mem_bytes; 1021 st = wasm_u64_to_size(mem_bytes, &mem_size); 1022 if (st != KIT_OK) { 1023 kit_wasm_instance_free(wasm_instance_from_wrap(w)); 1024 return st; 1025 } 1026 if (mem_size) { 1027 w->memories[i] = (uint8_t*)heap->alloc(heap, mem_size, 1u); 1028 if (!w->memories[i]) { 1029 kit_wasm_instance_free(wasm_instance_from_wrap(w)); 1030 return KIT_NOMEM; 1031 } 1032 memset(w->memories[i], 0, mem_size); 1033 } 1034 w->memory_bytes[i] = mem_bytes; 1035 rec = (KitWasmMemoryRecord*)(w->instance + ml->offset); 1036 rec->data = w->memories[i]; 1037 } 1038 w->total_memory_bytes = total_memory; 1039 *out = wasm_instance_from_wrap(w); 1040 return KIT_OK; 1041 } 1042 1043 KIT_API void kit_wasm_instance_free(KitWasmInstance* inst) { 1044 KitWasmRuntimeInstance* w; 1045 KitHeap* heap; 1046 uint32_t i; 1047 size_t allocation_size; 1048 if (!inst) return; 1049 w = wasm_wrap_from_instance(inst); 1050 heap = w->host->config.heap; 1051 for (i = 0; i < KIT_WASM_HOST_MAX_FDS; ++i) 1052 wasm_fd_close_slot(w, i); 1053 for (i = 0; i < w->nmemories; ++i) { 1054 size_t mem_size; 1055 if (w->memories && w->memories[i] && 1056 wasm_u64_to_size(w->memory_bytes[i], &mem_size) == KIT_OK) 1057 heap->free(heap, w->memories[i], mem_size); 1058 } 1059 if (w->memories) 1060 heap->free(heap, w->memories, (size_t)w->nmemories * sizeof(uint8_t*)); 1061 if (w->memory_bytes) 1062 heap->free(heap, w->memory_bytes, 1063 (size_t)w->nmemories * sizeof(uint64_t)); 1064 allocation_size = (size_t)w->allocation_bytes; 1065 heap->free(heap, w, allocation_size); 1066 } 1067 1068 KIT_API KitStatus kit_wasm_host_bind_imports(KitWasmHost* host, 1069 KitCompiler* compiler, 1070 KitJit* jit, 1071 KitWasmInstance* inst) { 1072 if (!host || !compiler || !jit || !inst) return KIT_INVALID; 1073 return kit_wasm_bind_host_imports(compiler, jit, inst, NULL, 0, 1074 wasm_wasi_resolve, host); 1075 } 1076 1077 KIT_API int kit_wasm_instance_exit_code(KitWasmInstance* inst, int* code_out) { 1078 KitWasmRuntimeInstance* w; 1079 if (!inst) return 0; 1080 w = wasm_wrap_from_instance(inst); 1081 if (!w->exit_called) return 0; 1082 if (code_out) *code_out = w->exit_code; 1083 return 1; 1084 }