ffibridge

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 4, 2026 License: BSD-3-Clause Imports: 9 Imported by: 0

Documentation

Overview

Package ffibridge is the host side of f4's foreign function interface.

It turns a textual C prototype plus a list of plain values into a real native call, so that a sandboxed plugin can reach host APIs without f4 shipping a hand-written wrapper for every function in every system library. Everything crossing the sandbox boundary is an integer, a float or a string: library handles, function pointers, memory blocks and callbacks are all plain addresses, which maps equally well onto Lua and onto wasm imports.

The bridge is built on pureffi (a purego-compatible, cgo-free FFI). Because purego's RegisterFunc is fully reflective, the Go function type matching a prototype is constructed at run time, which is what makes dynamic calls with floats, structs and C-variadic arguments possible at all.

Security: FFI inside a sandbox is, by construction, an escape hatch from that sandbox. Options.Allow is the single choke point where the permission model will be enforced; until it is wired up, leaving it nil allows everything, which is appropriate only for local development.

Index

Constants

View Source
const DefaultMaxAlloc = 64 << 20

DefaultMaxAlloc caps bridge-owned memory when Options.MaxAlloc is zero.

View Source
const Supported = true

Supported reports whether this build can make native calls. Building with the noffi tag, or on a platform pureffi does not cover, leaves the rest of the plugin machinery intact and only disables the escape hatch.

Variables

View Source
var (
	// ErrUnsupported is returned when the platform or the build has no FFI.
	ErrUnsupported = errors.New("ffibridge: FFI is not available in this build")
	// ErrClosed is returned once the owning plugin has been torn down.
	ErrClosed = errors.New("ffibridge: bridge is closed")
)

Functions

func LibCNames

func LibCNames() []string

LibCNames lists the usual names of the platform's C runtime, most likely first. It exists so that plugins and tests have one portable way to reach the functions everybody expects to be there.

Types

type Bridge

type Bridge struct {
	// contains filtered or unexported fields
}

Bridge is one sandbox's view of the host FFI. Each plugin gets its own, so that tearing the plugin down releases its libraries and memory. A Bridge is safe for concurrent use.

func New

func New(opts Options) *Bridge

New creates an empty bridge.

func (*Bridge) Alloc

func (b *Bridge) Alloc(size int) (uintptr, error)

Alloc reserves a zeroed block and returns its address.

func (*Bridge) Bytes

func (b *Bridge) Bytes(addr uintptr) ([]byte, error)

Bytes exposes a bridge-owned block for direct host-side access. Writes through the returned slice are visible to native code.

func (*Bridge) CString

func (b *Bridge) CString(s string) (uintptr, error)

CString allocates a NUL terminated copy of s and returns its address.

func (*Bridge) Call

func (b *Bridge) Call(fn uintptr, sig string, args ...any) (any, error)

Call invokes a native function described by a signature.

func (*Bridge) CallSig

func (b *Bridge) CallSig(fn uintptr, sig *Signature, args []any) (result any, err error)

CallSig is Call with an already parsed signature, which avoids re-parsing on hot paths.

func (*Bridge) CallSym

func (b *Bridge) CallSym(lib uintptr, name, sig string, args ...any) (any, error)

CallSym resolves a symbol and calls it in one step.

func (*Bridge) Close

func (b *Bridge) Close() error

Close releases every library and memory block the bridge owns. Callbacks are intentionally kept alive: native code may still hold their addresses, and there is no portable way to revoke a trampoline.

func (*Bridge) CloseLib

func (b *Bridge) CloseLib(lib uintptr) error

CloseLib unloads a single library.

func (*Bridge) Free

func (b *Bridge) Free(addr uintptr) error

Free releases a block previously returned by Alloc or CString.

func (*Bridge) GoStringAt

func (b *Bridge) GoStringAt(addr uintptr) (string, error)

GoStringAt reads a NUL terminated string from an arbitrary address.

func (*Bridge) NewCallback

func (b *Bridge) NewCallback(sig string, fn Callback) (uintptr, error)

