| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 98f9bec commit e850ee9
13 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,25 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const common = require('../common.js'); | ||
| 4 | + const ffi = require('node:ffi'); | ||
| 5 | + | ||
| 6 | + const bench = common.createBenchmark(main, { | ||
| 7 | + n: [1e7], | ||
| 8 | + }, { | ||
| 9 | + flags: ['--experimental-ffi'], | ||
| 10 | + }); | ||
| 11 | + | ||
| 12 | + const { lib, functions } = ffi.dlopen(null, { | ||
| 13 | + uv_os_getpid: { result: 'i32', parameters: [] }, | ||
| 14 | + }); | ||
| 15 | + | ||
| 16 | + const getpid = functions.uv_os_getpid; | ||
| 17 | + | ||
| 18 | + function main({ n }) { | ||
| 19 | + bench.start(); | ||
| 20 | + for (let i = 0; i < n; ++i) | ||
| 21 | + getpid(); | ||
| 22 | + bench.end(n); | ||
| 23 | + | ||
| 24 | + lib.close(); | ||
| 25 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1332,6 +1332,24 @@ added: v14.0.0 | |||
| 1332 | 1332 | Used when a feature that is not available | |
| 1333 | 1333 | to the current platform which is running Node.js is used. | |
| 1334 | 1334 | ||
| 1335 | + <a id="ERR_FFI_CALL_FAILED"></a> | ||
| 1336 | + | ||
| 1337 | + ### `ERR_FFI_CALL_FAILED` | ||
| 1338 | + | ||
| 1339 | + A low-level FFI call failed. | ||
| 1340 | + | ||
| 1341 | + <a id="ERR_FFI_INVALID_POINTER"></a> | ||
| 1342 | + | ||
| 1343 | + ### `ERR_FFI_INVALID_POINTER` | ||
| 1344 | + | ||
| 1345 | + An invalid pointer was passed to an FFI operation. | ||
| 1346 | + | ||
| 1347 | + <a id="ERR_FFI_LIBRARY_CLOSED"></a> | ||
| 1348 | + | ||
| 1349 | + ### `ERR_FFI_LIBRARY_CLOSED` | ||
| 1350 | + | ||
| 1351 | + An operation was attempted on an FFI dynamic library after it was closed. | ||
| 1352 | + | ||
| 1335 | 1353 | <a id="ERR_FS_CP_DIR_TO_NON_DIR"></a> | |
| 1336 | 1354 | ||
| 1337 | 1355 | ### `ERR_FS_CP_DIR_TO_NON_DIR` | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -165,12 +165,15 @@ const path = `libsqlite3.${suffix}`; | |||
| 165 | 165 | added: REPLACEME | |
| 166 | 166 | --> | |
| 167 | 167 | ||
| 168 | - * `path` {string} Path to a dynamic library. | ||
| 168 | + * `path` {string|null} Path to a dynamic library, or `null` to resolve symbols | ||
| 169 | + from the current process image. | ||
| 169 | 170 | * `definitions` {Object} Symbol definitions to resolve immediately. | |
| 170 | 171 | * Returns: {Object} | |
| 171 | 172 | ||
| 172 | 173 | Loads a dynamic library and resolves the requested function definitions. | |
| 173 | 174 | ||
| 175 | + On Windows passing `null` is not supported. | ||
| 176 | + | ||
| 174 | 177 | When `definitions` is omitted, `functions` is returned as an empty object until | |
| 175 | 178 | symbols are resolved explicitly. | |
| 176 | 179 | ||
@@ -237,10 +240,13 @@ Represents a loaded dynamic library. | |||
| 237 | 240 | ||
| 238 | 241 | ### `new DynamicLibrary(path)` | |
| 239 | 242 | ||
| 240 | - * `path` {string} Path to a dynamic library. | ||
| 243 | + * `path` {string|null} Path to a dynamic library, or `null` to resolve symbols | ||
| 244 | + from the current process image. | ||
| 241 | 245 | ||
| 242 | 246 | Loads the dynamic library without resolving any functions eagerly. | |
| 243 | 247 | ||
| 248 | + On Windows passing `null` is not supported. | ||
| 249 | + | ||
| 244 | 250 | ```cjs | |
| 245 | 251 | const { DynamicLibrary } = require('node:ffi'); | |
| 246 | 252 | ||
@@ -603,6 +609,55 @@ available storage. This function does not allocate memory on its own. | |||
| 603 | 609 | ||
| 604 | 610 | `buffer` must be a Node.js `Buffer`. | |
| 605 | 611 | ||
| 612 | + ## `ffi.exportArrayBuffer(arrayBuffer, pointer, length)` | ||
| 613 | + | ||
| 614 | + <!-- YAML | ||
| 615 | + added: REPLACEME | ||
| 616 | + --> | ||
| 617 | + | ||
| 618 | + * `arrayBuffer` {ArrayBuffer} | ||
| 619 | + * `pointer` {bigint} | ||
| 620 | + * `length` {number} | ||
| 621 | + | ||
| 622 | + Copies bytes from an `ArrayBuffer` into native memory. | ||
| 623 | + | ||
| 624 | + `length` must be at least `arrayBuffer.byteLength`. | ||
| 625 | + | ||
| 626 | + `pointer` must refer to writable native memory with at least `length` bytes of | ||
| 627 | + available storage. This function does not allocate memory on its own. | ||
| 628 | + | ||
| 629 | + ## `ffi.exportArrayBufferView(arrayBufferView, pointer, length)` | ||
| 630 | + | ||
| 631 | + <!-- YAML | ||
| 632 | + added: REPLACEME | ||
| 633 | + --> | ||
| 634 | + | ||
| 635 | + * `arrayBufferView` {ArrayBufferView} | ||
| 636 | + * `pointer` {bigint} | ||
| 637 | + * `length` {number} | ||
| 638 | + | ||
| 639 | + Copies bytes from an `ArrayBufferView` into native memory. | ||
| 640 | + | ||
| 641 | + `length` must be at least `arrayBufferView.byteLength`. | ||
| 642 | + | ||
| 643 | + `pointer` must refer to writable native memory with at least `length` bytes of | ||
| 644 | + available storage. This function does not allocate memory on its own. | ||
| 645 | + | ||
| 646 | + ## `ffi.getRawPointer(source)` | ||
| 647 | + | ||
| 648 | + <!-- YAML | ||
| 649 | + added: REPLACEME | ||
| 650 | + --> | ||
| 651 | + | ||
| 652 | + * `source` {Buffer|ArrayBuffer|ArrayBufferView} | ||
| 653 | + * Returns: {bigint} | ||
| 654 | + | ||
| 655 | + Returns the raw memory address of JavaScript-managed byte storage. | ||
| 656 | + | ||
| 657 | + This is unsafe and dangerous. The returned pointer can become invalid if the | ||
| 658 | + underlying memory is detached, resized, transferred, or otherwise invalidated. | ||
| 659 | + Using stale pointers can cause memory corruption or process crashes. | ||
| 660 | + | ||
| 606 | 661 | ## Safety notes | |
| 607 | 662 | ||
| 608 | 663 | The `node:ffi` module does not track pointer validity, memory ownership, or | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,9 +2,13 @@ | |||
| 2 | 2 | ||
| 3 | 3 | const { | |
| 4 | 4 | ObjectFreeze, | |
| 5 | + ObjectPrototypeToString, | ||
| 5 | 6 | } = primordials; | |
| 6 | 7 | const { Buffer } = require('buffer'); | |
| 7 | 8 | const { emitExperimentalWarning } = require('internal/util'); | |
| 9 | + const { | ||
| 10 | + isArrayBufferView, | ||
| 11 | + } = require('internal/util/types'); | ||
| 8 | 12 | const { | |
| 9 | 13 | codes: { | |
| 10 | 14 | ERR_ACCESS_DENIED, | |
@@ -32,6 +36,8 @@ const { | |||
| 32 | 36 | getUint64, | |
| 33 | 37 | getFloat32, | |
| 34 | 38 | getFloat64, | |
| 39 | + exportBytes, | ||
| 40 | + getRawPointer, | ||
| 35 | 41 | setInt8, | |
| 36 | 42 | setUint8, | |
| 37 | 43 | setInt16, | |
@@ -114,21 +120,52 @@ function exportString(str, data, len, encoding = 'utf8') { | |||
| 114 | 120 | targetBuffer.fill(0, dataLength, dataLength + terminatorSize); | |
| 115 | 121 | } | |
| 116 | 122 | ||
| 117 | - function exportBuffer(buffer, data, len) { | ||
| 123 | + function exportBuffer(source, data, len) { | ||
| 118 | 124 | checkFFIPermission(); | |
| 119 | 125 | ||
| 120 | - if (!Buffer.isBuffer(buffer)) { | ||
| 121 | - throw new ERR_INVALID_ARG_TYPE('buffer', 'Buffer', buffer); | ||
| 126 | + if (!Buffer.isBuffer(source)) { | ||
| 127 | + throw new ERR_INVALID_ARG_TYPE('buffer', 'Buffer', source); | ||
| 122 | 128 | } | |
| 123 | 129 | ||
| 124 | 130 | validateInteger(len, 'len', 0); | |
| 125 | 131 | ||
| 126 | - if (len < buffer.length) { | ||
| 127 | - throw new ERR_OUT_OF_RANGE('len', `>= ${buffer.length}`, len); | ||
| 132 | + if (len < source.length) { | ||
| 133 | + throw new ERR_OUT_OF_RANGE('len', `>= ${source.length}`, len); | ||
| 128 | 134 | } | |
| 129 | 135 | ||
| 130 | - const targetBuffer = toBuffer(data, len, false); | ||
| 131 | - buffer.copy(targetBuffer, 0, 0, buffer.length); | ||
| 136 | + exportBytes(source, data, len); | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + function exportArrayBuffer(source, data, len) { | ||
| 140 | + checkFFIPermission(); | ||
| 141 | + | ||
| 142 | + if (ObjectPrototypeToString(source) !== '[object ArrayBuffer]') { | ||
| 143 | + throw new ERR_INVALID_ARG_TYPE('arrayBuffer', 'ArrayBuffer', source); | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + validateInteger(len, 'len', 0); | ||
| 147 | + | ||
| 148 | + if (len < source.byteLength) { | ||
| 149 | + throw new ERR_OUT_OF_RANGE('len', `>= ${source.byteLength}`, len); | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + exportBytes(source, data, len); | ||
| 153 | + } | ||
| 154 | + | ||
| 155 | + function exportArrayBufferView(source, data, len) { | ||
| 156 | + checkFFIPermission(); | ||
| 157 | + | ||
| 158 | + if (!isArrayBufferView(source)) { | ||
| 159 | + throw new ERR_INVALID_ARG_TYPE('arrayBufferView', 'ArrayBufferView', source); | ||
| 160 | + } | ||
| 161 | + | ||
| 162 | + validateInteger(len, 'len', 0); | ||
| 163 | + | ||
| 164 | + if (len < source.byteLength) { | ||
| 165 | + throw new ERR_OUT_OF_RANGE('len', `>= ${source.byteLength}`, len); | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + exportBytes(source, data, len); | ||
| 132 | 169 | } | |
| 133 | 170 | ||
| 134 | 171 | const suffix = process.platform === 'win32' ? 'dll' : process.platform === 'darwin' ? 'dylib' : 'so'; | |
@@ -163,6 +200,8 @@ module.exports = { | |||
| 163 | 200 | dlopen, | |
| 164 | 201 | dlclose, | |
| 165 | 202 | dlsym, | |
| 203 | + exportArrayBuffer, | ||
| 204 | + exportArrayBufferView, | ||
| 166 | 205 | exportString, | |
| 167 | 206 | exportBuffer, | |
| 168 | 207 | getInt8, | |
@@ -175,6 +214,7 @@ module.exports = { | |||
| 175 | 214 | getUint64, | |
| 176 | 215 | getFloat32, | |
| 177 | 216 | getFloat64, | |
| 217 | + getRawPointer, | ||
| 178 | 218 | setInt8, | |
| 179 | 219 | setUint8, | |
| 180 | 220 | setInt16, | |
| Back | FazBrowse Home | New Git URL |
0 commit comments