|
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, |
|
0 commit comments