wasmtime-py icon indicating copy to clipboard operation
wasmtime-py copied to clipboard

Setting a slice of memory without having to enumerate

Open dsyer opened this issue 3 years ago • 3 comments

It's nice that the WASM memory can be inspected with a slice operator:

from wasmtime import *
engine = Engine()
store = Store(engine)
module = Module.from_file(engine, "./hello.wasm")
instance = Instance(store, module, [])
exports = instance.exports(store)
memory = exports["memory"]

Then

>>> memory.data_ptr(store)[1024:1029]
[114, 97, 116, 115, 0]

but it's not possible to set it that way which seems like a bug, or at least a missing feature:

>>> data = memory.data_ptr(store)
>>> data[1024:1028] = [114, 97, 116, 116]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sequence index must be integer, not 'slice'

You can work around it by iterating:

for i,v in enumerate("fats".encode('utf-8')): data[i] = v

dsyer avatar Feb 17 '22 10:02 dsyer

Ah sorry I don't know much about python bulk array assignment, but if a different type should be returned by the methods here that's more idiomatic that seems like a reasonable thing to do!

alexcrichton avatar Feb 17 '22 15:02 alexcrichton

Agree, but I have no idea how to achieve it. All I know is bulk assignment works with an actual list of bytes, and wasmtime._memory.Memory .data_ptr() is masquerading as a list of bytes. So it should be possible.

dsyer avatar Feb 17 '22 16:02 dsyer

This seems to work:

>>> import ctypes
>>> data = (ctypes.c_ubyte*memory.data_len(store)).from_address(ctypes.addressof(memory.data_ptr(store).contents))
>>> data[0:10] = "helloworld".encode('utf-8')
>>> data[0:10]
[104, 101, 108, 108, 111, 119, 111, 114, 108, 100]
>>> memory.data_ptr(store)[0:10]
[104, 101, 108, 108, 111, 119, 111, 114, 108, 100]

dsyer avatar Feb 17 '22 16:02 dsyer

I've also been playing around with wasmtime, got a toy program running but I was reading and writing memory one byte at a time.

Glad to see there's a bulk read method available (it didn't occur to me to use a slice), a bulk write would also be very welcome!

Tinche avatar Dec 09 '22 16:12 Tinche

Playing around with this a little more, memory.data_ptr(store)[:res_length] returns an actual list of integer objects. You can call bytes on it, but it's very inefficient. Realistically no one's going to be treating this as a list of integers, so I'd suggest changing the API to just return a bytes or bytearray instance directly.

Tinche avatar Dec 09 '22 16:12 Tinche