koffi 2.2.2-beta.6 → 2.2.3-beta.1

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.
Files changed (41) hide show
  1. package/ChangeLog.md +14 -0
  2. package/doc/callbacks.md +9 -2
  3. package/package.json +2 -2
  4. package/src/koffi/build/2.2.3-beta.1/koffi_darwin_arm64.tar.gz +0 -0
  5. package/src/koffi/build/2.2.3-beta.1/koffi_darwin_x64.tar.gz +0 -0
  6. package/src/koffi/build/2.2.3-beta.1/koffi_freebsd_arm64.tar.gz +0 -0
  7. package/src/koffi/build/2.2.3-beta.1/koffi_freebsd_ia32.tar.gz +0 -0
  8. package/src/koffi/build/2.2.3-beta.1/koffi_freebsd_x64.tar.gz +0 -0
  9. package/src/koffi/build/2.2.3-beta.1/koffi_linux_arm32hf.tar.gz +0 -0
  10. package/src/koffi/build/2.2.3-beta.1/koffi_linux_arm64.tar.gz +0 -0
  11. package/src/koffi/build/2.2.3-beta.1/koffi_linux_ia32.tar.gz +0 -0
  12. package/src/koffi/build/2.2.3-beta.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  13. package/src/koffi/build/2.2.3-beta.1/koffi_linux_x64.tar.gz +0 -0
  14. package/src/koffi/build/2.2.3-beta.1/koffi_openbsd_ia32.tar.gz +0 -0
  15. package/src/koffi/build/2.2.3-beta.1/koffi_openbsd_x64.tar.gz +0 -0
  16. package/src/koffi/build/2.2.3-beta.1/koffi_win32_arm64.tar.gz +0 -0
  17. package/src/koffi/build/2.2.3-beta.1/koffi_win32_ia32.tar.gz +0 -0
  18. package/src/koffi/build/2.2.3-beta.1/koffi_win32_x64.tar.gz +0 -0
  19. package/src/koffi/src/abi_x64_win.cc +28 -0
  20. package/src/koffi/src/abi_x86.cc +35 -1
  21. package/src/koffi/src/call.cc +3 -0
  22. package/src/koffi/src/ffi.cc +19 -4
  23. package/src/koffi/src/ffi.hh +6 -0
  24. package/vendor/miniz/ChangeLog.md +4 -0
  25. package/vendor/miniz/miniz.c +1 -1
  26. package/vendor/miniz/miniz.h +3 -3
  27. package/src/koffi/build/2.2.2-beta.6/koffi_darwin_arm64.tar.gz +0 -0
  28. package/src/koffi/build/2.2.2-beta.6/koffi_darwin_x64.tar.gz +0 -0
  29. package/src/koffi/build/2.2.2-beta.6/koffi_freebsd_arm64.tar.gz +0 -0
  30. package/src/koffi/build/2.2.2-beta.6/koffi_freebsd_ia32.tar.gz +0 -0
  31. package/src/koffi/build/2.2.2-beta.6/koffi_freebsd_x64.tar.gz +0 -0
  32. package/src/koffi/build/2.2.2-beta.6/koffi_linux_arm32hf.tar.gz +0 -0
  33. package/src/koffi/build/2.2.2-beta.6/koffi_linux_arm64.tar.gz +0 -0
  34. package/src/koffi/build/2.2.2-beta.6/koffi_linux_ia32.tar.gz +0 -0
  35. package/src/koffi/build/2.2.2-beta.6/koffi_linux_riscv64hf64.tar.gz +0 -0
  36. package/src/koffi/build/2.2.2-beta.6/koffi_linux_x64.tar.gz +0 -0
  37. package/src/koffi/build/2.2.2-beta.6/koffi_openbsd_ia32.tar.gz +0 -0
  38. package/src/koffi/build/2.2.2-beta.6/koffi_openbsd_x64.tar.gz +0 -0
  39. package/src/koffi/build/2.2.2-beta.6/koffi_win32_arm64.tar.gz +0 -0
  40. package/src/koffi/build/2.2.2-beta.6/koffi_win32_ia32.tar.gz +0 -0
  41. package/src/koffi/build/2.2.2-beta.6/koffi_win32_x64.tar.gz +0 -0
