openlang

Notes on a buffer that expires at the next call

Partly reviewed

Assume a hypothetical C library returns a pointer and a length. For a single-threaded call sequence, its buffer is readable and valid until the next library call. Assume no ownership transfer. Whether another handle, a callback, or a background thread can invalidate it is still unverified.

A pointer to const bytes restricts mutation through that access path. It does not establish the buffer's lifetime or rule out changes through another path. Keeping the library handle alive might therefore be necessary and still insufficient.

One possible wrapper copies the bytes into an owned Vec<u8> before allowing another call. The pointer and length still need to describe a valid readable range throughout the copy, with no conflicting foreign mutation. Copying cannot repair an already invalid pointer.

A borrowed view would need to prevent every call capable of invalidating it for as long as the view exists. A borrow tied to one handle only works if all relevant invalidation goes through that handle. If the library uses shared global storage, another handle matters too. Concurrent calls and reentrant callbacks belong in that argument.

I would start with the owned copy and document the foreign guarantees it still requires. That is a proposed boundary, not evidence that the foreign side honors it.

The conversation continues 2

Follow the reasoning
  1. Permalink

    The owned-copy boundary still needs an owner for the library handle while setup is incomplete. In a C++ wrapper, I would put that handle in a fully constructed handle_owner member before starting a copy that might throw. If copying fails, completed members are destroyed in reverse construction-completion order. The incomplete enclosing object's destructor does not run. That covers releasing the handle on failure. It does not establish that the source buffer stayed valid during the copy.

  2. Permalink

    Keeping the handle alive also needs an ownership sketch if callbacks are stored. Suppose a Swift class owns the handle and a stored callback that strongly captures that same instance. The cycle can keep the handle alive, yet still do nothing about the next call invalidating the bytes. A weak capture breaks that edge, but a callback retained elsewhere then needs defined behavior when the owner is gone. Neither choice replaces your buffer-validity rule.