wasmtime-dotnet: Calling function with string arguments returns out of bounds memory error.

Seems like trying to load and call a function that uses pointers to access strings fails to access memory in either an exported or imported memory.

Example code:

            using var engine = new Engine();
            using var module = Module.FromFile(engine, "../../../wasm/bucketing-lib-debug.wasm");
            using var linker = new Linker(engine);
            using var store = new Store(engine);
            linker.Define(
                "env",
                "abort",
                Function.FromCallback(store, (int message, int filename, int linenum, int colnum) =>
                {
                    var inst = linker.Instantiate(store, module);
                    var mem = inst.GetMemory(store, "memory");

                    var messageStr = From64Bitstring(mem.ReadString(store, message, 1000));
                    var filenameStr = From64Bitstring(mem.ReadString(store, filename, 1000));
                    var lineNumStr = From64Bitstring(mem.ReadString(store, linenum, 1000));
                    var colNumStr = From64Bitstring(mem.ReadString(store, colnum, 1000));
                    Console.WriteLine(messageStr);
                    Console.WriteLine(filenameStr);
                    Console.WriteLine(lineNumStr);
                    Console.WriteLine(colNumStr);
                })
            );
            var memory = new Memory(store, 10);
            linker.Define("env", "memory", memory);
            
            var config = "{\"project\":{\"_id\":\"_project\"},\"environment\":{\"_id\":\"environment\"}}\0";
            var user = "{\"user_id\":\"test_id\"}";
            
            var configaddr = 0;
            
            
            var configBytesWritten = memory?.WriteString(store, configaddr, config);
            var useraddr = configaddr + configBytesWritten!;
            var userBytesWritten = memory?.WriteString(store, (int) useraddr, user);
            
            var instance = linker.Instantiate(store, module);
            //var memory = instance.GetMemory(store, "memory");
            
            
            dynamic generateBucketedConfig = instance.GetFunction(store, "generateBucketedConfig")!;


            if (configBytesWritten == null || userBytesWritten == null)
            {
                Console.Out.WriteLine("Failed to write to memory.");
                return;
            }

            var config2 = memory.ReadString(store, configaddr, (int) configBytesWritten);
            var user2 = memory.ReadString(store, (int) useraddr, (int) userBytesWritten);


            Console.Out.WriteLine("Config data: " + config2);
            Console.Out.WriteLine("user data: " + user2);
            var span = memory.GetSpan(store);
            var result = generateBucketedConfig?.Invoke(store, (int)configaddr, (int)useraddr);

            Console.WriteLine("generateBucketedConfig result: " + result);

WAT file of relevant function showing param usage via pointers:

(func $src/index/generateBucketedConfig (param $0 i32) (param $1 i32) (result i32)
  (local $2 i32)
  (local $3 i32)
  (local $4 i32)
  (local $5 i32)
  global.get $~lib/memory/__stack_pointer
  i32.const 12
  i32.sub
  global.set $~lib/memory/__stack_pointer
  call $~stack_check
  global.get $~lib/memory/__stack_pointer
  i64.const 0
  i64.store
  global.get $~lib/memory/__stack_pointer
  i32.const 0
  i32.store offset=8
  global.get $~lib/memory/__stack_pointer
  global.get $~lib/memory/__stack_pointer
  local.get $0
  local.set $2
  local.get $2
  call $~lib/assemblyscript-json/JSON/_JSON.parse<~lib/string/String>
  local.tee $2
  i32.store
  local.get $2
  i32.const 3
  call $~lib/rt/__instanceof
  if (result i32)
   local.get $2
  else
   i32.const 1184
   i32.const 2960
   i32.const 4
   i32.const 41
   call $~lib/builtins/abort
   unreachable
  end
  local.tee $2
  i32.store
  global.get $~lib/memory/__stack_pointer
  global.get $~lib/memory/__stack_pointer
  local.get $1
  local.set $3
  local.get $3
  call $~lib/assemblyscript-json/JSON/_JSON.parse<~lib/string/String>
  local.tee $3
  i32.store offset=4
  local.get $3
  i32.const 3
  call $~lib/rt/__instanceof
  if (result i32)
   local.get $3
  else
   i32.const 1184
   i32.const 2960
   i32.const 5
   i32.const 39
   call $~lib/builtins/abort
   unreachable
  end
  local.tee $3
  i32.store offset=4
  global.get $~lib/memory/__stack_pointer
  i32.const 0
  local.get $2
  call $src/index/BucketedUserConfig#constructor
  local.tee $4
  i32.store offset=8
  local.get $4
  call $src/index/BucketedUserConfig#stringify
  local.set $5
  global.get $~lib/memory/__stack_pointer
  i32.const 12
  i32.add
  global.set $~lib/memory/__stack_pointer
  local.get $5
 )

Error output:

Config data: {"project":{"_id":"_project"},"environment":{"_id":"environment"}}
user data: {"user_id":"test_id"}
Unhandled exception. Wasmtime.TrapException: wasm trap: out of bounds memory access
wasm backtrace:
    0:  0x36a - <unknown>!~lib/string/String.UTF8.byteLength
    1: 0x69f2 - <unknown>!~lib/string/String.UTF8.encode
    2: 0x1638 - <unknown>!~lib/string/String.UTF8.encode@varargs
    3: 0x6c0e - <unknown>!~lib/assemblyscript-json/util/index/Buffer.fromString
    4: 0x5f16 - <unknown>!~lib/assemblyscript-json/JSON/_JSON.parse<~lib/string/String>
    5: 0x7c4b - <unknown>!src/index/generateBucketedConfig
    6: 0x7f2d - <unknown>!export:src/index/generateBucketedConfig

   at Wasmtime.Function.Invoke(StoreContext context, ReadOnlySpan`1 arguments)
   at Wasmtime.Function.Invoke(IStore store, Object[] arguments)
   at System.Dynamic.UpdateDelegates.UpdateAndExecute4[T0,T1,T2,T3,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2, T3 arg3)
   at Example.Program.runWASM() in /Users/jamiesinn/git/dotnet-server-sdk/Example/Program.cs:line 75
   at Example.Program.Main(String[] args) in /Users/jamiesinn/git/dotnet-server-sdk/Example/Program.cs:line 12
   at Example.Program.<Main>(String[] args)

What are we doing wrong here? or is this an unsupported method of accessing a function?

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 15 (9 by maintainers)

Most upvoted comments

Awesome! Thanks!

We had issues enabling and finding the proper WASI config - it would always complain with not being able to find fd_write.

WASM is a new area for us - and this helps a ton in understanding how to use it!