Skip to content

Commit

Permalink
Implement fd_fdstat_get.
Browse files Browse the repository at this point in the history
Improve other WASI functions as well.

Signed-off-by: Zoltan Herczeg [email protected]
  • Loading branch information
zherczeg authored and clover2123 committed Dec 9, 2024
1 parent 20d770b commit ed31dc5
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 30 deletions.
96 changes: 66 additions & 30 deletions src/wasi/WASI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,23 @@ static void* get_memory_pointer(Instance* instance, Value& value, size_t size)
return memory->buffer() + offset;
}

template <class T, int maxSize>
class TemporaryData {
public:
TemporaryData(size_t size)
{
/* Check that more memory is requested than the maximum provided by malloc. */
if (size > (std::numeric_limits<size_t>::max() / sizeof(T))) {
m_data = nullptr;
return;
}

size *= sizeof(T);

if (size <= sizeof(m_stackData)) {
m_data = m_stackData;
} else {
m_data = malloc(size);
m_data = reinterpret_cast<T*>(malloc(size));
}
}

Expand All @@ -59,14 +68,14 @@ class TemporaryData {
}
}

void* data()
T* data()
{
return m_data;
}

private:
void* m_stackData[8];
void* m_data;
T m_stackData[maxSize];
T* m_data;
};