NewCallback builds a native function pointer that dispatches into fn. The address stays valid for the lifetime of the bridge; there is no portable way to revoke a trampoline, so callbacks are never reclaimed early.

func (*Bridge) Open

func (b *Bridge) Open(name string) (uintptr, error)

Open loads a shared library and returns its handle.

func (*Bridge) OpenLibC

func (b *Bridge) OpenLibC() (uintptr, error)

OpenLibC opens the first C runtime it can find.

func (*Bridge) Peek

func (b *Bridge) Peek(addr uintptr, n int) ([]byte, error)

Peek reads raw memory at an arbitrary address. It is unchecked by nature: a bad address crashes the process, exactly as it would in C.

func (*Bridge) Poke

func (b *Bridge) Poke(addr uintptr, data []byte) error

Poke writes raw memory at an arbitrary address.

func (*Bridge) Read

func (b *Bridge) Read(addr uintptr, off, n int) ([]byte, error)

Read copies bytes out of a bridge-owned block.

func (*Bridge) Sym

func (b *Bridge) Sym(lib uintptr, name string) (uintptr, error)

Sym resolves a symbol in a library previously opened through this bridge.

func (*Bridge) Write

func (b *Bridge) Write(addr uintptr, off int, data []byte) error

Write copies data into a bridge-owned block at the given offset.

type Callback

type Callback func(args []any) (any, error)

Callback is the sandbox-facing shape of a native callback body. Arguments arrive normalised the same way call results are, and the returned value is converted back according to the signature's return type.

type Kind

type Kind uint8

Kind is one primitive type of the ffibridge signature mini-language.

The language deliberately has no C type names, no typedefs and no declaration parser: a sandboxed plugin describes the ABI it wants, not the C source it came from. A cdef-style parser may be layered on top later.

const (
	KindVoid Kind = iota
	KindBool
	KindI8
	KindU8
	KindI16
	KindU16
	KindI32
	KindU32
	KindI64
	KindU64
	KindF32
	KindF64
	KindPtr
	KindStr
)

func ParseKind

func ParseKind(name string) (Kind, bool)

ParseKind resolves a type name used in a signature.

func (Kind) String

func (k Kind) String() string

String returns the name this kind has inside a signature.

type Op

type Op string

Op names an operation the bridge can be asked to perform. It is the unit of granularity the permission model works with.

const (
	OpOpen     Op = "open"
	OpSym      Op = "sym"
	OpCall     Op = "call"
	OpAlloc    Op = "alloc"
	OpPeek     Op = "peek"
	OpPoke     Op = "poke"
	OpCallback Op = "callback"
)

type Options

type Options struct {
	// Allow, when not nil, is consulted before every operation. A non-nil
	// error aborts the operation and is returned to the caller verbatim.
	Allow func(op Op, detail string) error

	// MaxAlloc caps the total size of live blocks allocated through the
	// bridge. Zero means DefaultMaxAlloc.
	MaxAlloc int64
}

Options configures one bridge instance.

type Signature

type Signature struct {
	Text     string
	Ret      Kind
	Args     []Kind
	Variadic bool
	// contains filtered or unexported fields
}

Signature is one parsed C prototype written in the mini-language:

<ret>(<arg>, <arg>, ...)

Examples:

i64(str)              size_t strlen(const char *)
ptr(ptr,ptr,i64)      void *memcpy(void *, const void *, size_t)
void(ptr,i64,i64,ptr) void qsort(void *, size_t, size_t, cmp *)
i32(ptr,str,...)      int sprintf(char *, const char *, ...)

An empty or "void" argument list means no arguments. A trailing "..." marks a true C-variadic function; the types of the variadic arguments are then derived from the Go values passed at call time.

func ParseSignature

func ParseSignature(text string) (*Signature, error)

ParseSignature parses a signature and caches the result. Parsed signatures are immutable and safe for concurrent use.

func (*Signature) FuncType

func (s *Signature) FuncType() reflect.Type

FuncType is the Go function type this signature is dispatched through.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL