fluffos/tools/ffi/test_sample.h
Yucong Sun 9be761aa00 package_ffi: foreign function interface for LPC (libffi), with callbacks
Fully implements the docs/driver/ffi-plan.md design. LPC can now load
native shared libraries, call C functions whose signatures are described
at runtime, manage native memory, pass in/out parameters, and expose LPC
function pointers to C as callbacks.

Package (src/packages/ffi, option PACKAGE_FFI ON, libffi via pkg-config):
- ffi_load/unload/symbol; ffi_prepare/ffi_call (ffi_prep_cif + ffi_call);
  ffi_alloc/free/sizeof/peek/address; ffi_read/write; ffi_struct_layout;
  ffi_callback/ffi_callback_addr/ffi_callback_free (libffi closures that
  re-enter the VM via safe_call_function_pointer); ffi_error/ffi_status.
- Buffers are the currency for all pointer/byte data; raw pointer VALUES
  (returned pointers, buffer/callback addresses) are ints. LPC strings
  are UTF-8-native and never implicitly marshalled -- a char* is a
  buffer the caller encoded (pinned by ffi_string.lpc).
- Native allocations are LPC buffers (GC-tracked); handle tables freed at
  shutdown (ffi_cleanup) and marked for DEBUGMALLOC (mark_ffi).

Security: master apply valid_ffi(op, arg, caller) gates every
load/symbol/prepare/callback (VALID_FFI added to the applies table); a
missing apply denies by default. Optional "ffi allowed libraries" config
allow-list (rc.cc + runtime_config.h + regenerated config.md, new
Security category). __PACKAGE_FFI__ predefine added.

tools/ffi/generate.py: turns a C header into LPC bindings (buffer params
for char*, optional --string-convenience UTF-8 overloads) plus a struct
layout include; reports+skips unsupported forms; --emit-json contract.
Dependency-free test.py.

Tests: 20 testsuite/single/tests/efuns/ffi_*.lpc (every efun, the qsort
callback round trip, the generated-bindings end-to-end path), guarded by
__PACKAGE_FFI__ with a libc-reachability probe. The efuns are VM-stack-
based, so the LPC testsuite is the surface -- libffi's call/closure paths
run there under ASan/UBSan and the per-file check_memory leak gate.

The clang RelWithDebInfo sanitizer caught an error()-unwind leak: both
ffi_prepare and ffi_callback allocated before a code_to_type() that can
error() -- now unique_ptr/custom-deleter owned (AGENTS.md section 4).

Verified: testsuite x3 (ASan Debug) + ctest 297, RelWithDebInfo suite x3
+ ctest 298, clang RelWithDebInfo sanitizer (leak-clean), tools/ffi
test.py.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 20:48:48 -04:00

25 lines
666 B
C

/* Sample header for tools/ffi/test.py -- exercises the generator's C
* subset: scalar/pointer/string params, void return, structs, and the
* unsupported forms it must skip. */
extern double sqrt(double x);
extern double pow(double base, double exp);
int abs(int n);
size_t strlen(const char *s);
void qsort(void *base, size_t nmemb, size_t size, void *compar);
/* Unsupported: variadic and a raw function-pointer parameter -- both
* must be reported and skipped, never mis-bound. */
int printf(const char *fmt, ...);
void set_handler(int (*cb)(int));
struct Point {
int x;
int y;
};
struct Mixed {
char tag;
double value;
short flags;
};