| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 58dc92f commit 53eb7ab
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -194,6 +194,7 @@ void DynamicLibrary::CleanupFunctionInfo( | |||
| 194 | 194 | FFIFunctionInfo* info = data.GetParameter(); | |
| 195 | 195 | info->fn.reset(); | |
| 196 | 196 | info->self.Reset(); | |
| 197 | + info->library.Reset(); | ||
| 197 | 198 | delete info; | |
| 198 | 199 | } | |
| 199 | 200 | ||
@@ -313,6 +314,7 @@ MaybeLocal<Function> DynamicLibrary::CreateFunction( | |||
| 313 | 314 | } | |
| 314 | 315 | ||
| 315 | 316 | info->self.Reset(isolate, ret); | |
| 317 | + info->library.Reset(isolate, object()); | ||
| 316 | 318 | info->self.SetWeak(info.release(), | |
| 317 | 319 | DynamicLibrary::CleanupFunctionInfo, | |
| 318 | 320 | WeakCallbackType::kParameter); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -33,6 +33,8 @@ struct FFIFunctionInfo { | |||
| 33 | 33 | std::shared_ptr<FFIFunction> fn; | |
| 34 | 34 | v8::Global<v8::Function> self; | |
| 35 | 35 | std::shared_ptr<v8::BackingStore> sb_backing; | |
| 36 | + // Keep the owning DynamicLibrary alive while the generated function is alive. | ||
| 37 | + v8::Global<v8::Object> library; | ||
| 36 | 38 | }; | |
| 37 | 39 | ||
| 38 | 40 | struct FFICallback { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,7 +1,8 @@ | |||
| 1 | - // Flags: --experimental-ffi | ||
| 1 | + // Flags: --experimental-ffi --expose-gc | ||
| 2 | 2 | 'use strict'; | |
| 3 | 3 | const common = require('../common'); | |
| 4 | 4 | common.skipIfFFIMissing(); | |
| 5 | + const { gcUntil } = require('../common/gc'); | ||
| 5 | 6 | const assert = require('node:assert'); | |
| 6 | 7 | const { test } = require('node:test'); | |
| 7 | 8 | const ffi = require('node:ffi'); | |
@@ -117,6 +118,27 @@ test('getFunction caches signatures consistently', () => { | |||
| 117 | 118 | } | |
| 118 | 119 | }); | |
| 119 | 120 | ||
| 121 | + test('FFI functions keep their owning library alive', async () => { | ||
| 122 | + let lib = new ffi.DynamicLibrary(libraryPath); | ||
| 123 | + const addI32 = lib.getFunction('add_i32', fixtureSymbols.add_i32); | ||
| 124 | + const ref = new WeakRef(lib); | ||
| 125 | + | ||
| 126 | + lib = null; | ||
| 127 | + | ||
| 128 | + for (let i = 0; i < 5; i++) { | ||
| 129 | + await gcUntil( | ||
| 130 | + 'FFI function keeps its owning library alive', | ||
| 131 | + () => true, | ||
| 132 | + 1, | ||
| 133 | + ); | ||
| 134 | + assert.ok(ref.deref() instanceof ffi.DynamicLibrary); | ||
| 135 | + assert.strictEqual(addI32(20, 22), 42); | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + ref.deref().close(); | ||
| 139 | + assert.throws(() => addI32(20, 22), /Library is closed/); | ||
| 140 | + }); | ||
| 141 | + | ||
| 120 | 142 | test('closed libraries reject subsequent operations', () => { | |
| 121 | 143 | const { lib, functions } = ffi.dlopen(libraryPath, { | |
| 122 | 144 | add_i32: fixtureSymbols.add_i32, | |
| Back | FazBrowse Home | New Git URL |
0 commit comments