From d18704d76fae644b7b8862c0f2c0625f90ad8605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=9A=93?= Date: Fri, 3 Jan 2025 12:22:29 -0500 Subject: [PATCH] Fix memory leaks in wasi.cpp --- src/sandbox/wasi.cpp | 319 ++++++++++++++++++++++--------------------- src/sandbox/wasi.h | 26 ++-- 2 files changed, 176 insertions(+), 169 deletions(-) diff --git a/src/sandbox/wasi.cpp b/src/sandbox/wasi.cpp index b64da5a9c..bdeb60e0c 100644 --- a/src/sandbox/wasi.cpp +++ b/src/sandbox/wasi.cpp @@ -48,15 +48,15 @@ namespace mkxp_retro { #define WASM_MEM(address) ((void *)&wasi->ruby->w2c_memory.data[address]) -struct wasi_zip_handle *file_entry::zip_handle() { +struct wasi_zip_handle *wasi_file_entry::zip_handle() { return (wasi_zip_handle *)handle; } -struct wasi_zip_dir_handle *file_entry::zip_dir_handle() { +struct wasi_zip_dir_handle *wasi_file_entry::zip_dir_handle() { return (wasi_zip_dir_handle *)handle; } -struct wasi_zip_file_handle *file_entry::zip_file_handle() { +struct wasi_zip_file_handle *wasi_file_entry::zip_file_handle() { return (wasi_zip_file_handle *)handle; } @@ -119,25 +119,23 @@ wasi_t::w2c_wasi__snapshot__preview1(std::shared_ptr ruby, cons } // Initialize WASI file descriptor table - fdtable.push_back({.type = file_entry::STDIN}); - fdtable.push_back({.type = file_entry::STDOUT}); - fdtable.push_back({.type = file_entry::STDERR}); + fdtable.push_back({.type = wasi_fd_type::STDIN}); + fdtable.push_back({.type = wasi_fd_type::STDOUT}); + fdtable.push_back({.type = wasi_fd_type::STDERR}); struct wasi_zip_handle *dist_handle = (struct wasi_zip_handle *)std::malloc(sizeof(struct wasi_zip_handle)); if (dist_handle == NULL) { throw SandboxOutOfMemoryException(); } - new(&dist_handle->zip) std::shared_ptr(dist); - new(&dist_handle->path) std::string("/mkxp-retro-dist"); - fdtable.push_back({.type = file_entry::ZIP, .handle = dist_handle}); + new(dist_handle) (struct wasi_zip_handle){.zip = dist, .path = "/mkxp-retro-dist"}; + fdtable.push_back({.type = wasi_fd_type::ZIP, .handle = dist_handle}); struct wasi_zip_handle *game_handle = (struct wasi_zip_handle *)std::malloc(sizeof(struct wasi_zip_handle)); if (game_handle == NULL) { throw SandboxOutOfMemoryException(); } - new(&game_handle->zip) std::shared_ptr(game); - new(&game_handle->path) std::string("/mkxp-retro-game"); - fdtable.push_back({.type = file_entry::ZIP, .handle = game_handle}); + new(game_handle) (struct wasi_zip_handle){.zip = game, .path = "/mkxp-retro-game"}; + fdtable.push_back({.type = wasi_fd_type::ZIP, .handle = game_handle}); } wasi_t::~w2c_wasi__snapshot__preview1() { @@ -212,12 +210,12 @@ static struct wasi_zip_stat wasi_zip_stat(zip_t *zip, const char *path, u32 path } // Gets information about a file or directory at a certain index within a zip file. -static struct wasi_zip_stat wasi_zip_stat_entry(zip_t *zip, struct file_entry &entry) { +static struct wasi_zip_stat wasi_zip_stat_entry(zip_t *zip, struct wasi_file_entry &entry) { struct wasi_zip_stat info; zip_stat_t stat; switch (entry.type) { - case file_entry::ZIPDIR: + case wasi_fd_type::ZIPDIR: if (zip_stat_index(zip, entry.zip_dir_handle()->index, 0, &stat) == 0) { info.exists = true; info.filetype = WASI_IFDIR; @@ -229,7 +227,7 @@ static struct wasi_zip_stat wasi_zip_stat_entry(zip_t *zip, struct file_entry &e } return info; - case file_entry::ZIPFILE: + case wasi_fd_type::ZIPFILE: if (zip_stat_index(zip, entry.zip_file_handle()->index, 0, &stat) == 0) { info.exists = true; info.filetype = WASI_IFREG; @@ -247,10 +245,10 @@ static struct wasi_zip_stat wasi_zip_stat_entry(zip_t *zip, struct file_entry &e } } -u32 wasi_t::allocate_file_descriptor() { +u32 wasi_t::allocate_file_descriptor(enum wasi_fd_type type, void *handle) { if (vacant_fds.empty()) { u32 fd = fdtable.size(); - fdtable.push_back({.type = file_entry::VACANT}); + fdtable.push_back({.type = type, .handle = handle}); return fd; } else { u32 fd = vacant_fds.back(); @@ -260,21 +258,27 @@ u32 wasi_t::allocate_file_descriptor() { } void wasi_t::deallocate_file_descriptor(u32 fd) { - switch (fdtable[fd].type) { - case file_entry::ZIP: - case file_entry::ZIPDIR: - case file_entry::ZIPFILE: - std::free(fdtable[fd].handle); - break; - - default: - break; + if (fdtable[fd].handle != NULL) { + switch (fdtable[fd].type) { + case wasi_fd_type::ZIP: + fdtable[fd].zip_handle()->~wasi_zip_handle(); + break; + case wasi_fd_type::ZIPDIR: + fdtable[fd].zip_dir_handle()->~wasi_zip_dir_handle(); + break; + case wasi_fd_type::ZIPFILE: + fdtable[fd].zip_file_handle()->~wasi_zip_file_handle(); + break; + default: + break; + } + std::free(fdtable[fd].handle); } if (!fdtable.empty() && fd == fdtable.size() - 1) { fdtable.pop_back(); } else { - fdtable[fd].type = file_entry::VACANT; + fdtable[fd] = {.type = wasi_fd_type::VACANT, .handle = NULL}; vacant_fds.push_back(fd); } } @@ -328,17 +332,17 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_close(wasi_t *wasi, u32 fd) { } switch (wasi->fdtable[fd].type) { - case file_entry::VACANT: + case wasi_fd_type::VACANT: return WASI_EBADF; - case file_entry::STDIN: - case file_entry::STDOUT: - case file_entry::STDERR: - case file_entry::ZIP: + case wasi_fd_type::STDIN: + case wasi_fd_type::STDOUT: + case wasi_fd_type::STDERR: + case wasi_fd_type::ZIP: return WASI_EINVAL; - case file_entry::ZIPDIR: - case file_entry::ZIPFILE: + case wasi_fd_type::ZIPDIR: + case wasi_fd_type::ZIPFILE: wasi->deallocate_file_descriptor(fd); return WASI_ESUCCESS; } @@ -359,21 +363,21 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_fdstat_get(wasi_t *wasi, u32 fd, } switch (wasi->fdtable[fd].type) { - case file_entry::VACANT: + case wasi_fd_type::VACANT: return WASI_EBADF; - case file_entry::STDIN: - case file_entry::STDOUT: - case file_entry::STDERR: - case file_entry::ZIPFILE: + case wasi_fd_type::STDIN: + case wasi_fd_type::STDOUT: + case wasi_fd_type::STDERR: + case wasi_fd_type::ZIPFILE: WASM_SET(u8, result, WASI_IFCHR); // fs_filetype WASM_SET(u16, result + 2, 0); // fs_flags WASM_SET(u64, result + 8, WASI_FD_READ | WASI_FD_WRITE | WASI_FD_FILESTAT_GET); // fs_rights_base WASM_SET(u64, result + 16, 0); // fs_rights_inheriting return WASI_ESUCCESS; - case file_entry::ZIP: - case file_entry::ZIPDIR: + case wasi_fd_type::ZIP: + case wasi_fd_type::ZIPDIR: WASM_SET(u8, result, WASI_IFDIR); // fs_filetype WASM_SET(u16, result + 2, 0); // fs_flags WASM_SET(u64, result + 8, WASI_PATH_OPEN | WASI_FD_READDIR | WASI_PATH_FILESTAT_GET | WASI_FD_FILESTAT_GET); // fs_rights_base @@ -392,15 +396,15 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_fdstat_set_flags(wasi_t *wasi, u3 } switch (wasi->fdtable[fd].type) { - case file_entry::VACANT: + case wasi_fd_type::VACANT: return WASI_EBADF; - case file_entry::STDIN: - case file_entry::STDOUT: - case file_entry::STDERR: - case file_entry::ZIP: - case file_entry::ZIPDIR: - case file_entry::ZIPFILE: + case wasi_fd_type::STDIN: + case wasi_fd_type::STDOUT: + case wasi_fd_type::STDERR: + case wasi_fd_type::ZIP: + case wasi_fd_type::ZIPDIR: + case wasi_fd_type::ZIPFILE: return WASI_ESUCCESS; } @@ -415,12 +419,12 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_filestat_get(wasi_t *wasi, u32 fd } switch (wasi->fdtable[fd].type) { - case file_entry::VACANT: + case wasi_fd_type::VACANT: return WASI_EBADF; - case file_entry::STDIN: - case file_entry::STDOUT: - case file_entry::STDERR: + case wasi_fd_type::STDIN: + case wasi_fd_type::STDOUT: + case wasi_fd_type::STDERR: WASM_SET(u64, result, fd); // dev WASM_SET(u64, result + 8, 0); // ino WASM_SET(u8, result + 16, WASI_IFCHR); // filetype @@ -431,7 +435,7 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_filestat_get(wasi_t *wasi, u32 fd WASM_SET(u64, result + 56, 0); // ctim return WASI_ESUCCESS; - case file_entry::ZIP: + case wasi_fd_type::ZIP: { struct wasi_zip_stat info = wasi_zip_stat(wasi->fdtable[fd].zip_handle()->zip->zip, "", 0); if (!info.exists) { @@ -448,10 +452,10 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_filestat_get(wasi_t *wasi, u32 fd return WASI_ESUCCESS; } - case file_entry::ZIPDIR: - case file_entry::ZIPFILE: + case wasi_fd_type::ZIPDIR: + case wasi_fd_type::ZIPFILE: { - u32 parent_fd = wasi->fdtable[fd].type == file_entry::ZIPDIR + u32 parent_fd = wasi->fdtable[fd].type == wasi_fd_type::ZIPDIR ? wasi->fdtable[fd].zip_dir_handle()->parent_fd : wasi->fdtable[fd].zip_file_handle()->parent_fd; struct wasi_zip_stat info = wasi_zip_stat_entry( @@ -484,9 +488,9 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_filestat_set_size(wasi_t *wasi, u } switch (wasi->fdtable[fd].type) { - case file_entry::STDIN: - case file_entry::STDOUT: - case file_entry::STDERR: + case wasi_fd_type::STDIN: + case wasi_fd_type::STDOUT: + case wasi_fd_type::STDERR: return WASI_EINVAL; default: @@ -509,18 +513,18 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_prestat_dir_name(wasi_t *wasi, u3 } switch (wasi->fdtable[fd].type) { - case file_entry::VACANT: + case wasi_fd_type::VACANT: return WASI_EBADF; - case file_entry::ZIP: + case wasi_fd_type::ZIP: std::strncpy((char *)WASM_MEM(path), wasi->fdtable[fd].zip_handle()->path.c_str(), path_len); return WASI_ESUCCESS; - case file_entry::STDIN: - case file_entry::STDOUT: - case file_entry::STDERR: - case file_entry::ZIPDIR: - case file_entry::ZIPFILE: + case wasi_fd_type::STDIN: + case wasi_fd_type::STDOUT: + case wasi_fd_type::STDERR: + case wasi_fd_type::ZIPDIR: + case wasi_fd_type::ZIPFILE: return WASI_EINVAL; } @@ -535,19 +539,19 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_prestat_get(wasi_t *wasi, u32 fd, } switch (wasi->fdtable[fd].type) { - case file_entry::VACANT: + case wasi_fd_type::VACANT: return WASI_EBADF; - case file_entry::ZIP: + case wasi_fd_type::ZIP: WASM_SET(u32, result, 0); WASM_SET(u32, result + 4, wasi->fdtable[fd].zip_handle()->path.length()); return WASI_ESUCCESS; - case file_entry::STDIN: - case file_entry::STDOUT: - case file_entry::STDERR: - case file_entry::ZIPDIR: - case file_entry::ZIPFILE: + case wasi_fd_type::STDIN: + case wasi_fd_type::STDOUT: + case wasi_fd_type::STDERR: + case wasi_fd_type::ZIPDIR: + case wasi_fd_type::ZIPFILE: return WASI_EINVAL; } @@ -567,20 +571,20 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_read(wasi_t *wasi, u32 fd, usize } switch (wasi->fdtable[fd].type) { - case file_entry::VACANT: + case wasi_fd_type::VACANT: return WASI_EBADF; - case file_entry::STDIN: - case file_entry::STDOUT: - case file_entry::STDERR: + case wasi_fd_type::STDIN: + case wasi_fd_type::STDOUT: + case wasi_fd_type::STDERR: WASM_SET(u32, result, 0); return WASI_ESUCCESS; - case file_entry::ZIP: - case file_entry::ZIPDIR: + case wasi_fd_type::ZIP: + case wasi_fd_type::ZIPDIR: return WASI_EINVAL; - case file_entry::ZIPFILE: + case wasi_fd_type::ZIPFILE: { u32 size = 0; while (iovs_len > 0) { @@ -606,20 +610,20 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_readdir(wasi_t *wasi, u32 fd, usi } switch (wasi->fdtable[fd].type) { - case file_entry::VACANT: + case wasi_fd_type::VACANT: return WASI_EBADF; - case file_entry::STDIN: - case file_entry::STDOUT: - case file_entry::STDERR: - case file_entry::ZIPFILE: + case wasi_fd_type::STDIN: + case wasi_fd_type::STDOUT: + case wasi_fd_type::STDERR: + case wasi_fd_type::ZIPFILE: return WASI_EINVAL; - case file_entry::ZIP: - case file_entry::ZIPDIR: + case wasi_fd_type::ZIP: + case wasi_fd_type::ZIPDIR: { usize original_buf = buf; - std::string *prefix = wasi->fdtable[fd].type == file_entry::ZIP ? NULL : &wasi->fdtable[fd].zip_dir_handle()->path; + std::string *prefix = wasi->fdtable[fd].type == wasi_fd_type::ZIP ? NULL : &wasi->fdtable[fd].zip_dir_handle()->path; if (prefix != NULL && *prefix == "/") { prefix = NULL; } @@ -633,7 +637,7 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_readdir(wasi_t *wasi, u32 fd, usi } } - std::shared_ptr zip = wasi->fdtable[fd].type == file_entry::ZIP + std::shared_ptr zip = wasi->fdtable[fd].type == wasi_fd_type::ZIP ? wasi->fdtable[fd].zip_handle()->zip : wasi->fdtable[wasi->fdtable[fd].zip_dir_handle()->parent_fd].zip_handle()->zip; @@ -648,7 +652,7 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_readdir(wasi_t *wasi, u32 fd, usi ++cookie; struct wasi_zip_stat info = wasi_zip_stat( - wasi->fdtable[fd].type == file_entry::ZIP + wasi->fdtable[fd].type == wasi_fd_type::ZIP ? wasi->fdtable[fd].zip_handle()->zip->zip : wasi->fdtable[wasi->fdtable[fd].zip_dir_handle()->parent_fd].zip_handle()->zip->zip, it->second.c_str(), @@ -712,17 +716,17 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_renumber(wasi_t *wasi, u32 fd, u3 } switch (wasi->fdtable[fd].type) { - case file_entry::VACANT: + case wasi_fd_type::VACANT: return WASI_EBADF; - case file_entry::STDIN: - case file_entry::STDOUT: - case file_entry::STDERR: - case file_entry::ZIP: + case wasi_fd_type::STDIN: + case wasi_fd_type::STDOUT: + case wasi_fd_type::STDERR: + case wasi_fd_type::ZIP: return WASI_EINVAL; - case file_entry::ZIPFILE: - case file_entry::ZIPDIR: + case wasi_fd_type::ZIPFILE: + case wasi_fd_type::ZIPDIR: break; } @@ -733,17 +737,17 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_renumber(wasi_t *wasi, u32 fd, u3 if (to >= wasi->fdtable.size()) return WASI_EBADF; switch (wasi->fdtable[to].type) { - case file_entry::VACANT: + case wasi_fd_type::VACANT: return WASI_EBADF; - case file_entry::STDIN: - case file_entry::STDOUT: - case file_entry::STDERR: - case file_entry::ZIP: + case wasi_fd_type::STDIN: + case wasi_fd_type::STDOUT: + case wasi_fd_type::STDERR: + case wasi_fd_type::ZIP: return WASI_EINVAL; - case file_entry::ZIPDIR: - case file_entry::ZIPFILE: + case wasi_fd_type::ZIPDIR: + case wasi_fd_type::ZIPFILE: wasi->deallocate_file_descriptor(to); if (to == wasi->fdtable.size()) { wasi->fdtable.push_back(wasi->fdtable[fd]); @@ -753,7 +757,7 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_renumber(wasi_t *wasi, u32 fd, u3 if (!wasi->fdtable.empty() && fd == wasi->fdtable.size() - 1) { wasi->fdtable.pop_back(); } else { - wasi->fdtable[fd].type = file_entry::VACANT; + wasi->fdtable[fd] = {.type = wasi_fd_type::VACANT, .handle = NULL}; wasi->vacant_fds.push_back(fd); } return WASI_ESUCCESS; @@ -780,17 +784,17 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_tell(wasi_t *wasi, u32 fd, usize } switch (wasi->fdtable[fd].type) { - case file_entry::VACANT: + case wasi_fd_type::VACANT: return WASI_EBADF; - case file_entry::STDIN: - case file_entry::STDOUT: - case file_entry::STDERR: - case file_entry::ZIP: - case file_entry::ZIPDIR: + case wasi_fd_type::STDIN: + case wasi_fd_type::STDOUT: + case wasi_fd_type::STDERR: + case wasi_fd_type::ZIP: + case wasi_fd_type::ZIPDIR: return WASI_EINVAL; - case file_entry::ZIPFILE: + case wasi_fd_type::ZIPFILE: WASM_SET(u64, result, zip_ftell(wasi->fdtable[fd].zip_file_handle()->zip_file_handle.file)); return WASI_ESUCCESS; } @@ -806,15 +810,15 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_write(wasi_t *wasi, u32 fd, usize } switch (wasi->fdtable[fd].type) { - case file_entry::VACANT: + case wasi_fd_type::VACANT: return WASI_EBADF; - case file_entry::STDIN: + case wasi_fd_type::STDIN: WASM_SET(u32, result, 0); return WASI_ESUCCESS; - case file_entry::STDOUT: - case file_entry::STDERR: + case wasi_fd_type::STDOUT: + case wasi_fd_type::STDERR: { u32 size = 0; while (iovs_len > 0) { @@ -824,7 +828,7 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_write(wasi_t *wasi, u32 fd, usize } std::strncpy(buf, (char *)WASM_MEM(WASM_GET(u32, iovs)), WASM_GET(u32, iovs + 4)); for (char *ptr = std::strtok(buf, "\n"); ptr != NULL; ptr = std::strtok(NULL, "\n")) { - mkxp_retro::log_printf(wasi->fdtable[fd].type == file_entry::STDOUT ? RETRO_LOG_INFO : RETRO_LOG_ERROR, "%s\n", ptr); + mkxp_retro::log_printf(wasi->fdtable[fd].type == wasi_fd_type::STDOUT ? RETRO_LOG_INFO : RETRO_LOG_ERROR, "%s\n", ptr); } std::free(buf); size += WASM_GET(u32, iovs + 4); @@ -835,11 +839,11 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_write(wasi_t *wasi, u32 fd, usize return WASI_ESUCCESS; } - case file_entry::ZIP: - case file_entry::ZIPDIR: + case wasi_fd_type::ZIP: + case wasi_fd_type::ZIPDIR: return WASI_EINVAL; - case file_entry::ZIPFILE: + case wasi_fd_type::ZIPFILE: return WASI_EROFS; } @@ -859,16 +863,16 @@ extern "C" u32 w2c_wasi__snapshot__preview1_path_filestat_get(wasi_t *wasi, u32 } switch (wasi->fdtable[fd].type) { - case file_entry::VACANT: + case wasi_fd_type::VACANT: return WASI_EBADF; - case file_entry::STDIN: - case file_entry::STDOUT: - case file_entry::STDERR: - case file_entry::ZIPFILE: + case wasi_fd_type::STDIN: + case wasi_fd_type::STDOUT: + case wasi_fd_type::STDERR: + case wasi_fd_type::ZIPFILE: return WASI_EINVAL; - case file_entry::ZIP: + case wasi_fd_type::ZIP: { struct wasi_zip_stat info = wasi_zip_stat(wasi->fdtable[fd].zip_handle()->zip->zip, (char *)WASM_MEM(path), path_len); if (!info.exists) { @@ -885,7 +889,7 @@ extern "C" u32 w2c_wasi__snapshot__preview1_path_filestat_get(wasi_t *wasi, u32 return WASI_ESUCCESS; } - case file_entry::ZIPDIR: + case wasi_fd_type::ZIPDIR: { char *buf = (char *)std::calloc(wasi->fdtable[fd].zip_dir_handle()->path.length() + path_len + 1, 1); if (buf == NULL) { @@ -894,10 +898,10 @@ extern "C" u32 w2c_wasi__snapshot__preview1_path_filestat_get(wasi_t *wasi, u32 std::strcpy(buf, wasi->fdtable[fd].zip_dir_handle()->path.c_str()); std::strncat(buf, (char *)WASM_MEM(path), path_len); struct wasi_zip_stat info = wasi_zip_stat(wasi->fdtable[wasi->fdtable[fd].zip_dir_handle()->parent_fd].zip_handle()->zip->zip, buf, std::strlen(buf)); + std::free(buf); if (!info.exists) { return WASI_ENOENT; } - std::free(buf); WASM_SET(u64, result, wasi->fdtable[fd].zip_dir_handle()->parent_fd); // dev WASM_SET(u64, result + 8, info.inode); // ino WASM_SET(u8, result + 16, info.filetype); // filetype @@ -931,36 +935,37 @@ extern "C" u32 w2c_wasi__snapshot__preview1_path_open(wasi_t *wasi, u32 fd, u32 } switch (wasi->fdtable[fd].type) { - case file_entry::VACANT: + case wasi_fd_type::VACANT: return WASI_EBADF; - case file_entry::STDIN: - case file_entry::STDOUT: - case file_entry::STDERR: - case file_entry::ZIPFILE: + case wasi_fd_type::STDIN: + case wasi_fd_type::STDOUT: + case wasi_fd_type::STDERR: + case wasi_fd_type::ZIPFILE: return WASI_EINVAL; - case file_entry::ZIP: - case file_entry::ZIPDIR: + case wasi_fd_type::ZIP: + case wasi_fd_type::ZIPDIR: { - char *path_buf = (char *)std::calloc(wasi->fdtable[fd].type == file_entry::ZIPDIR ? wasi->fdtable[fd].zip_dir_handle()->path.length() + path_len + 1 : path_len + 1, 1); + char *path_buf = (char *)std::calloc(wasi->fdtable[fd].type == wasi_fd_type::ZIPDIR ? wasi->fdtable[fd].zip_dir_handle()->path.length() + path_len + 1 : path_len + 1, 1); if (path_buf == NULL) { throw SandboxOutOfMemoryException(); } - if (wasi->fdtable[fd].type == file_entry::ZIPDIR) { + if (wasi->fdtable[fd].type == wasi_fd_type::ZIPDIR) { std::strcpy(path_buf, wasi->fdtable[fd].zip_dir_handle()->path.c_str()); } std::strncat(path_buf, (char *)WASM_MEM(path), path_len); struct wasi_zip_stat info = wasi_zip_stat( - wasi->fdtable[fd].type == file_entry::ZIP + wasi->fdtable[fd].type == wasi_fd_type::ZIP ? wasi->fdtable[fd].zip_handle()->zip->zip : wasi->fdtable[wasi->fdtable[fd].zip_dir_handle()->parent_fd].zip_handle()->zip->zip, path_buf, std::strlen(path_buf) ); if (!info.exists) { + std::free(path_buf); return WASI_ENOENT; } @@ -974,13 +979,13 @@ extern "C" u32 w2c_wasi__snapshot__preview1_path_open(wasi_t *wasi, u32 fd, u32 if (handle == NULL) { throw SandboxOutOfMemoryException(); } - handle->index = info.inode; - new(&handle->path) std::string(new_path); - handle->parent_fd = wasi->fdtable[fd].type == file_entry::ZIPDIR ? wasi->fdtable[fd].zip_dir_handle()->parent_fd : fd; + new(handle) (struct wasi_zip_dir_handle){ + .index = info.inode, + .path = new_path, + .parent_fd = wasi->fdtable[fd].type == wasi_fd_type::ZIPDIR ? wasi->fdtable[fd].zip_dir_handle()->parent_fd : fd, + }; - u32 new_fd = wasi->allocate_file_descriptor(); - WASM_SET(u32, result, new_fd); - wasi->fdtable[new_fd] = {.type = file_entry::ZIPDIR, .handle = handle}; + WASM_SET(u32, result, wasi->allocate_file_descriptor(wasi_fd_type::ZIPDIR, handle)); } else { std::free(path_buf); @@ -988,19 +993,19 @@ extern "C" u32 w2c_wasi__snapshot__preview1_path_open(wasi_t *wasi, u32 fd, u32 if (handle == NULL) { throw SandboxOutOfMemoryException(); } - handle->index = info.inode; - new(&handle->zip_file_handle) wasi_zip_file_container( - wasi->fdtable[fd].type == file_entry::ZIP - ? *wasi->fdtable[fd].zip_handle()->zip - : *wasi->fdtable[wasi->fdtable[fd].zip_dir_handle()->parent_fd].zip_handle()->zip, - info.inode, - 0 - ); - handle->parent_fd = wasi->fdtable[fd].type == file_entry::ZIPDIR ? wasi->fdtable[fd].zip_dir_handle()->parent_fd : fd; - - u32 new_fd = wasi->allocate_file_descriptor(); - WASM_SET(u32, result, new_fd); - wasi->fdtable[new_fd] = {.type = file_entry::ZIPFILE, .handle = handle}; + new(handle) (struct wasi_zip_file_handle){ + .index = info.inode, + .zip_file_handle = wasi_zip_file_container( + wasi->fdtable[fd].type == wasi_fd_type::ZIP + ? *wasi->fdtable[fd].zip_handle()->zip + : *wasi->fdtable[wasi->fdtable[fd].zip_dir_handle()->parent_fd].zip_handle()->zip, + info.inode, + 0 + ), + .parent_fd = wasi->fdtable[fd].type == wasi_fd_type::ZIPDIR ? wasi->fdtable[fd].zip_dir_handle()->parent_fd : fd, + }; + + WASM_SET(u32, result, wasi->allocate_file_descriptor(wasi_fd_type::ZIPFILE, handle)); } return WASI_ESUCCESS; diff --git a/src/sandbox/wasi.h b/src/sandbox/wasi.h index 6e36a3217..668c578d6 100644 --- a/src/sandbox/wasi.h +++ b/src/sandbox/wasi.h @@ -229,16 +229,18 @@ struct wasi_zip_file_handle { struct undefined {}; -struct file_entry { - enum { - STDIN, // This file descriptor is standard input. The `handle` field is undefined. - STDOUT, // This file descriptor is standard output. The `handle` field is undefined. - STDERR, // This file descriptor is standard error. The `handle` field is undefined. - ZIP, // This file descriptor is a read-only zip file. The `handle` field is a `struct wasi_zip_handle`. - ZIPDIR, // This file descriptor is a directory inside of a zip file. The `handle` field is a `struct wasi_zip_dir_handle`. - ZIPFILE, // This file descriptor is a file inside of a zip file. The `handle` field is a `struct wasi_zip_file_handle`. - VACANT, // Indicates this is a vacant file descriptor that doesn't correspond to a file. The `handle` field is undefined. - } type; +enum wasi_fd_type { + STDIN, // This file descriptor is standard input. The `handle` field is null. + STDOUT, // This file descriptor is standard output. The `handle` field is null. + STDERR, // This file descriptor is standard error. The `handle` field is null. + ZIP, // This file descriptor is a read-only zip file. The `handle` field is a `struct wasi_zip_handle *`. + ZIPDIR, // This file descriptor is a directory inside of a zip file. The `handle` field is a `struct wasi_zip_dir_handle *`. + ZIPFILE, // This file descriptor is a file inside of a zip file. The `handle` field is a `struct wasi_zip_file_handle *`. + VACANT, // Indicates this is a vacant file descriptor that doesn't correspond to a file. The `handle` field is null. +}; + +struct wasi_file_entry { + wasi_fd_type type; // The file/directory handle that the file descriptor corresponds to. The exact type of this handle depends on the type of file descriptor. void *handle; @@ -265,14 +267,14 @@ typedef struct w2c_wasi__snapshot__preview1 { std::shared_ptr game; // WASI file descriptor table. Maps WASI file descriptors (unsigned 32-bit integers) to file handles. - std::vector fdtable; + std::vector fdtable; // List of vacant WASI file descriptors so that we can reallocate vacant WASI file descriptors in O(1) amortized time. std::vector vacant_fds; w2c_wasi__snapshot__preview1(std::shared_ptr ruby, const char *game_path); ~w2c_wasi__snapshot__preview1(); - u32 allocate_file_descriptor(); + u32 allocate_file_descriptor(enum wasi_fd_type type, void *handle = NULL); void deallocate_file_descriptor(u32 fd); } wasi_t;