void WASI::initialize(uvwasi_t* uvwasi)
Expand Down Expand Up @@ -123,51 +132,78 @@ void WASI::clock_time_get(ExecutionState& state, Value* argv, Value* result, Ins
void WASI::fd_write(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t fd = argv[0].asI32();
uint32_t iovptr = argv[1].asI32();
uint32_t iovcnt = argv[2].asI32();
uint32_t out = argv[3].asI32();
size_t iovsLen = static_cast<size_t>(argv[2].asI32());
uint32_t* nwritten = reinterpret_cast<uint32_t*>(get_memory_pointer(instance, argv[3], sizeof(uint32_t)));
uint32_t* iovptr = reinterpret_cast<uint32_t*>(get_memory_pointer(instance, argv[1], iovsLen * (sizeof(uint32_t) << 1)));

if (uint64_t(iovptr) + iovcnt >= instance->memory(0)->sizeInByte()) {
result[0] = Value(static_cast<int16_t>(WasiErrNo::inval));
if (iovptr == nullptr || nwritten == nullptr) {
result[0] = Value(WasiErrNo::inval);
return;
}

std::vector<uvwasi_ciovec_t> iovs(iovcnt);
for (uint32_t i = 0; i < iovcnt; i++) {
iovs[i].buf = instance->memory(0)->buffer() + *reinterpret_cast<uint32_t*>(instance->memory(0)->buffer() + iovptr + i * 8);
iovs[i].buf_len = *reinterpret_cast<uint32_t*>(instance->memory(0)->buffer() + iovptr + 4 + i * 8);
}
TemporaryData<uvwasi_ciovec_t, 8> iovsBuffer(iovsLen);
uvwasi_ciovec_t* iovs = iovsBuffer.data();
uint64_t sizeInByte = instance->memory(0)->sizeInByte();
uint8_t* buffer = instance->memory(0)->buffer();

uvwasi_size_t* out_addr = (uvwasi_size_t*)(instance->memory(0)->buffer() + out);
for (uint32_t i = 0; i < iovsLen; i++) {
if (iovptr[1] > sizeInByte || iovptr[0] > sizeInByte - iovptr[1]) {
result[0] = Value(WasiErrNo::inval);
return;
}

iovs[i].buf = buffer + iovptr[0];
iovs[i].buf_len = iovptr[1];
iovptr += 2;
}

result[0] = Value(static_cast<int16_t>(uvwasi_fd_write(WASI::g_uvwasi, fd, iovs.data(), iovs.size(), out_addr)));
*(instance->memory(0)->buffer() + out) = *out_addr;
result[0] = Value(uvwasi_fd_write(WASI::g_uvwasi, fd, iovs, iovsLen, nwritten));
}

void WASI::fd_read(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t fd = argv[0].asI32();
uint32_t iovptr = argv[1].asI32();
uint32_t iovcnt = argv[2].asI32();
uint32_t out = argv[3].asI32();

std::vector<uvwasi_iovec_t> iovs(iovcnt);
for (uint32_t i = 0; i < iovcnt; i++) {
iovs[i].buf = instance->memory(0)->buffer() + *reinterpret_cast<uint32_t*>(instance->memory(0)->buffer() + iovptr + i * 8);
iovs[i].buf_len = *reinterpret_cast<uint32_t*>(instance->memory(0)->buffer() + iovptr + 4 + i * 8);
size_t iovsLen = static_cast<size_t>(argv[2].asI32());
uint32_t* nread = reinterpret_cast<uint32_t*>(get_memory_pointer(instance, argv[3], sizeof(uint32_t)));
uint32_t* iovptr = reinterpret_cast<uint32_t*>(get_memory_pointer(instance, argv[1], iovsLen * (sizeof(uint32_t) << 1)));

if (iovptr == nullptr || nread == nullptr) {
result[0] = Value(WasiErrNo::inval);
return;
}

uvwasi_size_t* out_addr = (uvwasi_size_t*)(instance->memory(0)->buffer() + out);
TemporaryData<uvwasi_iovec_t, 8> iovsBuffer(iovsLen);
uvwasi_iovec_t* iovs = iovsBuffer.data();
uint64_t sizeInByte = instance->memory(0)->sizeInByte();
uint8_t* buffer = instance->memory(0)->buffer();

for (uint32_t i = 0; i < iovsLen; i++) {
if (iovptr[1] > sizeInByte || iovptr[0] > sizeInByte - iovptr[1]) {
result[0] = Value(WasiErrNo::inval);
return;
}

iovs[i].buf = buffer + iovptr[0];
iovs[i].buf_len = iovptr[1];
iovptr += 2;
}

result[0] = Value(static_cast<int16_t>(uvwasi_fd_read(WASI::g_uvwasi, fd, iovs.data(), iovs.size(), out_addr)));
*(instance->memory(0)->buffer() + out) = *out_addr;
result[0] = Value(uvwasi_fd_read(WASI::g_uvwasi, fd, iovs, iovsLen, nread));
}

void WASI::fd_close(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t fd = argv[0].asI32();

result[0] = Value(static_cast<int16_t>(uvwasi_fd_close(WASI::g_uvwasi, fd)));
result[0] = Value(uvwasi_fd_close(WASI::g_uvwasi, fd));
}

void WASI::fd_fdstat_get(ExecutionState& state, Value* argv, Value* result, Instance* instance)
{
uint32_t fd = argv[0].asI32();
uvwasi_fdstat_t* fdstat = reinterpret_cast<uvwasi_fdstat_t*>(get_memory_pointer(instance, argv[1], sizeof(uvwasi_fdstat_t)));

result[0] = Value(uvwasi_fd_fdstat_get(WASI::g_uvwasi, fd, fdstat));
}

void WASI::fd_seek(ExecutionState& state, Value* argv, Value* result, Instance* instance)
Expand Down Expand Up @@ -218,7 +254,7 @@ void WASI::environ_get(ExecutionState& state, Value* argv, Value* result, Instan
return;
}

TemporaryData pointers(count * sizeof(void*));
TemporaryData<void*, 8> pointers(count);

if (pointers.data() == nullptr) {
result[0] = Value(WasiErrNo::inval);
Expand Down
2 changes: 2 additions & 0 deletions src/wasi/WASI.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class WASI {
F(fd_write, I32I32I32I32_RI32) \
F(fd_read, I32I32I32I32_RI32) \
F(fd_close, I32_RI32) \
F(fd_fdstat_get, I32I32_RI32) \
F(fd_seek, I32I64I32I32_RI32) \
F(path_open, I32I32I32I32I32I64I64I32I32_RI32) \
F(environ_get, I32I32_RI32) \
Expand Down Expand Up @@ -159,6 +160,7 @@ class WASI {
static void fd_write(ExecutionState& state, Value* argv, Value* result, Instance* instance);
static void fd_read(ExecutionState& state, Value* argv, Value* result, Instance* instance);
static void fd_close(ExecutionState& state, Value* argv, Value* result, Instance* instance);
static void fd_fdstat_get(ExecutionState& state, Value* argv, Value* result, Instance* instance);
static void fd_seek(ExecutionState& state, Value* argv, Value* result, Instance* instance);
static void path_open(ExecutionState& state, Value* argv, Value* result, Instance* instance);
static void environ_get(ExecutionState& state, Value* argv, Value* result, Instance* instance);
Expand Down
60 changes: 60 additions & 0 deletions test/wasi/fd_fdstat_get.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
(module
(import "wasi_snapshot_preview1" "path_open" (func $path_open (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32)))
(import "wasi_snapshot_preview1" "fd_close" (func $fd_close (param i32) (result i32)))
(import "wasi_snapshot_preview1" "fd_fdstat_get" (func $fd_fdstat_get (param i32 i32) (result i32)))

(memory 1 1)
(data (i32.const 100) "./fd_fdstat_get.wast")

(func (export "fdstatGet") (result i32 i32 i32)
i32.const 3 ;; Directory file descriptior, by default 3 is the first opened directory
i32.const 1 ;; uvwasi_lookupflags_t: UVWASI_LOOKUP_SYMLINK_FOLLOW
i32.const 100 ;; Offset of file name in memory
i32.const 20 ;; Length of file name
i32.const 0 ;; uvwasi_oflags_t: none
i64.const 0x42000 ;; base uvwasi_rights_t: UVWASI_RIGHT_PATH_OPEN, UVWASI_RIGHT_FD_FILESTAT_GET
i64.const 0x42000 ;; inherited uvwasi_rights_t: UVWASI_RIGHT_PATH_OPEN, UVWASI_RIGHT_FD_FILESTAT_GET
i32.const 0 ;; uvwasi_fdflags_t: none
i32.const 0 ;; Offset to store at the opened file descriptor in memory
call $path_open

i32.const 0
i32.load
i32.const 200
call $fd_fdstat_get

i32.const 0
i32.load
call $fd_close
)

(func (export "fdstatGetBad") (result i32 i32 i32 i32)
i32.const 3 ;; Directory file descriptior, by default 3 is the first opened directory
i32.const 1 ;; uvwasi_lookupflags_t: UVWASI_LOOKUP_SYMLINK_FOLLOW
i32.const 100 ;; Offset of file name in memory
i32.const 20 ;; Length of file name
i32.const 0 ;; uvwasi_oflags_t: none
i64.const 0x42000 ;; base uvwasi_rights_t: UVWASI_RIGHT_PATH_OPEN, UVWASI_RIGHT_FD_FILESTAT_GET
i64.const 0x42000 ;; inherited uvwasi_rights_t: UVWASI_RIGHT_PATH_OPEN, UVWASI_RIGHT_FD_FILESTAT_GET
i32.const 0 ;; uvwasi_fdflags_t: none
i32.const 0 ;; Offset to store at the opened file descriptor in memory
call $path_open

i32.const 0
i32.load
i32.const 65535
call $fd_fdstat_get

i32.const -1
i32.const 200
call $fd_fdstat_get

i32.const 0
i32.load
call $fd_close
)
)

(assert_return (invoke "fdstatGet") (i32.const 0) (i32.const 0) (i32.const 0))
(assert_return (invoke "fdstatGetBad") (i32.const 0) (i32.const 28) (i32.const 8) (i32.const 0))

69 changes: 69 additions & 0 deletions test/wasi/print.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
(module
(import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))

(memory $memory 1 1)
(data (i32.const 100) "Hello ")
(data (i32.const 200) "World!\n")

(func (export "writeToStdout") (result i32 i32)
;; Write iovs into memory from offset 16
i32.const 16
i32.const 100
i32.store

i32.const 20
i32.const 6
i32.store

i32.const 24
i32.const 200
i32.store

i32.const 28
i32.const 7
i32.store

i32.const 1 ;; stdout
i32.const 16 ;; iovs offset
i32.const 2 ;; iovsLen
i32.const 8 ;; nwritten

call $fd_write

i32.const 8
i32.load
)

(func (export "badWrite") (result i32 i32 i32 i32)
i32.const 100000 ;; invalid descriptor
i32.const 8 ;; iovs offset
i32.const 1 ;; iovsLen
i32.const 4 ;; nwritten

call $fd_write

i32.const 1 ;; stdout
i32.const 65529 ;; bad iovs offset
i32.const 1 ;; iovsLen
i32.const 8 ;; nwritten

call $fd_write

i32.const 1 ;; stdout
i32.const 16 ;; iovs offset
i32.const 1 ;; iovsLen
i32.const 65533 ;; bad nwritten

call $fd_write

i32.const 1 ;; stdout
i32.const 8 ;; iovs offset
i32.const 8192 ;; bad iovsLen
i32.const 0 ;; nwritten

call $fd_write
)
)

(assert_return (invoke "writeToStdout") (i32.const 0) (i32.const 13))
(assert_return (invoke "badWrite") (i32.const 8) (i32.const 28) (i32.const 28) (i32.const 28))

0 comments on commit ed31dc5

Please sign in to comment.