Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e850ee9

Browse filesBrowse files
ShogunPandaaduh95
authored andcommitted
lib: add new methods and error codes
Signed-off-by: Paolo Insogna <paolo@cowtech.it> PR-URL: #62762 Reviewed-By: Xuguang Mei <meixuguang@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Bryan English <bryan@bryanenglish.com>
1 parent 98f9bec commit e850ee9
Copy full SHA for e850ee9

13 files changed

+459-117Lines changed: 459 additions & 117 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎benchmark/ffi/getpid.js‎

Copy file name to clipboard
+25Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff 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+
}
Collapse file

‎doc/api/errors.md‎

Copy file name to clipboardExpand all lines: doc/api/errors.md
+18Lines changed: 18 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -1332,6 +1332,24 @@ added: v14.0.0
13321332
Used when a feature that is not available
13331333
to the current platform which is running Node.js is used.
13341334

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+
13351353
<a id="ERR_FS_CP_DIR_TO_NON_DIR"></a>
13361354

13371355
### `ERR_FS_CP_DIR_TO_NON_DIR`
Collapse file

‎doc/api/ffi.md‎

Copy file name to clipboardExpand all lines: doc/api/ffi.md
+57-2Lines changed: 57 additions & 2 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,15 @@ const path = `libsqlite3.${suffix}`;
165165
added: REPLACEME
166166
-->
167167

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.
169170
* `definitions` {Object} Symbol definitions to resolve immediately.
170171
* Returns: {Object}
171172

172173
Loads a dynamic library and resolves the requested function definitions.
173174

175+
On Windows passing `null` is not supported.
176+
174177
When `definitions` is omitted, `functions` is returned as an empty object until
175178
symbols are resolved explicitly.
176179

@@ -237,10 +240,13 @@ Represents a loaded dynamic library.
237240

238241
### `new DynamicLibrary(path)`
239242

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.
241245

242246
Loads the dynamic library without resolving any functions eagerly.
243247

248+
On Windows passing `null` is not supported.
249+
244250
```cjs
245251
const { DynamicLibrary } = require('node:ffi');
246252

@@ -603,6 +609,55 @@ available storage. This function does not allocate memory on its own.
603609

604610
`buffer` must be a Node.js `Buffer`.
605611

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+
606661
## Safety notes
607662

608663
The `node:ffi` module does not track pointer validity, memory ownership, or
Collapse file

‎lib/ffi.js‎

Copy file name to clipboardExpand all lines: lib/ffi.js
+47-7Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22

33
const {
44
ObjectFreeze,
5+
ObjectPrototypeToString,
56
} = primordials;
67
const { Buffer } = require('buffer');
78
const { emitExperimentalWarning } = require('internal/util');
9+
const {
10+
isArrayBufferView,
11+
} = require('internal/util/types');
812
const {
913
codes: {
1014
ERR_ACCESS_DENIED,
@@ -32,6 +36,8 @@ const {
3236
getUint64,
3337
getFloat32,
3438
getFloat64,
39+
exportBytes,
40+
getRawPointer,
3541
setInt8,
3642
setUint8,
3743
setInt16,
@@ -114,21 +120,52 @@ function exportString(str, data, len, encoding = 'utf8') {
114120
targetBuffer.fill(0, dataLength, dataLength + terminatorSize);
115121
}
116122

117-
function exportBuffer(buffer, data, len) {
123+
function exportBuffer(source, data, len) {
118124
checkFFIPermission();
119125

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);
122128
}
123129

124130
validateInteger(len, 'len', 0);
125131

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);
128134
}
129135

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);
132169
}
133170

134171
const suffix = process.platform === 'win32' ? 'dll' : process.platform === 'darwin' ? 'dylib' : 'so';
@@ -163,6 +200,8 @@ module.exports = {
163200
dlopen,
164201
dlclose,
165202
dlsym,
203+
exportArrayBuffer,
204+
exportArrayBufferView,
166205
exportString,
167206
exportBuffer,
168207
getInt8,
@@ -175,6 +214,7 @@ module.exports = {
175214
getUint64,
176215
getFloat32,
177216
getFloat64,
217+
getRawPointer,
178218
setInt8,
179219
setUint8,
180220
setInt16,

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.