RyanLamansky / dotnet-webassembly

Create, read, modify, write and execute WebAssembly (WASM) files from .NET-based applications.
Apache License 2.0
792 stars 74 forks source link

How to read memory of executed wasm program ? #15

Closed ghost closed 5 years ago

ghost commented 5 years ago

I've not been able to access UnmanagedMemory of the executed program. I've tried this code:

//in imports array of the Compile.FromBinary method:
new MemoryImport("env", "memory", GetMethod(nameof(GetMemory)))

public static MethodInfo GetMethod(string name)
{
    var mi = typeof(ExecutorService).GetMethod(name);
    if (mi == null)
        throw new Exception("missing method " + name);
    return mi;
}

public static UnmanagedMemory GetMemory(){
    var um = new UnmanagedMemory(1, null);

    //Store a reference to re-use it later

    return um;
}
RyanLamansky commented 5 years ago

With the current design, the memory instance is disposed when the compiled webassembly instance that used it is disposed. I don't see enough of the code to know for sure if that's your issue but it's one possibility.

Let me know if that helps.

ghost commented 5 years ago

This is the entire code I'm using.

public static class ExecutorService
{ 
    public static bool IsExecutingTask { get; set; }
    public static UnmanagedMemory CurrentTaskMemory { get; set; }

    public static int SysCall(int n, int[] args)
    {
        //Access to unmanaged memory here
        return 0;
    }
    public static int SysCall0(int n)
    {
        return SysCall(n, new int[0]);
    }
    public static int SysCall1(int n, int a)
    {
        return SysCall(n, new int[1] { a });
    }
    public static int SysCall2(int n, int a, int b)
    {
        return SysCall(n, new int[2] { a, b });
    }
    public static int SysCall3(int n, int a, int b, int c)
    {
        return SysCall(n, new int[3] { a, b, c });
    }
    public static int SysCall4(int n, int a, int b, int c, int d)
    {
        return SysCall(n, new int[4] { a, b, c, d });
    }
    public static int SysCall5(int n, int a, int b, int c, int d, int e)
    {
        return SysCall(n, new int[5] { a, b, c, d, e });
    }
    public static int SysCall6(int n, int a, int b, int c, int d, int e, int f)
    {
        return SysCall(n, new int[6] { a, b, c, d, e, f });
    }

    public static UnmanagedMemory GetMemory(){
        var um = new UnmanagedMemory(1, null);

        CurrentTaskMemory = um;

        return um;
    }

    public static MethodInfo GetMethod(string name)
    {
        var mi = typeof(ExecutorService).GetMethod(name);
        if (mi == null)
            throw new Exception("missing method " + name);
        return mi;
    }

    public static TaskResponse Execute(string b64)
    { 
        IsExecutingTask = true; 
        MemoryStream input = new MemoryStream(Convert.FromBase64String(b64));
        try
        {
            var instanceCreator = Compile.FromBinary<Program>(input, imports: new RuntimeImport[]
            { 
                new MemoryImport("env", "memory", GetMethod(nameof(GetMemory))),
                new FunctionImport("env", "__syscall0", GetMethod(nameof(SysCall0))),
                new FunctionImport("env", "__syscall1", GetMethod(nameof(SysCall1))),
                new FunctionImport("env", "__syscall2", GetMethod(nameof(SysCall2))),
                new FunctionImport("env", "__syscall3", GetMethod(nameof(SysCall3))),
                new FunctionImport("env", "__syscall4", GetMethod(nameof(SysCall4))),
                new FunctionImport("env", "__syscall5", GetMethod(nameof(SysCall5))),
                new FunctionImport("env", "__syscall6", GetMethod(nameof(SysCall6)))
            });
            using(var instance = instanceCreator()){ 
                var result = instance.Exports.main(task.Parameter); 
            } 
            IsExecutingTask = false;
            return result;
        }
        catch
        {
            IsExecutingTask = false;
            throw;
        }
    }

}

public abstract class Program
{
    public abstract int main(int value); 
}

I'm trying to imitate the behavoiur of this program: https://webassembly.studio/?f=lgcsyr30pfe . Unfortunately, the GetMemory method is never called. I'm running this code on UWP platform.

ghost commented 5 years ago

I've found a way of getting the memory by adding this line in the Program class public abstract UnmanagedMemory memory { get; }

RyanLamansky commented 5 years ago

Glad to hear it! It sounds like this program exports memory but your class didn't originally have a place for it to go.