5 Commits

Author SHA1 Message Date
Ivan FB
ad493d6f9d
feat(ffi): cross struct/seq/Option params natively via POD
The native (zero-serialization) path previously handed `{.ffi.}` struct
params to the FFI thread using the Nim object layout (GC'd `string` fields),
which does not match the C-POD layout the generated header declares — an ABI
mismatch that left struct-param procs uncallable from C and skipped by the Go
codegen.

Wire the generated POD machinery into both the `{.ffi.}` and `{.ffiCtor.}`
native paths: a registered `{.ffi.}` struct now travels as its `<T>Pod`
mirror — `clonePod` deep-copies it off the caller's buffers into shared
(`c_malloc`) memory on the caller thread, `podToNim` rebuilds the Nim value on
the FFI thread, and `freePod` releases it from the CArgs free proc. `string`
collapses to `cstring` (alloc/ffiCFree); scalars copy direct. New classifiers
(`nativeWireType` / `nativeArgCopyStmt` / `nativeArgUnpackStmt`) keep both
paths and the CArgs alloc/free in lockstep so ownership can't drift.

The load-bearing invariant: the `<T>Pod` `{.bycopy.}` layout is identical to
the C struct emitted by `codegen/c.emitCStructs`, so the `exportc` symbol's
ABI matches the header even though Nim's own struct name differs. Keep the two
emitters in sync.

Validated end-to-end from C (TimerConfig, EchoRequest, and a nested
ComplexRequest with seq-of-structs, seq-of-strings and two Options) and clean
under ASAN. Struct *returns* still travel as CBOR on the native path; that is
left for a follow-up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 18:37:05 +02:00
Ivan FB
f3206c30b8
feat(ffi): emit a native (zero-serialization) C ABI alongside CBOR
A single {.ffi.} definition now produces BOTH interfaces, chosen by the
caller at link time rather than by a global compile flag:

- `<name>`      — native typed-arg C export. Args travel to the FFI thread in
                  a c_malloc'd C-POD struct passed by pointer (no CBOR), and the
                  result is delivered to the callback as raw bytes. This is the
                  preferred path for same-process callers: no serialization on
                  either side.
- `<name>_cbor` — the existing CBOR-buffer dispatcher, kept for generic /
                  cross-language callers.

Both share the user's helper proc; they register distinct handlers keyed by
"<Camel>Req" (CBOR) and "<Camel>ReqNative". FFIThreadRequest gains a `cborMode`
flag and a `payloadFree` hook so the native C-POD payload (which owns duplicated
cstring fields) is released correctly and an empty native result is delivered as
a zero-length buffer instead of the CBOR null sentinel. alloc.nim gains
ffiCMalloc/ffiCFree (prefixed to avoid Nim's style-insensitive clash with
ansi_c.c_malloc/c_free).

Verified end-to-end on a scalar-param lib: native calls return raw strings
("calc v1", "sum=42"); the _cbor variant still returns CBOR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 02:02:39 +02:00
Gabriel Cruz
ee472f05ad
chore(ci): fsanitize tests (#34) 2026-05-20 14:14:42 -03:00
Ivan FB
df2277e726
Fix memleaks (#11)
* protect against mem leak in case of failures sending requests to ffi thread
* better cleanup if failures in createFFIContext
* avoid dangling cstring in handleRes under ARC/ORC
* better resource cleanup in destroyFFIContext
* invoke onNotResponding if failure in destroyFFIContext
* correct seq copy in alloc
* make sure the lock is init before cleanUpResources
* better possible exception handling in processReq
* guard allocSharedSeq if given seq is empty
* enhance error handling in ffi_context
* add new tests and some corrections
2026-04-27 21:22:45 +02:00
Ivan Folgueira Bande
bbddf6925b
First commit 2025-09-17 14:37:11 +02:00