schemeracketchez-scheme

How to retrieve a foreign raw bytes pointer from a scheme bytevector?


Scheme provides a bytevector type which can be used to do low-level operations on bytes abd array of bytes (see r6rs and chez manual). However, it does not seem to provide a way to retrieve the underlying pointer to the array of bytes it is storing and I need that pointer to pass to foreign C functions to fill or read data from the bytevector.

To be more precise about the context, I am trying to write some code for low-level handling of bytes in Idris2 which is using Scheme as its backend, but I am a newbie in Scheme so I am certainly overlooking something obvious: What's the preferred approach to extract this pointer from the bytevector?


Solution

  • An operation that returned a bytevector's address as an integer would be dangerously unsafe, since the garbage collector might subsequently move the bytevector and place other objects there. Passing a stale address to C code could cause memory corruption.

    The docs for Chez Scheme's foreign-procedure say that an argument declared as u8* accepts a bytevector and passes the address of its contents to the foreign function. That's safe, because the FFI and GC cooperate to make sure the object is not moved between taking the address and calling the foreign function --- but see the warning about retaining the pointer in foreign data structures. See also lock-object, which temporarily prevents the GC from moving or reclaiming an object.

    In Racket, the _bytes and _pointer foreign types work similarly. There's also a ptr-add operation that combines a pointer-like object with an offset. For example, if bs is a bytestring, then (ptr-add bs 1 _byte) is reliably converted to the address of the second byte of bs, even if the GC moves bs. I don't know if Chez has a similar feature.