package/ChangeLog.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  ## History
4
4
 
5
+ ### Koffi 2.2.2
6
+
7
+ **Main fixes:**
8
+
9
+ - Support transparent [asynchronous callbacks](callbacks.md#asynchronous-callbacks)
10
+ - Expand from a maximum of 16+16 to 1024 callbacks running in parallel
11
+
12
+ **Other fixes:**
13
+
14
+ - Fix bundler support by removing shebang from index.js
15
+ - Fix bugs when loading Koffi multiples times in same process (context aware module)
16
+ - Check N-API version when module is loaded
17
+ - Optimize callback unregistration
18
+
5
19
  ### Koffi 2.2.1
6
20
 
7
21
  **Main fixes:**
package/doc/callbacks.md CHANGED
@@ -172,9 +172,16 @@ console.log(array); // Prints ['123', 'bar', 'foo', 'foobar']
172
172
 
173
173
  *New in Koffi 2.2.2*
174
174
 
175
- In Koffi, [asynchronous native calls](functions.md#asynchronous-calls) happen on a secondary thread. However, JS execution is inherently single-threaded, callbacks must run on the main thread.
175
+ JS execution is inherently single-threaded, so JS callbacks must run on the main thread. There are two ways you may want to call a callback function from another thread:
176
176
 
177
- Koffi deals with this by running the JS callback function in the Node.js event loop. This means the callback cannot run while the engine is busy running synchronous code.
177
+ - Call the callback from an asynchronous FFI call (e.g. `waitpid.async`)
178
+ - Inside a synchronous FFI call, pass the callback to another thread
179
+
180
+ In both cases, Koffi will queue the call back to JS to run on the main thread, as soon as the JS event loop has a chance to run (for example when you await a promise).
181
+
182
+ ```{warning}
183
+ Be careful, you can easily get into a deadlock situation if you call a callback from a secondary thread and your main thread never lets the JS event loop run (for example, if the main thread waits for the secondary thread to finish something itself).
184
+ ```
178
185
 
179
186
  ## Handling of exceptions
180
187
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.2.2-beta.6",
4
- "stable": "2.2.1",
3
+ "version": "2.2.3-beta.1",
4
+ "stable": "2.2.2",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
7
7
  "foreign",
@@ -18,6 +18,14 @@
18
18
  #include "call.hh"
19
19
  #include "util.hh"
20
20
 
21
+ #ifndef NOMINMAX
22
+ #define NOMINMAX
23
+ #endif
24
+ #ifndef WIN32_LEAN_AND_MEAN
25
+ #define WIN32_LEAN_AND_MEAN
26
+ #endif
27
+ #include <windows.h>
28
+
21
29
  #include <napi.h>
22
30
 
23
31
  namespace RG {
@@ -216,6 +224,16 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
216
224
 
217
225
  void CallData::Execute(const FunctionInfo *func)
218
226
  {
227
+ NT_TIB *tib = (NT_TIB *)__readgsqword(0x30);
228
+
229
+ // Adjust TIB stack limits so SEH works correctly
230
+ RG_DEFER_C(base = tib->StackBase, limit = tib->StackLimit) {
231
+ tib->StackBase = base;
232
+ tib->StackLimit = limit;
233
+ };
234
+ tib->StackBase = mem->stack0.end();
235
+ tib->StackLimit = mem->stack0.ptr;
236
+
219
237
  #define PERFORM_CALL(Suffix) \
220
238
  ([&]() { \
221
239
  auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, new_sp, &old_sp) \
@@ -317,6 +335,16 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
317
335
  if (RG_UNLIKELY(env.IsExceptionPending()))
318
336
  return;
319
337
 
338
+ NT_TIB *tib = (NT_TIB *)__readgsqword(0x30);
339
+
340
+ // Restore real thread stack limits
341
+ RG_DEFER_C(base = tib->StackBase, limit = tib->StackLimit) {
342
+ tib->StackBase = base;
343
+ tib->StackLimit = limit;
344
+ };
345
+ tib->StackBase = instance->main_stack_base;
346
+ tib->StackLimit = instance->main_stack_limit;
347
+
320
348
  const TrampolineInfo &trampoline = shared.trampolines[idx];
321
349
 
322
350
  const FunctionInfo *proto = trampoline.proto;
@@ -18,6 +18,16 @@
18
18
  #include "call.hh"
19
19
  #include "util.hh"
20
20
 
21
+ #ifdef _WIN32
22
+ #ifndef NOMINMAX
23
+ #define NOMINMAX
24
+ #endif
25
+ #ifndef WIN32_LEAN_AND_MEAN
26
+ #define WIN32_LEAN_AND_MEAN
27
+ #endif
28
+ #include <windows.h>
29
+ #endif
30
+
21
31
  #include <napi.h>
22
32
 
23
33
  namespace RG {
@@ -297,6 +307,18 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
297
307
 
298
308
  void CallData::Execute(const FunctionInfo *func)
299
309
  {
310
+ #ifdef _WIN32
311
+ NT_TIB *tib = (NT_TIB *)__readfsdword(0x18);
312
+
313
+ // Adjust TIB stack limits so SEH works correctly
314
+ RG_DEFER_C(base = tib->StackBase, limit = tib->StackLimit) {
315
+ tib->StackBase = base;
316
+ tib->StackLimit = limit;
317
+ };
318
+ tib->StackBase = mem->stack0.end();
319
+ tib->StackLimit = mem->stack0.ptr;
320
+ #endif
321
+
300
322
  #define PERFORM_CALL(Suffix) \
301
323
  ([&]() { \
302
324
  auto ret = (func->fast ? ForwardCallR ## Suffix(func->func, new_sp, &old_sp) \
@@ -394,11 +416,23 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
394
416
  RG_UNREACHABLE();
395
417
  }
396
418
 
397
- void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async, BackRegisters *out_reg)
419
+ void CallData::Relay(Size idx, uint8_t *, uint8_t *caller_sp, bool async, BackRegisters *out_reg)
398
420
  {
399
421
  if (RG_UNLIKELY(env.IsExceptionPending()))
400
422
  return;
401
423
 
424
+ #ifdef _WIN32
425
+ NT_TIB *tib = (NT_TIB *)__readfsdword(0x18);
426
+
427
+ // Restore real thread stack limits
428
+ RG_DEFER_C(base = tib->StackBase, limit = tib->StackLimit) {
429
+ tib->StackBase = base;
430
+ tib->StackLimit = limit;
431
+ };
432
+ tib->StackBase = instance->main_stack_base;
433
+ tib->StackLimit = instance->main_stack_limit;
434
+ #endif
435
+
402
436
  const TrampolineInfo &trampoline = shared.trampolines[idx];
403
437
 
404
438
  const FunctionInfo *proto = trampoline.proto;
@@ -81,6 +81,9 @@ CallData::~CallData()
81
81
  void CallData::RelaySafe(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
82
82
  {
83
83
  if (std::this_thread::get_id() != instance->main_thread_id) {
84
+ // JS/V8 is single-threaded, and runs on main_thread_id. Forward the call
85
+ // to the JS event loop.
86
+
84
87
  RelayContext ctx;
85
88
 
86
89
  ctx.call = this;
@@ -1030,6 +1030,9 @@ static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, S
1030
1030
  mem->stack.len -= 16;
1031
1031
  #endif
1032
1032
 
1033
+ // Keep real stack limits intact, in case we need them
1034
+ mem->stack0 = mem->stack;
1035
+
1033
1036
  mem->heap.len = heap_size;
1034
1037
  #ifdef _WIN32
1035
1038
  mem->heap.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->heap.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
@@ -1065,9 +1068,6 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
1065
1068
  InstanceMemory *mem = instance->memories[0];
1066
1069
  CallData call(env, instance, mem);
1067
1070
 
1068
- RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1069
- exec_call = &call;
1070
-
1071
1071
  if (!RG_UNLIKELY(call.Prepare(func, info)))
1072
1072
  return env.Null();
1073
1073
 
@@ -1113,7 +1113,7 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
1113
1113
  for (Size i = func.parameters.len; i < (Size)info.Length(); i += 2) {
1114
1114
  ParameterInfo param = {};
1115
1115
 
1116
- param.type = ResolveType(info[i], &param.directions);
1116
+ param.type = ResolveType(info[(uint32_t)i], &param.directions);
1117
1117
 
1118
1118
  if (RG_UNLIKELY(!param.type))
1119
1119
  return env.Null();
@@ -1893,6 +1893,9 @@ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, Bac
1893
1893
  if (RG_LIKELY(exec_call)) {
1894
1894
  exec_call->RelaySafe(idx, own_sp, caller_sp, out_reg);
1895
1895
  } else {
1896
+ // This happens if the callback pointer is called from a different thread
1897
+ // than the one that runs the FFI call (sync or async).
1898
+
1896
1899
  TrampolineInfo *trampoline = &shared.trampolines[idx];
1897
1900
 
1898
1901
  Napi::Env env = trampoline->func.Env();
@@ -1929,6 +1932,18 @@ static InstanceData *CreateInstance(Napi::Env env)
1929
1932
  }
1930
1933
  napi_unref_threadsafe_function(env, instance->broker);
1931
1934
 
1935
+ #if defined(_WIN32) && (defined(__x86_64__) || defined(_M_AMD64))
1936
+ NT_TIB *tib = (NT_TIB *)__readgsqword(0x30);
1937
+
1938
+ instance->main_stack_base = tib->StackBase;
1939
+ instance->main_stack_limit = tib->StackLimit;
1940
+ #elif defined(_WIN32) && (defined(__i386__) || defined(_M_IX86))
1941
+ NT_TIB *tib = (NT_TIB *)__readfsdword(0x18);
1942
+
1943
+ instance->main_stack_base = tib->StackBase;
1944
+ instance->main_stack_limit = tib->StackLimit;
1945
+ #endif
1946
+
1932
1947
  err_guard.Disable();
1933
1948
  return instance;
1934
1949
  }
@@ -225,6 +225,7 @@ struct InstanceMemory {
225
225
  ~InstanceMemory();
226
226
 
227
227
  Span<uint8_t> stack;
228
+ Span<uint8_t> stack0;
228
229
  Span<uint8_t> heap;
229
230
 
230
231
  uint16_t generation; // Can wrap without risk
@@ -254,6 +255,11 @@ struct InstanceData {
254
255
  std::thread::id main_thread_id;
255
256
  napi_threadsafe_function broker = nullptr;
256
257
 
258
+ #ifdef _WIN32
259
+ void *main_stack_base;
260
+ void *main_stack_limit;
261
+ #endif
262
+
257
263
  HashMap<void *, int16_t> trampolines_map;
258
264
 
259
265
  BlockAllocator str_alloc;
@@ -1,5 +1,9 @@
1
1
  ## Changelog
2
2
 
3
+ ### 3.0.2
4
+
5
+ - Fix buffer overrun in mz_utf8z_to_widechar on Windows
6
+
3
7
  ### 3.0.1
4
8
 
5
9
  - Fix compilation error with MINIZ_USE_UNALIGNED_LOADS_AND_STORES=1
@@ -3068,7 +3068,7 @@ static WCHAR* mz_utf8z_to_widechar(const char* str)
3068
3068
  {
3069
3069
  int reqChars = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
3070
3070
  WCHAR* wStr = (WCHAR*)malloc(reqChars * sizeof(WCHAR));
3071
- MultiByteToWideChar(CP_UTF8, 0, str, -1, wStr, sizeof(WCHAR) * reqChars);
3071
+ MultiByteToWideChar(CP_UTF8, 0, str, -1, wStr, reqChars);
3072
3072
  return wStr;
3073
3073
  }
3074
3074
 
@@ -275,10 +275,10 @@ enum
275
275
  MZ_DEFAULT_COMPRESSION = -1
276
276
  };
277
277
 
278
- #define MZ_VERSION "11.0.1"
279
- #define MZ_VERNUM 0xB001
278
+ #define MZ_VERSION "11.0.2"
279
+ #define MZ_VERNUM 0xB002
280
280
  #define MZ_VER_MAJOR 11
281
- #define MZ_VER_MINOR 1
281
+ #define MZ_VER_MINOR 2
282
282
  #define MZ_VER_REVISION 0
283
283
  #define MZ_VER_SUBREVISION 0
284
284