koffi 2.8.3 → 2.8.5

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 CHANGED
@@ -4,10 +4,20 @@
4
4
 
5
5
  ### Koffi 2.8
6
6
 
7
- #### Koffi 2.8.3 (2024-04-08)
7
+ #### Koffi 2.8.5 (2024-04-11)
8
+
9
+ - Prevent obviously invalid type and member names
10
+ - Fix possible infinite loop / UB for `koffi.load()` errors on POSIX systems
11
+ - Fix null return value instead of exception for some errors in `koffi.load()` on Windows
12
+
13
+ #### Koffi 2.8.4 (2024-04-09)
8
14
 
9
15
  - Use simpler workaround for Node 20.12+ and 21.6+ to avoid excessive memory use
10
16
 
17
+ ```{warning}
18
+ Some pre-built binaries are missing in Koffi 2.8.3, skip this version.
19
+ ```
20
+
11
21
  #### Koffi 2.8.2 (2024-04-07)
12
22
 
13
23
  - Support [loading library](functions.md#loading-options) with RTLD_GLOBAL on POSIX platforms
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/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.3",
382
- stable: "2.8.3",
381
+ version: "2.8.5",
382
+ stable: "2.8.5",
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.3",
382
- stable: "2.8.3",
381
+ version: "2.8.5",
382
+ stable: "2.8.5",
383
383
  description: "Fast and simple C FFI (foreign function interface) for Node.js",
384
384
  keywords: [
385
385
  "foreign",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.8.3",
4
- "stable": "2.8.3",
3
+ "version": "2.8.5",
4
+ "stable": "2.8.5",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
7
7
  "foreign",
@@ -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 RG_THREAD_LOCAL LocalArray<char, 1024> buf;
1938
+ static thread_local LocalArray<char, 1024> buf;
1939
1939
 
1940
1940
  buf.len = Fmt(buf.data, " [%1:%2] ", filename, line).len;
1941
1941
 
@@ -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
- bool inserted;
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
- bool inserted;
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
- bool inserted;
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 (!inserted) {
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
- bool inserted;
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
  }
@@ -1757,9 +1770,10 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
1757
1770
 
1758
1771
  if (StartsWith(msg, filename.c_str())) {
1759
1772
  msg += filename.length();
1760
- }
1761
- while (strchr(": ", msg[0])) {
1762
- msg++;
1773
+
1774
+ while (strchr(": ", msg[0]) && msg[0]) {
1775
+ msg++;
1776
+ }
1763
1777
  }
1764
1778
 
1765
1779
  ThrowError<Napi::Error>(env, "Failed to load shared library: %1", msg);
@@ -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
  }