Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion expected/wasm32-wasip2/defined-symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@ ctanhl
ctanl
ctime
ctime_r
descriptor_table_clear
descriptor_table_get_ref
descriptor_table_insert
descriptor_table_remove
Expand Down Expand Up @@ -1569,4 +1570,4 @@ y0f
y1
y1f
yn
ynf
ynf
3 changes: 2 additions & 1 deletion expected/wasm32-wasip3/defined-symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ ctanhl
ctanl
ctime
ctime_r
descriptor_table_clear
descriptor_table_get_ref
descriptor_table_insert
descriptor_table_remove
Expand Down Expand Up @@ -1596,4 +1597,4 @@ y0f
y1
y1f
yn
ynf
ynf
3 changes: 3 additions & 0 deletions libc-bottom-half/headers/private/wasi/descriptor_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@ int descriptor_table_remove(int fd);
/// errno on failure.
int descriptor_table_renumber(int fd, int newfd);

/// Removes all file descriptors from the table, running their destructors.
void descriptor_table_clear();

#endif // __wasip1__

#endif // DESCRIPTOR_TABLE_H
7 changes: 7 additions & 0 deletions libc-bottom-half/headers/public/wasi/libc.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ struct timespec;
/// afterward, you should call this before doing so.
void __wasilibc_populate_preopens(void);

/// Clear the set of preopens (and, on p2+, any other open file descriptors).
///
/// This is appropriate to call just prior to snapshotting the guest state so
/// that it can be resumed on another runtime, in which case any
/// previously-opened handles will no longer be valid.
void __wasilibc_reset_preopens();

#ifndef __wasip2__
/// Register the given pre-opened file descriptor under the given path.
int __wasilibc_register_preopened_fd(int fd, const char *prefix);
Expand Down
21 changes: 21 additions & 0 deletions libc-bottom-half/sources/descriptor_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,22 @@ static int remove(descriptor_table_t *table, int fd,
return 0;
}

static void clear(descriptor_table_t *table) {
for (size_t i = 0; i < table->len; ++i) {
descriptor_table_item_t *table_entry = &table->entries[i];
if (table_entry->occupied) {
descriptor_table_entry_t entry = table_entry->entry;
entry.vtable->free(entry.data);
}
}
if (table->entries)
free(table->entries);
table->entries = NULL;
table->next = 0;
table->len = 0;
table->cap = 0;
}

static bool stdio_initialized = false;

static int init_stdio() {
Expand Down Expand Up @@ -176,3 +192,8 @@ int descriptor_table_remove(int fd) {
entry.vtable->free(entry.data);
return 0;
}

void descriptor_table_clear() {
clear(&global_table);
stdio_initialized = false;
}
4 changes: 4 additions & 0 deletions libc-bottom-half/sources/preopens.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,5 +418,9 @@ void __wasilibc_reset_preopens(void) {

assert_invariants();

#ifndef __wasip1__
descriptor_table_clear();
#endif

UNLOCK(lock);
}
6 changes: 6 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,12 @@ add_wasilibc_test(sleep.c)
add_wasilibc_test(write.c FS)
add_wasilibc_test(wasi-defines.c)

# This tests the behavior of the WASIp2+ descriptor table and won't succeed on
# p1:
if (NOT (WASI STREQUAL "p1"))
add_wasilibc_test(clear_fds.c FS)
endif()

if (CMAKE_C_COMPILER_VERSION VERSION_GREATER 20.0)
add_wasilibc_test(setjmp.c SETJMP)
set_tests_properties(setjmp.wasm PROPERTIES LABELS v8fail)
Expand Down
33 changes: 33 additions & 0 deletions test/src/clear_fds.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "test.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wasi/libc.h>

#define TEST(c) \
do { \
errno = 0; \
if (!(c)) \
t_error("%s failed (errno = %d)\n", #c, errno); \
} while (0)

int main(void) {
char tmp[] = "testsuite-XXXXXX";
int fd;
TEST((fd = open(tmp, O_RDWR | O_CREAT | O_EXCL, 0600)) > 2);
TEST(write(fd, "hello", 6) == 6);
TEST(write(2, "test stderr\n", 12) == 12);
// This should clear the entire descriptor table, closing all descriptors
// (e.g. as the last step of a Wizer-style pre-init function).
__wasilibc_reset_preopens();
if (!(write(fd, "hello", 6) == -1 && errno == EBADF))
t_error("fd should have been closed by `__wasilibc_reset_preopens`");
// stdio handles will be lazily reinitialized, so should still work:
TEST(write(2, "test stderr\n", 12) == 12);
if (fd > 2)
TEST(unlink(tmp) != -1);
return t_status;
}