koffi 2.16.0 → 2.16.2
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 +14 -1
- 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_arm64/koffi.node +0 -0
- package/build/koffi/linux_armhf/koffi.node +0 -0
- package/build/koffi/linux_ia32/koffi.node +0 -0
- package/build/koffi/linux_loong64/koffi.node +0 -0
- package/build/koffi/linux_riscv64d/koffi.node +0 -0
- package/build/koffi/linux_x64/koffi.node +0 -0
- package/build/koffi/musl_arm64/koffi.node +0 -0
- package/build/koffi/musl_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/index.js +1 -1
- package/indirect.js +1 -1
- package/package.json +1 -1
- package/src/koffi/src/abi_arm32.cc +2 -10
- package/src/koffi/src/abi_arm64.cc +2 -28
- package/src/koffi/src/abi_loong64_asm.S +2 -2
- package/src/koffi/src/abi_riscv64.cc +2 -10
- package/src/koffi/src/abi_riscv64_asm.S +2 -2
- package/src/koffi/src/abi_x64_sysv.cc +2 -10
- package/src/koffi/src/abi_x64_win.cc +2 -26
- package/src/koffi/src/abi_x64_win_asm.S +2 -2
- package/src/koffi/src/abi_x86.cc +2 -28
- package/src/koffi/src/abi_x86_asm.S +4 -2
- package/src/koffi/src/abi_x86_asm.asm +2 -0
- package/src/koffi/src/call.cc +15 -8
- package/src/koffi/src/ffi.cc +32 -5
- package/src/koffi/src/ffi.hh +1 -3
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,19 @@
|
|
|
7
7
|
|
|
8
8
|
### Koffi 2.16
|
|
9
9
|
|
|
10
|
+
#### Koffi 2.16.2
|
|
11
|
+
|
|
12
|
+
*Released on 2026-05-06*
|
|
13
|
+
|
|
14
|
+
- Fix string truncation bugs when passing some kinds of long V8 strings (see [Koromix/koffi#266](https://github.com/Koromix/koffi/issues/266))
|
|
15
|
+
|
|
16
|
+
#### Koffi 2.16.1
|
|
17
|
+
|
|
18
|
+
*Released on 2026-04-17*
|
|
19
|
+
|
|
20
|
+
- Fix possible stack check crash when relaying callbacks on Windows
|
|
21
|
+
- Improve exception handling inside callbacks
|
|
22
|
+
|
|
10
23
|
#### Koffi 2.16.0
|
|
11
24
|
|
|
12
25
|
*Released on 2026-04-14*
|
|
@@ -14,7 +27,7 @@
|
|
|
14
27
|
- Support buffers and typed arrays in `koffi.address()`
|
|
15
28
|
- Put x86 SEH record at the top of stack frame
|
|
16
29
|
- Optimize Koffi binaries produced by GCC (with `-fno-semantic-interposition`)
|
|
17
|
-
- Fix nonsensical addresses in Koffi call dumps (when using DUMP_CALLS=1
|
|
30
|
+
- Fix nonsensical addresses in Koffi call dumps (when using DUMP_CALLS=1 environment variable)
|
|
18
31
|
|
|
19
32
|
- Reduce Koffi package size even more:
|
|
20
33
|
* Replace table of callback trampoline pointers with simple offset computation
|
|
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
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/index.js
CHANGED
|
@@ -398,7 +398,7 @@ var require_package = __commonJS({
|
|
|
398
398
|
"../../bin/Koffi/package/src/koffi/package.json"(exports2, module2) {
|
|
399
399
|
module2.exports = {
|
|
400
400
|
name: "koffi",
|
|
401
|
-
version: "2.16.
|
|
401
|
+
version: "2.16.2",
|
|
402
402
|
description: "Fast and simple C FFI (foreign function interface) for Node.js",
|
|
403
403
|
keywords: [
|
|
404
404
|
"foreign",
|
package/indirect.js
CHANGED
|
@@ -398,7 +398,7 @@ var require_package = __commonJS({
|
|
|
398
398
|
"../../bin/Koffi/package/src/koffi/package.json"(exports2, module2) {
|
|
399
399
|
module2.exports = {
|
|
400
400
|
name: "koffi",
|
|
401
|
-
version: "2.16.
|
|
401
|
+
version: "2.16.2",
|
|
402
402
|
description: "Fast and simple C FFI (foreign function interface) for Node.js",
|
|
403
403
|
keywords: [
|
|
404
404
|
"foreign",
|
package/package.json
CHANGED
|
@@ -544,15 +544,12 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
|
|
|
544
544
|
|
|
545
545
|
void CallData::Relay(Size idx, uint8_t *sp)
|
|
546
546
|
{
|
|
547
|
+
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
548
|
+
|
|
547
549
|
uint8_t *own_sp = sp;
|
|
548
550
|
uint8_t *caller_sp = sp + 128;
|
|
549
551
|
BackRegisters *out_reg = (BackRegisters *)(sp + 80);
|
|
550
552
|
|
|
551
|
-
if (env.IsExceptionPending()) [[unlikely]]
|
|
552
|
-
return;
|
|
553
|
-
|
|
554
|
-
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
555
|
-
|
|
556
553
|
const FunctionInfo *proto = trampoline.proto;
|
|
557
554
|
Napi::Function func = trampoline.func.Value();
|
|
558
555
|
|
|
@@ -565,11 +562,6 @@ void CallData::Relay(Size idx, uint8_t *sp)
|
|
|
565
562
|
|
|
566
563
|
K_DEFER_N(err_guard) { memset(out_reg, 0, K_SIZE(*out_reg)); };
|
|
567
564
|
|
|
568
|
-
if (trampoline.generation >= 0 && trampoline.generation != (int32_t)mem->generation) [[unlikely]] {
|
|
569
|
-
ThrowError<Napi::Error>(env, "Cannot use non-registered callback beyond FFI call");
|
|
570
|
-
return;
|
|
571
|
-
}
|
|
572
|
-
|
|
573
565
|
LocalArray<napi_value, MaxParameters + 1> arguments;
|
|
574
566
|
|
|
575
567
|
arguments.Append(!trampoline.recv.IsEmpty() ? trampoline.recv.Value() : env.Undefined());
|
|
@@ -693,33 +693,12 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
|
|
|
693
693
|
|
|
694
694
|
void CallData::Relay(Size idx, uint8_t *sp)
|
|
695
695
|
{
|
|
696
|
+
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
697
|
+
|
|
696
698
|
uint8_t *own_sp = sp;
|
|
697
699
|
uint8_t *caller_sp = sp + 208;
|
|
698
700
|
BackRegisters *out_reg = (BackRegisters *)(sp + 136);
|
|
699
701
|
|
|
700
|
-
if (env.IsExceptionPending()) [[unlikely]]
|
|
701
|
-
return;
|
|
702
|
-
|
|
703
|
-
#if defined(_WIN32)
|
|
704
|
-
TEB *teb = GetTEB();
|
|
705
|
-
|
|
706
|
-
// Restore previous stack limits at the end
|
|
707
|
-
K_DEFER_C(base = teb->StackBase,
|
|
708
|
-
limit = teb->StackLimit,
|
|
709
|
-
dealloc = teb->DeallocationStack) {
|
|
710
|
-
teb->StackBase = base;
|
|
711
|
-
teb->StackLimit = limit;
|
|
712
|
-
teb->DeallocationStack = dealloc;
|
|
713
|
-
};
|
|
714
|
-
|
|
715
|
-
// Adjust stack limits so SEH works correctly
|
|
716
|
-
teb->StackBase = instance->main_stack_max;
|
|
717
|
-
teb->StackLimit = instance->main_stack_min;
|
|
718
|
-
teb->DeallocationStack = instance->main_stack_min;
|
|
719
|
-
#endif
|
|
720
|
-
|
|
721
|
-
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
722
|
-
|
|
723
702
|
const FunctionInfo *proto = trampoline.proto;
|
|
724
703
|
Napi::Function func = trampoline.func.Value();
|
|
725
704
|
|
|
@@ -731,11 +710,6 @@ void CallData::Relay(Size idx, uint8_t *sp)
|
|
|
731
710
|
|
|
732
711
|
K_DEFER_N(err_guard) { memset(out_reg, 0, K_SIZE(*out_reg)); };
|
|
733
712
|
|
|
734
|
-
if (trampoline.generation >= 0 && trampoline.generation != (int32_t)mem->generation) [[unlikely]] {
|
|
735
|
-
ThrowError<Napi::Error>(env, "Cannot use non-registered callback beyond FFI call");
|
|
736
|
-
return;
|
|
737
|
-
}
|
|
738
|
-
|
|
739
713
|
LocalArray<napi_value, MaxParameters + 1> arguments;
|
|
740
714
|
|
|
741
715
|
arguments.Append(!trampoline.recv.IsEmpty() ? trampoline.recv.Value() : env.Undefined());
|
|
@@ -141,7 +141,7 @@ ForwardCallXDD:
|
|
|
141
141
|
.macro trampoline id
|
|
142
142
|
li.d $t0, \id
|
|
143
143
|
b RelayTrampoline
|
|
144
|
-
.
|
|
144
|
+
.balign 16
|
|
145
145
|
.endm
|
|
146
146
|
|
|
147
147
|
RelayTrampoline:
|
|
@@ -197,7 +197,7 @@ SwitchAndRelay:
|
|
|
197
197
|
addi.d $sp, $sp, 16
|
|
198
198
|
jr $ra
|
|
199
199
|
|
|
200
|
-
.
|
|
200
|
+
.balign 16
|
|
201
201
|
#include "gnu.inc"
|
|
202
202
|
|
|
203
203
|
TrampolineEnd:
|
|
@@ -485,15 +485,12 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
|
|
|
485
485
|
|
|
486
486
|
void CallData::Relay(Size idx, uint8_t *sp)
|
|
487
487
|
{
|
|
488
|
+
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
489
|
+
|
|
488
490
|
uint8_t *own_sp = sp;
|
|
489
491
|
uint8_t *caller_sp = sp + 168;
|
|
490
492
|
BackRegisters *out_reg = (BackRegisters *)(sp + 128);
|
|
491
493
|
|
|
492
|
-
if (env.IsExceptionPending()) [[unlikely]]
|
|
493
|
-
return;
|
|
494
|
-
|
|
495
|
-
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
496
|
-
|
|
497
494
|
const FunctionInfo *proto = trampoline.proto;
|
|
498
495
|
Napi::Function func = trampoline.func.Value();
|
|
499
496
|
|
|
@@ -506,11 +503,6 @@ void CallData::Relay(Size idx, uint8_t *sp)
|
|
|
506
503
|
|
|
507
504
|
K_DEFER_N(err_guard) { memset(out_reg, 0, K_SIZE(*out_reg)); };
|
|
508
505
|
|
|
509
|
-
if (trampoline.generation >= 0 && trampoline.generation != (int32_t)mem->generation) [[unlikely]] {
|
|
510
|
-
ThrowError<Napi::Error>(env, "Cannot use non-registered callback beyond FFI call");
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
506
|
LocalArray<napi_value, MaxParameters + 1> arguments;
|
|
515
507
|
|
|
516
508
|
arguments.Append(!trampoline.recv.IsEmpty() ? trampoline.recv.Value() : env.Undefined());
|
|
@@ -141,7 +141,7 @@ ForwardCallXDD:
|
|
|
141
141
|
.macro trampoline id
|
|
142
142
|
li t0, \id
|
|
143
143
|
j RelayTrampoline
|
|
144
|
-
.
|
|
144
|
+
.balign 16
|
|
145
145
|
.endm
|
|
146
146
|
|
|
147
147
|
RelayTrampoline:
|
|
@@ -196,7 +196,7 @@ SwitchAndRelay:
|
|
|
196
196
|
addi sp, sp, 16
|
|
197
197
|
ret
|
|
198
198
|
|
|
199
|
-
.
|
|
199
|
+
.balign 16
|
|
200
200
|
#include "gnu.inc"
|
|
201
201
|
|
|
202
202
|
TrampolineEnd:
|
|
@@ -521,15 +521,12 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
|
|
|
521
521
|
|
|
522
522
|
void CallData::Relay(Size idx, uint8_t *sp)
|
|
523
523
|
{
|
|
524
|
+
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
525
|
+
|
|
524
526
|
uint8_t *own_sp = sp;
|
|
525
527
|
uint8_t *caller_sp = sp + 160;
|
|
526
528
|
BackRegisters *out_reg = (BackRegisters *)(sp + 112);
|
|
527
529
|
|
|
528
|
-
if (env.IsExceptionPending()) [[unlikely]]
|
|
529
|
-
return;
|
|
530
|
-
|
|
531
|
-
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
532
|
-
|
|
533
530
|
const FunctionInfo *proto = trampoline.proto;
|
|
534
531
|
Napi::Function func = trampoline.func.Value();
|
|
535
532
|
|
|
@@ -542,11 +539,6 @@ void CallData::Relay(Size idx, uint8_t *sp)
|
|
|
542
539
|
|
|
543
540
|
K_DEFER_N(err_guard) { memset(out_reg, 0, K_SIZE(*out_reg)); };
|
|
544
541
|
|
|
545
|
-
if (trampoline.generation >= 0 && trampoline.generation != (int32_t)mem->generation) [[unlikely]] {
|
|
546
|
-
ThrowError<Napi::Error>(env, "Cannot use non-registered callback beyond FFI call");
|
|
547
|
-
return;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
542
|
LocalArray<napi_value, MaxParameters + 1> arguments;
|
|
551
543
|
|
|
552
544
|
arguments.Append(!trampoline.recv.IsEmpty() ? trampoline.recv.Value() : env.Undefined());
|
|
@@ -327,31 +327,12 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
|
|
|
327
327
|
|
|
328
328
|
void CallData::Relay(Size idx, uint8_t *sp)
|
|
329
329
|
{
|
|
330
|
+
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
331
|
+
|
|
330
332
|
uint8_t *own_sp = sp;
|
|
331
333
|
uint8_t *caller_sp = sp + 128;
|
|
332
334
|
BackRegisters *out_reg = (BackRegisters *)(sp + 64);
|
|
333
335
|
|
|
334
|
-
if (env.IsExceptionPending()) [[unlikely]]
|
|
335
|
-
return;
|
|
336
|
-
|
|
337
|
-
TEB *teb = GetTEB();
|
|
338
|
-
|
|
339
|
-
// Restore previous stack limits at the end
|
|
340
|
-
K_DEFER_C(base = teb->StackBase,
|
|
341
|
-
limit = teb->StackLimit,
|
|
342
|
-
dealloc = teb->DeallocationStack) {
|
|
343
|
-
teb->StackBase = base;
|
|
344
|
-
teb->StackLimit = limit;
|
|
345
|
-
teb->DeallocationStack = dealloc;
|
|
346
|
-
};
|
|
347
|
-
|
|
348
|
-
// Adjust stack limits so SEH works correctly
|
|
349
|
-
teb->StackBase = instance->main_stack_max;
|
|
350
|
-
teb->StackLimit = instance->main_stack_min;
|
|
351
|
-
teb->DeallocationStack = instance->main_stack_min;
|
|
352
|
-
|
|
353
|
-
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
354
|
-
|
|
355
336
|
const FunctionInfo *proto = trampoline.proto;
|
|
356
337
|
Napi::Function func = trampoline.func.Value();
|
|
357
338
|
|
|
@@ -363,11 +344,6 @@ void CallData::Relay(Size idx, uint8_t *sp)
|
|
|
363
344
|
|
|
364
345
|
K_DEFER_N(err_guard) { memset(out_reg, 0, K_SIZE(*out_reg)); };
|
|
365
346
|
|
|
366
|
-
if (trampoline.generation >= 0 && trampoline.generation != (int32_t)mem->generation) [[unlikely]] {
|
|
367
|
-
ThrowError<Napi::Error>(env, "Cannot use non-registered callback beyond FFI call");
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
347
|
LocalArray<napi_value, MaxParameters + 1> arguments;
|
|
372
348
|
|
|
373
349
|
arguments.Append(!trampoline.recv.IsEmpty() ? trampoline.recv.Value() : env.Undefined());
|
package/src/koffi/src/abi_x86.cc
CHANGED
|
@@ -441,32 +441,11 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
|
|
|
441
441
|
|
|
442
442
|
void CallData::Relay(Size idx, uint8_t *sp)
|
|
443
443
|
{
|
|
444
|
+
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
445
|
+
|
|
444
446
|
uint8_t *caller_sp = sp + 48;
|
|
445
447
|
BackRegisters *out_reg = (BackRegisters *)(sp + 16);
|
|
446
448
|
|
|
447
|
-
if (env.IsExceptionPending()) [[unlikely]]
|
|
448
|
-
return;
|
|
449
|
-
|
|
450
|
-
#if defined(_WIN32)
|
|
451
|
-
TEB *teb = GetTEB();
|
|
452
|
-
|
|
453
|
-
// Restore previous stack limits at the end
|
|
454
|
-
K_DEFER_C(base = teb->StackBase,
|
|
455
|
-
limit = teb->StackLimit,
|
|
456
|
-
dealloc = teb->DeallocationStack) {
|
|
457
|
-
teb->StackBase = base;
|
|
458
|
-
teb->StackLimit = limit;
|
|
459
|
-
teb->DeallocationStack = dealloc;
|
|
460
|
-
};
|
|
461
|
-
|
|
462
|
-
// Adjust stack limits so SEH works correctly
|
|
463
|
-
teb->StackBase = instance->main_stack_max;
|
|
464
|
-
teb->StackLimit = instance->main_stack_min;
|
|
465
|
-
teb->DeallocationStack = instance->main_stack_min;
|
|
466
|
-
#endif
|
|
467
|
-
|
|
468
|
-
const TrampolineInfo &trampoline = shared.trampolines[idx];
|
|
469
|
-
|
|
470
449
|
const FunctionInfo *proto = trampoline.proto;
|
|
471
450
|
Napi::Function func = trampoline.func.Value();
|
|
472
451
|
|
|
@@ -492,11 +471,6 @@ void CallData::Relay(Size idx, uint8_t *sp)
|
|
|
492
471
|
out_reg->ret_pop = pop;
|
|
493
472
|
};
|
|
494
473
|
|
|
495
|
-
if (trampoline.generation >= 0 && trampoline.generation != (int32_t)mem->generation) [[unlikely]] {
|
|
496
|
-
ThrowError<Napi::Error>(env, "Cannot use non-registered callback beyond FFI call");
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
474
|
LocalArray<napi_value, MaxParameters + 1> arguments;
|
|
501
475
|
|
|
502
476
|
arguments.Append(!trampoline.recv.IsEmpty() ? trampoline.recv.Value() : env.Undefined());
|
|
@@ -109,6 +109,8 @@ RelayTrampoline:
|
|
|
109
109
|
.cfi_def_cfa esp, 48
|
|
110
110
|
movl %eax, 0(%esp)
|
|
111
111
|
movl %esp, 4(%esp)
|
|
112
|
+
movl $0, 32(%esp)
|
|
113
|
+
movl $0, 36(%esp)
|
|
112
114
|
call GetEIP
|
|
113
115
|
addl $_GLOBAL_OFFSET_TABLE_, %eax
|
|
114
116
|
call *RelayCallback@GOT(%eax)
|
|
@@ -172,13 +174,13 @@ SwitchAndRelay:
|
|
|
172
174
|
ret
|
|
173
175
|
.cfi_endproc
|
|
174
176
|
|
|
175
|
-
.
|
|
177
|
+
.balign 16
|
|
176
178
|
FindTrampolineStart:
|
|
177
179
|
call GetEIP
|
|
178
180
|
addl $16, %eax
|
|
179
181
|
andl $0xFFFFFFF0, %eax
|
|
180
182
|
ret
|
|
181
|
-
.
|
|
183
|
+
.balign 16
|
|
182
184
|
|
|
183
185
|
#include "gnu.inc"
|
|
184
186
|
|
package/src/koffi/src/call.cc
CHANGED
|
@@ -31,7 +31,6 @@ CallData::CallData(Napi::Env env, InstanceData *instance, InstanceMemory *mem)
|
|
|
31
31
|
: env(env), instance(instance),
|
|
32
32
|
mem(mem), old_stack_mem(mem->stack), old_heap_mem(mem->heap)
|
|
33
33
|
{
|
|
34
|
-
mem->generation += !mem->depth;
|
|
35
34
|
mem->depth++;
|
|
36
35
|
|
|
37
36
|
K_ASSERT(AlignUp(mem->stack.ptr, 16) == mem->stack.ptr);
|
|
@@ -64,9 +63,9 @@ void CallData::Dispose()
|
|
|
64
63
|
K_ASSERT(trampoline->instance == instance);
|
|
65
64
|
K_ASSERT(!trampoline->func.IsEmpty());
|
|
66
65
|
|
|
67
|
-
trampoline->instance = nullptr;
|
|
68
66
|
trampoline->func.Reset();
|
|
69
67
|
trampoline->recv.Reset();
|
|
68
|
+
trampoline->used = false;
|
|
70
69
|
|
|
71
70
|
shared.available.Append(idx);
|
|
72
71
|
}
|
|
@@ -152,14 +151,22 @@ Size CallData::PushStringValue(Napi::Value value, const char **out_str)
|
|
|
152
151
|
napi_status status;
|
|
153
152
|
|
|
154
153
|
buf.ptr = (char *)mem->heap.ptr;
|
|
155
|
-
buf.len =
|
|
154
|
+
buf.len = mem->heap.len;
|
|
156
155
|
|
|
157
156
|
status = napi_get_value_string_utf8(env, value, buf.ptr, (size_t)buf.len, &len);
|
|
158
157
|
K_ASSERT(status == napi_ok);
|
|
159
158
|
|
|
160
159
|
len++;
|
|
161
160
|
|
|
162
|
-
|
|
161
|
+
// V8 can truncate the string and return a length that is less than the real string
|
|
162
|
+
// length in several cases, such as when it flattens string ropes.
|
|
163
|
+
// This was the cause of a truncation bug (see https://github.com/Koromix/koffi/issues/266),
|
|
164
|
+
// which went unnoticed for a long time.
|
|
165
|
+
// We don't want to query the length beforehand, because it's slow. Instead, check that the
|
|
166
|
+
// returned lengfth is much shorter than the available buffer capacity, and if so, we know
|
|
167
|
+
// we're okay because V8 flattens strings ~32 KiB at a time.
|
|
168
|
+
|
|
169
|
+
if ((Size)len < buf.len - Kibibytes(64)) [[likely]] {
|
|
163
170
|
mem->heap.ptr += (Size)len;
|
|
164
171
|
mem->heap.len -= (Size)len;
|
|
165
172
|
} else {
|
|
@@ -187,14 +194,14 @@ Size CallData::PushString16Value(Napi::Value value, const char16_t **out_str16)
|
|
|
187
194
|
|
|
188
195
|
mem->heap.ptr = AlignUp(mem->heap.ptr, 2);
|
|
189
196
|
buf.ptr = (char16_t *)mem->heap.ptr;
|
|
190
|
-
buf.len =
|
|
197
|
+
buf.len = mem->heap.len / 2;
|
|
191
198
|
|
|
192
199
|
status = napi_get_value_string_utf16(env, value, buf.ptr, (size_t)buf.len, &len);
|
|
193
200
|
K_ASSERT(status == napi_ok);
|
|
194
201
|
|
|
195
202
|
len++;
|
|
196
203
|
|
|
197
|
-
if (len <
|
|
204
|
+
if ((Size)len < buf.len - Kibibytes(64) / 2) [[likely]] {
|
|
198
205
|
mem->heap.ptr += (Size)len * 2;
|
|
199
206
|
mem->heap.len -= (Size)len * 2;
|
|
200
207
|
} else {
|
|
@@ -227,7 +234,7 @@ Size CallData::PushString32Value(Napi::Value value, const char32_t **out_str32)
|
|
|
227
234
|
|
|
228
235
|
mem->heap.ptr = AlignUp(mem->heap.ptr, 4);
|
|
229
236
|
buf.ptr = (char32_t *)mem->heap.ptr;
|
|
230
|
-
buf.len =
|
|
237
|
+
buf.len = mem->heap.len / 4;
|
|
231
238
|
|
|
232
239
|
if (buf16.len < buf.len) [[likely]] {
|
|
233
240
|
mem->heap.ptr += buf16.len * 4;
|
|
@@ -1142,7 +1149,7 @@ void *CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func
|
|
|
1142
1149
|
trampoline->proto = proto;
|
|
1143
1150
|
trampoline->func.Reset(func, 1);
|
|
1144
1151
|
trampoline->recv.Reset();
|
|
1145
|
-
trampoline->
|
|
1152
|
+
trampoline->used = true;
|
|
1146
1153
|
|
|
1147
1154
|
void *ptr = GetTrampoline(idx);
|
|
1148
1155
|
|
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -1728,10 +1728,6 @@ extern "C" void RelayCallback(Size idx, uint8_t *sp)
|
|
|
1728
1728
|
return;
|
|
1729
1729
|
}
|
|
1730
1730
|
|
|
1731
|
-
// Avoid triggering the "use callback beyond FFI" check
|
|
1732
|
-
K_DEFER_C(generation = trampoline->generation) { trampoline->generation = generation; };
|
|
1733
|
-
trampoline->generation = -1;
|
|
1734
|
-
|
|
1735
1731
|
if (std::this_thread::get_id() == instance->main_thread_id) {
|
|
1736
1732
|
CallData call(env, instance, mem);
|
|
1737
1733
|
|
|
@@ -1745,6 +1741,35 @@ extern "C" void RelayCallback(Size idx, uint8_t *sp)
|
|
|
1745
1741
|
|
|
1746
1742
|
extern "C" void RelayDirect(CallData *call, Size idx, uint8_t *sp)
|
|
1747
1743
|
{
|
|
1744
|
+
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
1745
|
+
Napi::Env env = trampoline->func.Env();
|
|
1746
|
+
|
|
1747
|
+
#if defined(_WIN32)
|
|
1748
|
+
TEB *teb = GetTEB();
|
|
1749
|
+
InstanceData *instance = trampoline->instance;
|
|
1750
|
+
|
|
1751
|
+
// Restore previous stack limits at the end
|
|
1752
|
+
K_DEFER_C(base = teb->StackBase,
|
|
1753
|
+
limit = teb->StackLimit,
|
|
1754
|
+
dealloc = teb->DeallocationStack) {
|
|
1755
|
+
teb->StackBase = base;
|
|
1756
|
+
teb->StackLimit = limit;
|
|
1757
|
+
teb->DeallocationStack = dealloc;
|
|
1758
|
+
};
|
|
1759
|
+
|
|
1760
|
+
// Adjust stack limits so SEH works correctly
|
|
1761
|
+
teb->StackBase = instance->main_stack_max;
|
|
1762
|
+
teb->StackLimit = instance->main_stack_min;
|
|
1763
|
+
teb->DeallocationStack = instance->main_stack_min;
|
|
1764
|
+
#endif
|
|
1765
|
+
|
|
1766
|
+
if (env.IsExceptionPending()) [[unlikely]]
|
|
1767
|
+
return;
|
|
1768
|
+
if (!trampoline->used) [[unlikely]] {
|
|
1769
|
+
ThrowError<Napi::Error>(env, "Cannot use non-registered callback beyond FFI call");
|
|
1770
|
+
return;
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1748
1773
|
Napi::HandleScope scope(call->env);
|
|
1749
1774
|
call->Relay(idx, sp);
|
|
1750
1775
|
}
|
|
@@ -2020,7 +2045,7 @@ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
|
|
|
2020
2045
|
} else {
|
|
2021
2046
|
trampoline->recv.Reset();
|
|
2022
2047
|
}
|
|
2023
|
-
trampoline->
|
|
2048
|
+
trampoline->used = true;
|
|
2024
2049
|
|
|
2025
2050
|
void *ptr = GetTrampoline(idx);
|
|
2026
2051
|
|
|
@@ -2072,6 +2097,7 @@ static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
|
|
|
2072
2097
|
|
|
2073
2098
|
trampoline->func.Reset();
|
|
2074
2099
|
trampoline->recv.Reset();
|
|
2100
|
+
trampoline->used = false;
|
|
2075
2101
|
|
|
2076
2102
|
shared.available.Append(idx);
|
|
2077
2103
|
}
|
|
@@ -2665,6 +2691,7 @@ InstanceData::~InstanceData()
|
|
|
2665
2691
|
trampoline->instance = nullptr;
|
|
2666
2692
|
trampoline->func.Reset();
|
|
2667
2693
|
trampoline->recv.Reset();
|
|
2694
|
+
trampoline->used = false;
|
|
2668
2695
|
}
|
|
2669
2696
|
}
|
|
2670
2697
|
}
|
package/src/koffi/src/ffi.hh
CHANGED
|
@@ -249,8 +249,6 @@ struct InstanceMemory {
|
|
|
249
249
|
Span<uint8_t> stack0;
|
|
250
250
|
Span<uint8_t> heap;
|
|
251
251
|
|
|
252
|
-
uint16_t generation; // Can wrap without risk
|
|
253
|
-
|
|
254
252
|
bool busy;
|
|
255
253
|
bool temporary;
|
|
256
254
|
int depth;
|
|
@@ -322,7 +320,7 @@ struct TrampolineInfo {
|
|
|
322
320
|
Napi::FunctionReference func;
|
|
323
321
|
Napi::Reference<Napi::Value> recv;
|
|
324
322
|
|
|
325
|
-
|
|
323
|
+
bool used;
|
|
326
324
|
};
|
|
327
325
|
|
|
328
326
|
struct SharedData {
|