Remove malloc() and free() as much as possible in wasi.cpp

This commit is contained in:
刘皓 2025-01-03 14:06:35 -05:00
parent d18704d76f
commit 886fa6b96f
No known key found for this signature in database
GPG key ID: 7901753DB465B711

View file

@ -19,10 +19,10 @@
** along with mkxp. If not, see <http://www.gnu.org/licenses/>. ** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <algorithm>
#include <cstdio>
#include <cstring> #include <cstring>
#include <algorithm>
#include <random> #include <random>
#include <sstream>
#include <zip.h> #include <zip.h>
#include "wasi.h" #include "wasi.h"
#include "sandbox.h" #include "sandbox.h"
@ -48,6 +48,11 @@ namespace mkxp_retro {
#define WASM_MEM(address) ((void *)&wasi->ruby->w2c_memory.data[address]) #define WASM_MEM(address) ((void *)&wasi->ruby->w2c_memory.data[address])
static inline size_t strlen_safe(const char *str, size_t max_length) {
const char *ptr = (const char *)std::memchr(str, 0, max_length);
return ptr == NULL ? max_length : ptr - str;
}
struct wasi_zip_handle *wasi_file_entry::zip_handle() { struct wasi_zip_handle *wasi_file_entry::zip_handle() {
return (wasi_zip_handle *)handle; return (wasi_zip_handle *)handle;
} }
@ -150,31 +155,24 @@ static struct wasi_zip_stat wasi_zip_stat(zip_t *zip, const char *path, u32 path
struct wasi_zip_stat info; struct wasi_zip_stat info;
zip_stat_t stat; zip_stat_t stat;
char *buf = (char *)std::calloc(path_len + 2, 1); std::string normalized_path(path, strlen_safe(path, path_len));
if (buf == NULL) {
throw SandboxOutOfMemoryException();
}
std::strncpy(buf, path, path_len);
// Trim trailing '/' from the path
info.path_len = std::strlen(buf);
char *ptr = buf + info.path_len;
while (ptr != buf && *--ptr == '/') {
*ptr = 0;
--info.path_len;
}
// Trim leading '/' and '.' from the path // Trim leading '/' and '.' from the path
info.path_offset = 0; info.path_offset = 0;
ptr = buf; info.path_len = normalized_path.length();
while (*ptr == '/' || *ptr == '.') { while (normalized_path[info.path_offset] == '/' || (normalized_path[info.path_offset] == '.' && (info.path_offset >= normalized_path.length() - 1 || normalized_path[info.path_offset + 1] == '/'))) {
++ptr;
++info.path_offset; ++info.path_offset;
--info.path_len; --info.path_len;
} }
if (*ptr == 0) { // Trim trailing '/' from the path
std::free(buf); while (info.path_len != 0 && normalized_path[info.path_len - 1] == '/') {
--info.path_len;
}
normalized_path = normalized_path.substr(info.path_offset, info.path_len);
if (normalized_path.length() == 0) {
info.exists = true; info.exists = true;
info.filetype = WASI_IFDIR; info.filetype = WASI_IFDIR;
info.inode = -1; info.inode = -1;
@ -183,8 +181,7 @@ static struct wasi_zip_stat wasi_zip_stat(zip_t *zip, const char *path, u32 path
return info; return info;
} }
if (zip_stat(zip, ptr, 0, &stat) == 0) { if (zip_stat(zip, normalized_path.c_str(), 0, &stat) == 0) {
std::free(buf);
info.exists = true; info.exists = true;
info.filetype = WASI_IFREG; info.filetype = WASI_IFREG;
info.inode = stat.index; info.inode = stat.index;
@ -193,9 +190,8 @@ static struct wasi_zip_stat wasi_zip_stat(zip_t *zip, const char *path, u32 path
return info; return info;
} }
ptr[std::strlen(ptr)] = '/'; normalized_path.push_back('/');
if (zip_stat(zip, ptr, 0, &stat) == 0) { if (zip_stat(zip, normalized_path.c_str(), 0, &stat) == 0) {
std::free(buf);
info.exists = true; info.exists = true;
info.filetype = WASI_IFDIR; info.filetype = WASI_IFDIR;
info.inode = stat.index; info.inode = stat.index;
@ -204,7 +200,6 @@ static struct wasi_zip_stat wasi_zip_stat(zip_t *zip, const char *path, u32 path
return info; return info;
} }
std::free(buf);
info.exists = false; info.exists = false;
return info; return info;
} }
@ -821,20 +816,18 @@ extern "C" u32 w2c_wasi__snapshot__preview1_fd_write(wasi_t *wasi, u32 fd, usize
case wasi_fd_type::STDERR: case wasi_fd_type::STDERR:
{ {
u32 size = 0; u32 size = 0;
std::string buf;
while (iovs_len > 0) { while (iovs_len > 0) {
char *buf = (char *)std::calloc(WASM_GET(u32, iovs + 4) + 1, 1); buf.append((const char *)WASM_MEM(WASM_GET(u32, iovs)), strlen_safe((const char *)WASM_MEM(WASM_GET(u32, iovs)), WASM_GET(u32, iovs + 4)));
if (buf == NULL) {
throw SandboxOutOfMemoryException();
}
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 == wasi_fd_type::STDOUT ? RETRO_LOG_INFO : RETRO_LOG_ERROR, "%s\n", ptr);
}
std::free(buf);
size += WASM_GET(u32, iovs + 4); size += WASM_GET(u32, iovs + 4);
iovs += 8; iovs += 8;
--iovs_len; --iovs_len;
} }
std::string line;
std::istringstream stream(buf);
while (std::getline(stream, line)) {
mkxp_retro::log_printf(wasi->fdtable[fd].type == wasi_fd_type::STDOUT ? RETRO_LOG_INFO : RETRO_LOG_ERROR, "%s\n", line.c_str());
}
WASM_SET(u32, result, size); WASM_SET(u32, result, size);
return WASI_ESUCCESS; return WASI_ESUCCESS;
} }
@ -891,14 +884,9 @@ extern "C" u32 w2c_wasi__snapshot__preview1_path_filestat_get(wasi_t *wasi, u32
case wasi_fd_type::ZIPDIR: case wasi_fd_type::ZIPDIR:
{ {
char *buf = (char *)std::calloc(wasi->fdtable[fd].zip_dir_handle()->path.length() + path_len + 1, 1); std::string new_path(wasi->fdtable[fd].zip_dir_handle()->path);
if (buf == NULL) { new_path.append((const char *)WASM_MEM(path), strlen_safe((const char *)WASM_MEM(path), path_len));
throw SandboxOutOfMemoryException(); struct wasi_zip_stat info = wasi_zip_stat(wasi->fdtable[wasi->fdtable[fd].zip_dir_handle()->parent_fd].zip_handle()->zip->zip, new_path.c_str(), new_path.length());
}
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) { if (!info.exists) {
return WASI_ENOENT; return WASI_ENOENT;
} }
@ -947,32 +935,25 @@ extern "C" u32 w2c_wasi__snapshot__preview1_path_open(wasi_t *wasi, u32 fd, u32
case wasi_fd_type::ZIP: case wasi_fd_type::ZIP:
case wasi_fd_type::ZIPDIR: case wasi_fd_type::ZIPDIR:
{ {
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); std::string new_path;
if (path_buf == NULL) {
throw SandboxOutOfMemoryException();
}
if (wasi->fdtable[fd].type == wasi_fd_type::ZIPDIR) { if (wasi->fdtable[fd].type == wasi_fd_type::ZIPDIR) {
std::strcpy(path_buf, wasi->fdtable[fd].zip_dir_handle()->path.c_str()); new_path.append(wasi->fdtable[fd].zip_dir_handle()->path);
} }
std::strncat(path_buf, (char *)WASM_MEM(path), path_len); new_path.append((const char *)WASM_MEM(path), strlen_safe((const char *)WASM_MEM(path), path_len));
struct wasi_zip_stat info = wasi_zip_stat( struct wasi_zip_stat info = wasi_zip_stat(
wasi->fdtable[fd].type == wasi_fd_type::ZIP wasi->fdtable[fd].type == wasi_fd_type::ZIP
? wasi->fdtable[fd].zip_handle()->zip->zip ? wasi->fdtable[fd].zip_handle()->zip->zip
: wasi->fdtable[wasi->fdtable[fd].zip_dir_handle()->parent_fd].zip_handle()->zip->zip, : wasi->fdtable[wasi->fdtable[fd].zip_dir_handle()->parent_fd].zip_handle()->zip->zip,
path_buf, new_path.c_str(),
std::strlen(path_buf) new_path.length()
); );
if (!info.exists) { if (!info.exists) {
std::free(path_buf);
return WASI_ENOENT; return WASI_ENOENT;
} }
if (info.filetype == WASI_IFDIR) { if (info.filetype == WASI_IFDIR) {
path_buf[info.path_offset + info.path_len] = 0; new_path = new_path.substr(info.path_offset, info.path_len);
std::string new_path(path_buf + info.path_offset);
std::free(path_buf);
new_path.push_back('/'); new_path.push_back('/');
struct wasi_zip_dir_handle *handle = (struct wasi_zip_dir_handle *)std::malloc(sizeof(struct wasi_zip_dir_handle)); struct wasi_zip_dir_handle *handle = (struct wasi_zip_dir_handle *)std::malloc(sizeof(struct wasi_zip_dir_handle));
@ -987,8 +968,6 @@ extern "C" u32 w2c_wasi__snapshot__preview1_path_open(wasi_t *wasi, u32 fd, u32
WASM_SET(u32, result, wasi->allocate_file_descriptor(wasi_fd_type::ZIPDIR, handle)); WASM_SET(u32, result, wasi->allocate_file_descriptor(wasi_fd_type::ZIPDIR, handle));
} else { } else {
std::free(path_buf);
struct wasi_zip_file_handle *handle = (struct wasi_zip_file_handle *)std::malloc(sizeof(struct wasi_zip_file_handle)); struct wasi_zip_file_handle *handle = (struct wasi_zip_file_handle *)std::malloc(sizeof(struct wasi_zip_file_handle));
if (handle == NULL) { if (handle == NULL) {
throw SandboxOutOfMemoryException(); throw SandboxOutOfMemoryException();