koffi 2.8.4 → 2.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/README.md +6 -0
- package/build/koffi/darwin_arm64/koffi.node +0 -0
- package/build/koffi/darwin_x64/koffi.node +0 -0
- package/build/koffi/freebsd_arm64/koffi.node +0 -0
- package/build/koffi/freebsd_ia32/koffi.node +0 -0
- package/build/koffi/freebsd_x64/koffi.node +0 -0
- package/build/koffi/linux_arm32hf/koffi.node +0 -0
- package/build/koffi/linux_arm64/koffi.node +0 -0
- package/build/koffi/linux_ia32/koffi.node +0 -0
- package/build/koffi/linux_riscv64hf64/koffi.node +0 -0
- package/build/koffi/linux_x64/koffi.node +0 -0
- package/build/koffi/openbsd_ia32/koffi.node +0 -0
- package/build/koffi/openbsd_x64/koffi.node +0 -0
- package/build/koffi/win32_arm64/koffi.node +0 -0
- package/build/koffi/win32_ia32/koffi.node +0 -0
- package/build/koffi/win32_x64/koffi.node +0 -0
- package/doc/contribute.md +3 -2
- package/doc/functions.md +3 -2
- package/doc/start.md +9 -1
- package/index.js +2 -2
- package/indirect.js +2 -2
- package/package.json +2 -2
- package/src/core/libcc/libcc.cc +1 -1
- package/src/koffi/CMakeLists.txt +5 -1
- package/src/koffi/src/ffi.cc +56 -39
- package/src/koffi/src/win32.cc +6 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
|
|
5
5
|
### Koffi 2.8
|
|
6
6
|
|
|
7
|
+
#### Koffi 2.8.6 (2024-04-12)
|
|
8
|
+
|
|
9
|
+
- Support [loading library](functions.md#loading-options) with RTLD_DEEPBIND where supported
|
|
10
|
+
|
|
11
|
+
#### Koffi 2.8.5 (2024-04-11)
|
|
12
|
+
|
|
13
|
+
- Prevent obviously invalid type and member names
|
|
14
|
+
- Fix possible infinite loop / UB for `koffi.load()` errors on POSIX systems
|
|
15
|
+
- Fix null return value instead of exception for some errors in `koffi.load()` on Windows
|
|
16
|
+
|
|
7
17
|
#### Koffi 2.8.4 (2024-04-09)
|
|
8
18
|
|
|
9
19
|
- Use simpler workaround for Node 20.12+ and 21.6+ to avoid excessive memory use
|
package/README.md
CHANGED
|
@@ -29,6 +29,12 @@ You can consult the [changelog](https://koffi.dev/changelog) on the official web
|
|
|
29
29
|
|
|
30
30
|
Major version increments can include breaking API changes, use the [migration guide](https://koffi.dev/changelog#migration-guide) for more information.
|
|
31
31
|
|
|
32
|
+
# Build manually
|
|
33
|
+
|
|
34
|
+
Koffi is built with a custom CMake-wrapper called CNoke, which also lives in this repository. Don't try to run CMake manually because it will fail.
|
|
35
|
+
|
|
36
|
+
Follow the [documented build instructions](https://koffi.dev/contribute#build-from-source) to build Koffi from source.
|
|
37
|
+
|
|
32
38
|
# License
|
|
33
39
|
|
|
34
40
|
This program is free software: you can redistribute it and/or modify it under the terms of the **MIT License**.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/doc/contribute.md
CHANGED
|
@@ -25,7 +25,7 @@ First, make sure the following dependencies are met:
|
|
|
25
25
|
|
|
26
26
|
- The "Desktop development with C++" workload from [Visual Studio 2022 or 2019](https://visualstudio.microsoft.com/downloads/) or the "C++ build tools" workload from the [Build Tools](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022), with the default optional components.
|
|
27
27
|
- [CMake meta build system](https://cmake.org/)
|
|
28
|
-
- [Node.js](https://nodejs.org/)
|
|
28
|
+
- [Node.js](https://nodejs.org/) 16 or later
|
|
29
29
|
|
|
30
30
|
Once this is done, run this command _from the test or the benchmark directory_ (depending on what you want to build):
|
|
31
31
|
|
|
@@ -41,7 +41,7 @@ Make sure the following dependencies are met:
|
|
|
41
41
|
- `gcc` and `g++` >= 8.3 or newer
|
|
42
42
|
- GNU Make 3.81 or newer
|
|
43
43
|
- [CMake meta build system](https://cmake.org/)
|
|
44
|
-
- [Node.js](https://nodejs.org/)
|
|
44
|
+
- [Node.js](https://nodejs.org/) 16 or later
|
|
45
45
|
|
|
46
46
|
Once this is done, run this command _from the test or the benchmark directory_ (depending on what you want to build):
|
|
47
47
|
|
|
@@ -64,6 +64,7 @@ node sync.js # Run synchronous unit tests
|
|
|
64
64
|
node async.js # Run asynchronous unit tests
|
|
65
65
|
node callbacks.js # Run callback unit tests
|
|
66
66
|
node union.js # Run union unit tests
|
|
67
|
+
node posix.js # Run POSIX-specific unit tests (not for Windows)
|
|
67
68
|
node win32.js # Run Windows-specific unit tests (only on Windows)
|
|
68
69
|
|
|
69
70
|
node sqlite.js # Run SQLite integration tests
|
package/doc/functions.md
CHANGED
|
@@ -21,14 +21,15 @@ On some platforms (such as with the [musl C library on Linux](https://wiki.musl-
|
|
|
21
21
|
|
|
22
22
|
## Loading options
|
|
23
23
|
|
|
24
|
-
*New in Koffi 2.6 and Koffi 2.8.
|
|
24
|
+
*New in Koffi 2.6, changed in Koffi 2.8.2 and Koffi 2.8.6*
|
|
25
25
|
|
|
26
26
|
The `load` function can take an optional object argument, with the following options:
|
|
27
27
|
|
|
28
28
|
```js
|
|
29
29
|
const options = {
|
|
30
30
|
lazy: true, // Use RTLD_LAZY (lazy-binding) on POSIX platforms (by default, use RTLD_NOW)
|
|
31
|
-
global: true // Use RTLD_GLOBAL on POSIX platforms (by default, use RTLD_LOCAL)
|
|
31
|
+
global: true, // Use RTLD_GLOBAL on POSIX platforms (by default, use RTLD_LOCAL)
|
|
32
|
+
deep: true // Use RTLD_DEEPBIND if supported (Linux, FreeBSD)
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
const lib = koffi.load('/path/to/shared/library.so', options);
|
package/doc/start.md
CHANGED
|
@@ -109,4 +109,12 @@ if (ret == IDYES)
|
|
|
109
109
|
|
|
110
110
|
## Bundling Koffi
|
|
111
111
|
|
|
112
|
-
Please read the [dedicated page](packaging.md) for information about bundling and packaging applications using Koffi.
|
|
112
|
+
Please read the [dedicated page](packaging.md) for information about bundling and packaging applications using Koffi.
|
|
113
|
+
|
|
114
|
+
## Build manually
|
|
115
|
+
|
|
116
|
+
Follow the [build instrutions](contribute.md#build-from-source) if you want to build the native Koffi code yourself.
|
|
117
|
+
|
|
118
|
+
```{note}
|
|
119
|
+
This is only needed if you want to hack on Koffi. The official NPM package provide prebuilt binaries and you don't need to compile anything if you only want to use Koffi in Node.js.
|
|
120
|
+
```
|
package/index.js
CHANGED
|
@@ -378,8 +378,8 @@ var require_package = __commonJS({
|
|
|
378
378
|
"build/dist/src/koffi/package.json"(exports2, module2) {
|
|
379
379
|
module2.exports = {
|
|
380
380
|
name: "koffi",
|
|
381
|
-
version: "2.8.
|
|
382
|
-
stable: "2.8.
|
|
381
|
+
version: "2.8.6",
|
|
382
|
+
stable: "2.8.6",
|
|
383
383
|
description: "Fast and simple C FFI (foreign function interface) for Node.js",
|
|
384
384
|
keywords: [
|
|
385
385
|
"foreign",
|
package/indirect.js
CHANGED
|
@@ -378,8 +378,8 @@ var require_package = __commonJS({
|
|
|
378
378
|
"build/dist/src/koffi/package.json"(exports2, module2) {
|
|
379
379
|
module2.exports = {
|
|
380
380
|
name: "koffi",
|
|
381
|
-
version: "2.8.
|
|
382
|
-
stable: "2.8.
|
|
381
|
+
version: "2.8.6",
|
|
382
|
+
stable: "2.8.6",
|
|
383
383
|
description: "Fast and simple C FFI (foreign function interface) for Node.js",
|
|
384
384
|
keywords: [
|
|
385
385
|
"foreign",
|
package/package.json
CHANGED
package/src/core/libcc/libcc.cc
CHANGED
|
@@ -1935,7 +1935,7 @@ bool GetDebugFlag(const char *name)
|
|
|
1935
1935
|
#ifndef NDEBUG
|
|
1936
1936
|
const char *DebugLogContext(const char *filename, int line)
|
|
1937
1937
|
{
|
|
1938
|
-
static
|
|
1938
|
+
static thread_local LocalArray<char, 1024> buf;
|
|
1939
1939
|
|
|
1940
1940
|
buf.len = Fmt(buf.data, " [%1:%2] ", filename, line).len;
|
|
1941
1941
|
|
package/src/koffi/CMakeLists.txt
CHANGED
|
@@ -21,8 +21,12 @@
|
|
|
21
21
|
|
|
22
22
|
cmake_minimum_required(VERSION 3.6)
|
|
23
23
|
cmake_policy(SET CMP0091 NEW)
|
|
24
|
-
project(koffi C CXX ASM)
|
|
25
24
|
|
|
25
|
+
if(NOT NODE_JS_INCLUDE_DIRS)
|
|
26
|
+
message(FATAL_ERROR "Please use CNoke to build Koffi, follow instructions here: https://koffi.dev/contribute#build-from-source")
|
|
27
|
+
endif()
|
|
28
|
+
|
|
29
|
+
project(koffi C CXX ASM)
|
|
26
30
|
find_package(CNoke)
|
|
27
31
|
|
|
28
32
|
include(CheckCXXCompilerFlag)
|
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -200,6 +200,38 @@ static inline bool CheckAlignment(int64_t align)
|
|
|
200
200
|
return valid;
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
+
// Prevent simple mistakes but don't be too strict, the world is bigger than the US!
|
|
204
|
+
static bool IsNameValid(const char *name)
|
|
205
|
+
{
|
|
206
|
+
if (!name[0] || IsAsciiWhite(name[0]) || IsAsciiDigit(name[0])) [[unlikely]]
|
|
207
|
+
return false;
|
|
208
|
+
|
|
209
|
+
for (Size i = 1; name[i]; i++) {
|
|
210
|
+
if (IsAsciiWhite(name[i])) [[unlikely]]
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
static bool MapType(Napi::Env env, InstanceData *instance, const TypeInfo *type, const char *name)
|
|
218
|
+
{
|
|
219
|
+
if (!IsNameValid(name)) {
|
|
220
|
+
ThrowError<Napi::Error>(env, "Invalid type name '%1'", name);
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
bool inserted;
|
|
225
|
+
instance->types_map.TrySet(name, type, &inserted);
|
|
226
|
+
|
|
227
|
+
if (!inserted) {
|
|
228
|
+
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", name);
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
234
|
+
|
|
203
235
|
static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
204
236
|
{
|
|
205
237
|
Napi::Env env = info.Env();
|
|
@@ -245,13 +277,8 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
|
245
277
|
if (named) {
|
|
246
278
|
type->name = DuplicateString(name.Utf8Value().c_str(), &instance->str_alloc).ptr;
|
|
247
279
|
|
|
248
|
-
|
|
249
|
-
instance->types_map.TrySet(type->name, type, &inserted);
|
|
250
|
-
|
|
251
|
-
if (!inserted) {
|
|
252
|
-
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
|
|
280
|
+
if (!MapType(env, instance, type, type->name))
|
|
253
281
|
return env.Null();
|
|
254
|
-
}
|
|
255
282
|
} else {
|
|
256
283
|
type->name = Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.len).ptr;
|
|
257
284
|
}
|
|
@@ -312,6 +339,11 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
|
312
339
|
return env.Null();
|
|
313
340
|
}
|
|
314
341
|
|
|
342
|
+
if (!IsNameValid(member.name)) {
|
|
343
|
+
ThrowError<Napi::Error>(env, "Invalid member name '%1'", member.name);
|
|
344
|
+
return env.Null();
|
|
345
|
+
}
|
|
346
|
+
|
|
315
347
|
bool inserted;
|
|
316
348
|
members.TrySet(member.name, &inserted);
|
|
317
349
|
|
|
@@ -391,13 +423,8 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
|
|
|
391
423
|
if (named) {
|
|
392
424
|
type->name = DuplicateString(name.Utf8Value().c_str(), &instance->str_alloc).ptr;
|
|
393
425
|
|
|
394
|
-
|
|
395
|
-
instance->types_map.TrySet(type->name, type, &inserted);
|
|
396
|
-
|
|
397
|
-
if (!inserted) {
|
|
398
|
-
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
|
|
426
|
+
if (!MapType(env, instance, type, type->name))
|
|
399
427
|
return env.Null();
|
|
400
|
-
}
|
|
401
428
|
} else {
|
|
402
429
|
type->name = Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.len).ptr;
|
|
403
430
|
}
|
|
@@ -449,6 +476,11 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
|
|
|
449
476
|
size = std::max(size, member.type->size);
|
|
450
477
|
type->align = std::max(type->align, align);
|
|
451
478
|
|
|
479
|
+
if (!IsNameValid(member.name)) {
|
|
480
|
+
ThrowError<Napi::Error>(env, "Invalid member name '%1'", member.name);
|
|
481
|
+
return env.Null();
|
|
482
|
+
}
|
|
483
|
+
|
|
452
484
|
bool inserted;
|
|
453
485
|
members.TrySet(member.name, &inserted);
|
|
454
486
|
|
|
@@ -530,15 +562,8 @@ static Napi::Value CreateOpaqueType(const Napi::CallbackInfo &info)
|
|
|
530
562
|
type->align = 0;
|
|
531
563
|
|
|
532
564
|
// If the insert succeeds, we cannot fail anymore
|
|
533
|
-
if (named)
|
|
534
|
-
|
|
535
|
-
instance->types_map.TrySet(type->name, type, &inserted);
|
|
536
|
-
|
|
537
|
-
if (!inserted) {
|
|
538
|
-
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
|
|
539
|
-
return env.Null();
|
|
540
|
-
}
|
|
541
|
-
}
|
|
565
|
+
if (named && !MapType(env, instance, type, type->name))
|
|
566
|
+
return env.Null();
|
|
542
567
|
err_guard.Disable();
|
|
543
568
|
|
|
544
569
|
return WrapType(env, instance, type);
|
|
@@ -594,14 +619,9 @@ static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
|
|
|
594
619
|
memcpy((void *)copy, type, RG_SIZE(*type));
|
|
595
620
|
copy->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
|
|
596
621
|
|
|
597
|
-
bool inserted;
|
|
598
|
-
instance->types_map.TrySet(copy->name, copy, &inserted);
|
|
599
|
-
|
|
600
622
|
// If the insert succeeds, we cannot fail anymore
|
|
601
|
-
if (!
|
|
602
|
-
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", copy->name);
|
|
623
|
+
if (!MapType(env, instance, copy, copy->name))
|
|
603
624
|
return env.Null();
|
|
604
|
-
}
|
|
605
625
|
err_guard.Disable();
|
|
606
626
|
|
|
607
627
|
type = copy;
|
|
@@ -1090,15 +1110,8 @@ static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
|
|
|
1090
1110
|
return env.Null();
|
|
1091
1111
|
|
|
1092
1112
|
// Alias the type
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
instance->types_map.TrySet(alias, type, &inserted);
|
|
1096
|
-
|
|
1097
|
-
if (!inserted) {
|
|
1098
|
-
ThrowError<Napi::Error>(env, "Type name '%1' already exists", alias);
|
|
1099
|
-
return env.Null();
|
|
1100
|
-
}
|
|
1101
|
-
}
|
|
1113
|
+
if (!MapType(env, instance, type, alias))
|
|
1114
|
+
return env.Null();
|
|
1102
1115
|
|
|
1103
1116
|
return WrapType(env, instance, type);
|
|
1104
1117
|
}
|
|
@@ -1724,6 +1737,9 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
|
|
|
1724
1737
|
|
|
1725
1738
|
flags |= options.Get("lazy").ToBoolean() ? RTLD_LAZY : RTLD_NOW;
|
|
1726
1739
|
flags |= options.Get("global").ToBoolean() ? RTLD_GLOBAL : RTLD_LOCAL;
|
|
1740
|
+
#ifdef RTLD_DEEPBIND
|
|
1741
|
+
flags |= options.Get("deep").ToBoolean() ? RTLD_DEEPBIND : 0;
|
|
1742
|
+
#endif
|
|
1727
1743
|
} else {
|
|
1728
1744
|
flags = RTLD_NOW | RTLD_LOCAL;
|
|
1729
1745
|
}
|
|
@@ -1757,9 +1773,10 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
|
|
|
1757
1773
|
|
|
1758
1774
|
if (StartsWith(msg, filename.c_str())) {
|
|
1759
1775
|
msg += filename.length();
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1776
|
+
|
|
1777
|
+
while (strchr(": ", msg[0]) && msg[0]) {
|
|
1778
|
+
msg++;
|
|
1779
|
+
}
|
|
1763
1780
|
}
|
|
1764
1781
|
|
|
1765
1782
|
ThrowError<Napi::Error>(env, "Failed to load shared library: %1", msg);
|
package/src/koffi/src/win32.cc
CHANGED
|
@@ -74,8 +74,10 @@ HANDLE LoadWindowsLibrary(Napi::Env env, Span<const char> path)
|
|
|
74
74
|
|
|
75
75
|
Span<wchar_t> filename_w = AllocateSpan<wchar_t>(&temp_alloc, path.len + 1);
|
|
76
76
|
|
|
77
|
-
if (ConvertUtf8ToWin32Wide(path, filename_w) < 0)
|
|
77
|
+
if (ConvertUtf8ToWin32Wide(path, filename_w) < 0) {
|
|
78
|
+
ThrowError<Napi::Error>(env, "Invalid path string");
|
|
78
79
|
return nullptr;
|
|
80
|
+
}
|
|
79
81
|
|
|
80
82
|
HMODULE module = LoadLibraryW(filename_w.ptr);
|
|
81
83
|
|
|
@@ -85,8 +87,10 @@ HANDLE LoadWindowsLibrary(Napi::Env env, Span<const char> path)
|
|
|
85
87
|
Span<const char> filename = NormalizePath(path, GetWorkingDirectory(), &temp_alloc);
|
|
86
88
|
Span<wchar_t> filename_w = AllocateSpan<wchar_t>(&temp_alloc, filename.len + 1);
|
|
87
89
|
|
|
88
|
-
if (ConvertUtf8ToWin32Wide(filename, filename_w) < 0)
|
|
90
|
+
if (ConvertUtf8ToWin32Wide(filename, filename_w) < 0) {
|
|
91
|
+
ThrowError<Napi::Error>(env, "Invalid path string");
|
|
89
92
|
return nullptr;
|
|
93
|
+
}
|
|
90
94
|
|
|
91
95
|
module = LoadLibraryExW(filename_w.ptr, nullptr, flags);
|
|
92
96
|
}
|