Wasi/WasiInstance.cs
using System;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Text;
using WasmBox.Wasi.Data;
using WasmBox.Wasm.Interpret;
namespace WasmBox.Wasi;
public class WasiInstance : IImporter {
const string ModuleName = "wasi_snapshot_preview1";
public WasiInstance() {
// This is a godsend: https://wasix.org/docs/api-reference
predefinedImporter.DefineFunction( "fd_write", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => {
var (fd, iovs_ptr, iovsLen, nwritten_ptr) = ((int)inputs[0], (uint)(int)inputs[1], (int)inputs[2], (uint)(int)inputs[3]);
Stream stream;
switch ( fd ) {
case 0:
return [Errno.EIO];
case 1:
stream = StdOut;
break;
case 2:
stream = StdErr;
break;
default:
return [Errno.EPERM];
}
var memory = context.Module.Memories[0];
var memoryInt32 = memory.Int32;
int written = 0;
for ( uint i = 0; i < iovsLen; i++ ) {
var offset = i * __wasi_ciovec_t.Size;
var iovec = new __wasi_ciovec_t() {
Pointer = memoryInt32[iovs_ptr + offset],
Length = memoryInt32[iovs_ptr + offset + 4],
};
var buffer = memory[iovec];
stream.Write( buffer );
written += iovec.Length;
}
stream.Flush();
memoryInt32[nwritten_ptr] = written;
return [Errno.SUCCESS];
} ) );
predefinedImporter.DefineFunction( "fd_read", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => {
var (fd, iovs_ptr, iovsLen, nread_ptr) = ((int)inputs[0], (uint)(int)inputs[1], (int)inputs[2], (uint)(int)inputs[3]);
Stream stream;
switch ( fd ) {
case 0:
stream = StdIn;
break;
default:
return [Errno.EPERM];
}
var memory = context.Module.Memories[0];
var memoryInt32 = memory.Int32;
int read = 0;
for ( uint i = 0; i < iovsLen; i++ ) {
var offset = i * __wasi_ciovec_t.Size;
var iovec = new __wasi_ciovec_t() {
Pointer = memoryInt32[iovs_ptr + offset],
Length = memoryInt32[iovs_ptr + offset + 4],
};
var buffer = memory[iovec];
var tempBuffer = new byte[iovec.Length];
int bytesRead = stream.Read( tempBuffer, 0, iovec.Length );
tempBuffer.CopyTo( buffer );
read += bytesRead;
}
memoryInt32[nread_ptr] = read;
return [Errno.SUCCESS];
} ) );
predefinedImporter.DefineFunction( "environ_sizes_get", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => {
var (environ_count, environ_buf_size) = ((uint)(int)inputs[0], (uint)(int)inputs[1]);
var memoryInt32 = context.Module.Memories[0].Int32;
memoryInt32[environ_count] = EnvironmentVariables.Count;
memoryInt32[environ_buf_size] = EnvironmentVariableBufferSize;
return [Errno.SUCCESS];
} ) );
predefinedImporter.DefineFunction( "environ_get", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => {
var (environ, environ_buf) = ((uint)(int)inputs[0], (uint)(int)inputs[1]);
var memory = context.Module.Memories[0];
var memoryInt32 = memory.Int32;
uint i = 0;
uint offset = environ_buf;
foreach ( var kv in EnvironmentVariables ) {
string env = $"{kv.Key}={kv.Value}";
byte[] envBytes = Encoding.UTF8.GetBytes( env + '\0' );
var length = (uint)envBytes.Length;
memoryInt32[environ + i * 4] = (int)offset;
memory[(int)offset..(int)(offset + length)] = envBytes;
offset += length;
i++;
}
return [Errno.SUCCESS];
} ) );
predefinedImporter.DefineFunction( "args_sizes_get", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => {
var (argc, argv_buf_size) = ((uint)(int)inputs[0], (uint)(int)inputs[1]);
var memoryInt32 = context.Module.Memories[0].Int32;
memoryInt32[argc] = Arguments.Count;
memoryInt32[argv_buf_size] = ArgumentsBufferSize;
return [Errno.SUCCESS];
} ) );
predefinedImporter.DefineFunction( "args_get", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => {
var (argv, argv_buf) = ((uint)(int)inputs[0], (uint)(int)inputs[1]);
var memory = context.Module.Memories[0];
var memoryInt32 = memory.Int32;
uint i = 0;
uint offset = argv_buf;
foreach ( var arg in Arguments ) {
byte[] argBytes = Encoding.UTF8.GetBytes( $"{arg}\0" );
var length = (uint)argBytes.Length;
memoryInt32[argv + i * 4] = (int)offset;
memory[(int)offset..(int)(offset + length)] = argBytes;
offset += length;
i++;
}
return [Errno.SUCCESS];
} ) );
predefinedImporter.DefineFunction( "clock_time_get", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int64, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => {
var (clockId, precision, time_ptr) = ((int)inputs[0], (long)inputs[1], (uint)(int)inputs[2]);
var memory = context.Module.Memories[0];
var memoryInt64 = memory.Int64;
long nano = 10000L * Stopwatch.GetTimestamp();
nano /= TimeSpan.TicksPerMillisecond;
nano *= 100L;
memoryInt64[time_ptr] = nano;
return [Errno.SUCCESS];
} ) );
predefinedImporter.DefineFunction( "clock_res_get", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => {
var (clockId, resolution_ptr) = ((int)inputs[0], (uint)(int)inputs[1]);
var memory = context.Module.Memories[0];
var memoryInt32 = memory.Int32;
memoryInt32[resolution_ptr] = 100;
return [Errno.SUCCESS];
} ) );
predefinedImporter.DefineFunction( "random_get", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => {
var (buf_ptr, buf_len) = ((uint)(int)inputs[0], (int)inputs[1]);
var memory = context.Module.Memories[0];
for ( uint i = 0; i < buf_len; i++ )
memory[buf_ptr + i] = (byte)Random.Shared.Next( 0, 256 );
return [Errno.SUCCESS];
} ) );
predefinedImporter.DefineFunction( "proc_exit", new DelegateFunctionDefinition(
[WasmValueType.Int32],
[],
( context, inputs ) => {
throw new ProcessExitTrapException( (int)inputs[0] );
} ) );
predefinedImporter.DefineFunction( "sched_yield", new DelegateFunctionDefinition(
[],
[WasmValueType.Int32],
( context, inputs ) => {
return [Errno.SUCCESS];
}
) );
// Idk
predefinedImporter.DefineFunction( "proc_raise", new DelegateFunctionDefinition(
[WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
// These could be implemented for fd of 0/1/2 (stdin/stdout/stderr), but, uhm, too lazy to do dat
predefinedImporter.DefineFunction( "fd_pwrite", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_pread", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_seek", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_tell", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
// File system stuff: Not implemented / Not allowed
predefinedImporter.DefineFunction( "fd_advise", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_allocate", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_close", new DelegateFunctionDefinition(
[WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_datasync", new DelegateFunctionDefinition(
[WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_fdstat_get", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_fdstat_set_flags", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_fdstat_set_rights", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_filestat_get", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_filestat_set_size", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_filestat_set_times", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_prestat_get", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_prestat_dir_name", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_readdir", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_renumber", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "fd_sync", new DelegateFunctionDefinition(
[WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "path_create_directory", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "path_filestat_get", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "path_filestat_set_times", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "path_link", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "path_open", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "path_readlink", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "path_remove_directory", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "path_rename", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "path_symlink", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "path_unlink_file", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "poll_oneoff", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
// Socket stuff : Not Implemented / Not Allowed
predefinedImporter.DefineFunction( "sock_accept", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "sock_recv", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "sock_send", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
predefinedImporter.DefineFunction( "sock_shutdown", new DelegateFunctionDefinition(
[WasmValueType.Int32, WasmValueType.Int32],
[WasmValueType.Int32],
( context, inputs ) => [Errno.EPERM] ) );
namespacedImporter.RegisterImporter( ModuleName, predefinedImporter );
}
public IImporter Importer => this;
public Stream StdIn { get; set; } = new MemoryStream();
public Stream StdOut { get; set; } = SandboxConsoleStream.Info;
public Stream StdErr { get; set; } = SandboxConsoleStream.Warning;
public void SetStdInText(string s) {
StdIn.Flush();
StdIn.SetLength( 0 );
StdIn.Write( Encoding.UTF8.GetBytes( s ) );
StdIn.Seek( 0, SeekOrigin.Begin );
}
public List<string> Arguments = [];
private int ArgumentsBufferSize
=> Arguments.Select( x => Encoding.UTF8.GetByteCount( $"{x}\0" ) ).Sum();
public Dictionary<string, string> EnvironmentVariables = [];
private int EnvironmentVariableBufferSize
=> EnvironmentVariables.Select( kv => Encoding.UTF8.GetByteCount( $"{kv.Key}={kv.Value}\0" ) ).Sum();
private NamespacedImporter namespacedImporter = new();
private PredefinedImporter predefinedImporter = new();
public FunctionDefinition ImportFunction( ImportedFunction description, FunctionType signature )
=> namespacedImporter.ImportFunction( description, signature );
public Variable ImportGlobal( ImportedGlobal description )
=> namespacedImporter.ImportGlobal( description );
public LinearMemory ImportMemory( ImportedMemory description )
=> namespacedImporter.ImportMemory( description );
public FunctionTable ImportTable( ImportedTable description )
=> namespacedImporter.ImportTable( description );
}