Commit43283237Recorded15 Jul 2026Repositorysigil-ffi
ffi: never dlclose a library from the GC finalizer
Message
Unloading a shared library when its handle object is garbage-collected is unsound: the GC only knows the handle is unreachable, not whether C code still holds raw pointers into the library (c-function fnptrs, callbacks registered with GLib main-context sources or signal handlers, atexit handlers, static data). Collecting a let-bound library handle in a dev-bundle build dlclosed libgtk-4 out from under a live GMainContext and crashed the next gmaincontextiteration. Python ctypes, JNA, and Guile all keep libraries mapped until process exit for the same reason. Explicit c-library-close remains for callers who know nothing references the library.
Bump 0.16.3.
Changed
native/ffi.c | 17 ++++++++++++++---
package.sgl | 2 +-
2 files changed, 15 insertions(+), 4 deletions(-)Diff
native/ffi.cmodified
@@ -478,9 +478,20 @@ static void library_finalizer(void *data)
478
{ 479
FfiLibrary *lib = (FfiLibrary *)data; 480
if (lib) {−481
if (!lib->closed && lib->handle) {−482
ffi_close_library(lib->handle);−483
}+481
/* Deliberately do NOT dlclose here. Unloading a shared library+482
* when its handle object is garbage-collected is unsound: the GC+483
* only knows the handle is unreachable, not whether the program+484
* (or C code acting on its behalf) still holds raw pointers into+485
* the library - c-function fn_ptrs, callbacks registered with C+486
* event loops (GLib main-context sources, signal handlers),+487
* atexit handlers, static data. dlclose on collection unmapped+488
* libgtk-4 out from under a live GMainContext and crashed the+489
* next g_main_context_iteration (dev-bundle builds collect dead+490
* locals promptly, so a let-bound handle died while its library+491
* was still in use). Every mainstream FFI (Python ctypes, JNA,+492
* Guile) keeps libraries mapped until process exit for the same+493
* reason. Explicit c-library-close remains available for callers+494
* who KNOW nothing references the library. */ 495
free(lib->name); 496
free(lib); 497
}package.sglmodified
@@ -6,7 +6,7 @@
6
7
(package 8
name: "sigil-ffi"−9
version: "0.16.2"+9
version: "0.16.3" 10
sigil: "^0.17" 11
description: "Dynamic foreign function interface for Sigil" 12
url: "https://codeberg.org/sigil/sigil-ffi"