ffi: load libraries from a mounted VFS - #65909
Conversation
The dlopen hook installed while a VFS is mounted always forwarded its flags parameter, so a two-argument process.dlopen() call for a real file system path reached the original implementation with `undefined` as the flags. That coerces to 0, which is not a valid dlopen(2) mode, instead of applying the default flags, and loading any addon from the real file system failed with EINVAL while a VFS was mounted. Signed-off-by: Matteo Collina <hello@matteocollina.com>
|
LETM (Looks Excellent To Me 😃 ) |
|
The only question I have is whether we want to hide the detail that the path may need materializing inside And since |
fa3e51d to
dd7d5f0
Compare
|
@pipobscure updated, PTAL |
The operating system's dynamic loader cannot open a library that lives in a mounted virtual file system: the reserved mount path has no real inode. Native addons already handle this in require(): the loader hands their bytes to process.dlopen(), which loads them from a private, self-cleaning image - an anonymous in-memory memfd on Linux. Make ffi.dlopen() and new DynamicLibrary() do the same transparently. Mirroring the fs handler integration, the VFS hook installer sets a library reader into node:ffi while at least one VFS is mounted and clears it when the last one unmounts; DynamicLibrary consults it before every load, so the dependency points from the VFS into ffi and ffi never loads any VFS code. The reader hands the library's bytes to the native constructor, which loads them from the same kind of image, released right after the load, while library.path keeps reporting the virtual path. Libraries on the real file system are unaffected and load directly, and pay only a null check while no VFS is mounted. Since the load happens inside the constructor, the image never outlives the call: nothing is left for dlclose() to clean up and no temporary file lingers on POSIX. The AddonImage materializer moves from an anonymous namespace in node_binding.cc to node_binding.h so that node_ffi.cc can reuse it. Signed-off-by: Matteo Collina <hello@matteocollina.com>
dd7d5f0 to
c994e3d
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #65909 +/- ##
==========================================
+ Coverage 90.16% 90.19% +0.03%
==========================================
Files 771 773 +2
Lines 265097 265287 +190
Branches 50358 50404 +46
==========================================
+ Hits 239026 239284 +258
+ Misses 17011 16954 -57
+ Partials 9060 9049 -11
🚀 New features to boost your workflow:
|
The operating system's dynamic loader cannot open a library that lives in a mounted virtual file system: the reserved mount path has no real inode. Native addons already handle this in
require(): the loader hands their bytes toprocess.dlopen(), which loads them from a private, self-cleaning image — an anonymous in-memory memfd on Linux.This makes
ffi.dlopen()andnew ffi.DynamicLibrary()do the same, transparently:setVfsHandlers), the VFS hook installer sets a library reader intonode:ffiwhile at least one VFS is mounted and clears it when the last one unmounts, so the dependency points from the VFS into ffi and ffi never loads any VFS code. The reader hands the library's bytes to the native constructor, which loads them from the same kind of private image (AddonImage, moved from an anonymous namespace innode_binding.cctonode_binding.hsonode_ffi.cccan reuse it).library.pathkeeps reporting the virtual path.uv_dlopen()on POSIX (in-memory memfd on Linux, so nothing touches the file system at all), and there is nothing left fordlclose()to clean up or reference-count. Windows retains the delete-on-close handle for the process lifetime, exactly as for addons.dlopenBinary().Bug fix included
Writing the test exposed a pre-existing bug, fixed in the first commit: the dlopen hook installed while a VFS is mounted always forwarded its
flagsparameter, so a two-argumentprocess.dlopen()call for a real file-system path reached the original implementation withundefinedas the flags. That coerces to0, which is not a validdlopen(2)mode, and loading any addon from the real file system failed with EINVAL while a VFS was mounted.