mirror of
https://github.com/fluffos/fluffos
synced 2026-08-12 18:26:06 -04:00
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>
40 lines
1.2 KiB
C
40 lines
1.2 KiB
C
/*
|
|
* ffi.h -- type codes for the FFI package (package_ffi).
|
|
*
|
|
* Copy this file to your mudlib include dir. The codes describe the C
|
|
* type of an argument or return value to ffi_prepare()/ffi_call() and
|
|
* the scalar type for ffi_read()/ffi_write(). See docs/driver/ffi-plan.md.
|
|
*
|
|
* The boundary is BYTES: LPC strings are UTF-8-native and are NEVER
|
|
* marshalled implicitly to C char*. All pointer/data crosses as a
|
|
* `buffer`; encode with string_encode()/decode with string_decode().
|
|
*/
|
|
|
|
#ifndef _FFI_H_
|
|
#define _FFI_H_
|
|
|
|
#define FFI_VOID 0
|
|
#define FFI_INT8 1
|
|
#define FFI_UINT8 2
|
|
#define FFI_INT16 3
|
|
#define FFI_UINT16 4
|
|
#define FFI_INT32 5
|
|
#define FFI_UINT32 6
|
|
#define FFI_INT64 7
|
|
#define FFI_UINT64 8
|
|
#define FFI_FLOAT 9 /* C float <-> LPC float */
|
|
#define FFI_DOUBLE 10 /* C double <-> LPC float */
|
|
/*
|
|
* A pointer. As an ARGUMENT: pass a buffer; the native pointer is the
|
|
* buffer's bytes (whatever encoding you put there). As a RETURN: an
|
|
* integer holding the raw address -- copy from it with ffi_peek().
|
|
*/
|
|
#define FFI_POINTER 11
|
|
|
|
/* Native C int/long widths (resolved to fixed sizes at build time). */
|
|
#define FFI_INT FFI_INT32
|
|
#define FFI_UINT FFI_UINT32
|
|
#define FFI_LONG FFI_INT64
|
|
#define FFI_ULONG FFI_UINT64
|
|
|
|
#endif /* _FFI_H_ */
|