koffi 2.14.0-beta.1 → 2.14.0-beta.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.
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
@@ -4,9 +4,9 @@ var __commonJS = (cb, mod3) => function __require() {
4
4
  return mod3 || (0, cb[__getOwnPropNames(cb)[0]])((mod3 = { exports: {} }).exports, mod3), mod3.exports;
5
5
  };
6
6
 
7
- // ../../bin/Koffi/package/src/cnoke/src/tools.js
7
+ // ../../../bin/Koffi/package/src/cnoke/src/tools.js
8
8
  var require_tools = __commonJS({
9
- "../../bin/Koffi/package/src/cnoke/src/tools.js"(exports2, module2) {
9
+ "../../../bin/Koffi/package/src/cnoke/src/tools.js"(exports2, module2) {
10
10
  "use strict";
11
11
  var crypto = require("crypto");
12
12
  var fs2 = require("fs");
@@ -397,12 +397,12 @@ var require_tools = __commonJS({
397
397
  }
398
398
  });
399
399
 
400
- // ../../bin/Koffi/package/src/koffi/package.json
400
+ // ../../../bin/Koffi/package/src/koffi/package.json
401
401
  var require_package = __commonJS({
402
- "../../bin/Koffi/package/src/koffi/package.json"(exports2, module2) {
402
+ "../../../bin/Koffi/package/src/koffi/package.json"(exports2, module2) {
403
403
  module2.exports = {
404
404
  name: "koffi",
405
- version: "2.14.0-beta.1",
405
+ version: "2.14.0-beta.2",
406
406
  description: "Fast and simple C FFI (foreign function interface) for Node.js",
407
407
  keywords: [
408
408
  "foreign",
@@ -443,9 +443,9 @@ var require_package = __commonJS({
443
443
  }
444
444
  });
445
445
 
446
- // ../../bin/Koffi/package/src/koffi/src/init.js
446
+ // ../../../bin/Koffi/package/src/koffi/src/init.js
447
447
  var require_init = __commonJS({
448
- "../../bin/Koffi/package/src/koffi/src/init.js"(exports, module) {
448
+ "../../../bin/Koffi/package/src/koffi/src/init.js"(exports, module) {
449
449
  var fs = require("fs");
450
450
  var path = require("path");
451
451
  var util = require("util");
@@ -528,7 +528,7 @@ var require_init = __commonJS({
528
528
  }
529
529
  });
530
530
 
531
- // ../../bin/Koffi/package/src/koffi/index.js
531
+ // ../../../bin/Koffi/package/src/koffi/index.js
532
532
  var { detect: detect2, init: init2 } = require_init();
533
533
  var triplet2 = detect2();
534
534
  var native2 = null;
package/indirect.js CHANGED
@@ -4,9 +4,9 @@ var __commonJS = (cb, mod3) => function __require() {
4
4
  return mod3 || (0, cb[__getOwnPropNames(cb)[0]])((mod3 = { exports: {} }).exports, mod3), mod3.exports;
5
5
  };
6
6
 
7
- // ../../bin/Koffi/package/src/cnoke/src/tools.js
7
+ // ../../../bin/Koffi/package/src/cnoke/src/tools.js
8
8
  var require_tools = __commonJS({
9
- "../../bin/Koffi/package/src/cnoke/src/tools.js"(exports2, module2) {
9
+ "../../../bin/Koffi/package/src/cnoke/src/tools.js"(exports2, module2) {
10
10
  "use strict";
11
11
  var crypto = require("crypto");
12
12
  var fs2 = require("fs");
@@ -397,12 +397,12 @@ var require_tools = __commonJS({
397
397
  }
398
398
  });
399
399
 
400
- // ../../bin/Koffi/package/src/koffi/package.json
400
+ // ../../../bin/Koffi/package/src/koffi/package.json
401
401
  var require_package = __commonJS({
402
- "../../bin/Koffi/package/src/koffi/package.json"(exports2, module2) {
402
+ "../../../bin/Koffi/package/src/koffi/package.json"(exports2, module2) {
403
403
  module2.exports = {
404
404
  name: "koffi",
405
- version: "2.14.0-beta.1",
405
+ version: "2.14.0-beta.2",
406
406
  description: "Fast and simple C FFI (foreign function interface) for Node.js",
407
407
  keywords: [
408
408
  "foreign",
@@ -443,9 +443,9 @@ var require_package = __commonJS({
443
443
  }
444
444
  });
445
445
 
446
- // ../../bin/Koffi/package/src/koffi/src/init.js
446
+ // ../../../bin/Koffi/package/src/koffi/src/init.js
447
447
  var require_init = __commonJS({
448
- "../../bin/Koffi/package/src/koffi/src/init.js"(exports, module) {
448
+ "../../../bin/Koffi/package/src/koffi/src/init.js"(exports, module) {
449
449
  var fs = require("fs");
450
450
  var path = require("path");
451
451
  var util = require("util");
@@ -528,7 +528,7 @@ var require_init = __commonJS({
528
528
  }
529
529
  });
530
530
 
531
- // ../../bin/Koffi/package/src/koffi/indirect.js
531
+ // ../../../bin/Koffi/package/src/koffi/indirect.js
532
532
  var { detect: detect2, init: init2 } = require_init();
533
533
  var triplet2 = detect2();
534
534
  var mod2 = init2(triplet2, null);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.14.0-beta.1",
3
+ "version": "2.14.0-beta.2",
4
4
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
5
5
  "keywords": [
6
6
  "foreign",
@@ -523,6 +523,13 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
523
523
  const RecordMember &member = members[i];
524
524
  Napi::Value value = obj.Get(member.name);
525
525
 
526
+ if (member.countedby >= 0) {
527
+ const char *countedby = members[member.countedby].name;
528
+
529
+ if (!CheckDynamicLength(obj, member.type->ref.type->size, countedby, value)) [[unlikely]]
530
+ return false;
531
+ }
532
+
526
533
  if (value.IsUndefined())
527
534
  continue;
528
535
 
@@ -1359,6 +1366,45 @@ void CallData::DumpForward(const FunctionInfo *func) const
1359
1366
  DumpMemory("Heap", heap);
1360
1367
  }
1361
1368
 
1369
+ bool CallData::CheckDynamicLength(Napi::Object obj, Size element, const char *countedby, Napi::Value value)
1370
+ {
1371
+ int64_t expected = -1;
1372
+ int64_t len = -1;
1373
+
1374
+ // Get expected length
1375
+ {
1376
+ Napi::Value by = obj.Get(countedby);
1377
+
1378
+ if (!by.IsNumber() && !by.IsBigInt()) [[unlikely]] {
1379
+ ThrowError<Napi::Error>(env, "Unexpected %1 value for dynamic length, expected number", GetValueType(instance, by));
1380
+ return false;
1381
+ }
1382
+
1383
+ expected = GetNumber<int64_t>(by);
1384
+ }
1385
+
1386
+ // Get actual length
1387
+ if (value.IsArray()) {
1388
+ Napi::Array array = value.As<Napi::Array>();
1389
+ len = array.Length();
1390
+ } else if (value.IsTypedArray()) {
1391
+ Napi::TypedArray typed = value.As<Napi::TypedArray>();
1392
+ len = typed.ByteLength() / element;
1393
+ } else if (value.IsArrayBuffer()) {
1394
+ Napi::ArrayBuffer buffer = value.As<Napi::ArrayBuffer>();
1395
+ len = buffer.ByteLength() / element;
1396
+ } else {
1397
+ len = !IsNullOrUndefined(value);
1398
+ }
1399
+
1400
+ if (len != expected) {
1401
+ ThrowError<Napi::Error>(env, "Mismatched dynamic length between '%1' and actual array", countedby);
1402
+ return false;
1403
+ }
1404
+
1405
+ return true;
1406
+ }
1407
+
1362
1408
  static inline Napi::Value GetReferenceValue(Napi::Env env, napi_ref ref)
1363
1409
  {
1364
1410
  napi_value value;
@@ -138,6 +138,8 @@ private:
138
138
  template <typename T = uint8_t>
139
139
  T *AllocHeap(Size size, Size align);
140
140
 
141
+ bool CheckDynamicLength(Napi::Object obj, Size element, const char *countedby, Napi::Value value);
142
+
141
143
  void PopOutArguments();
142
144
  };
143
145
 
@@ -232,33 +232,6 @@ static bool MapType(Napi::Env env, InstanceData *instance, const TypeInfo *type,
232
232
  return true;
233
233
  }
234
234
 
235
- static bool CheckDynamicMembers(Napi::Env env, TypeInfo *type)
236
- {
237
- for (RecordMember &member: type->members) {
238
- const char *countedby = member.type->countedby;
239
-
240
- if (countedby) {
241
- const RecordMember *by = std::find_if(type->members.begin(), type->members.end(),
242
- [&](const RecordMember &member) { return TestStr(member.name, countedby); });
243
-
244
- if (by == member.type->members.end()) {
245
- ThrowError<Napi::Error>(env, "Record type %1 does not have member '%2'", type->name, countedby);
246
- return false;
247
- }
248
- if (!IsInteger(by->type)) {
249
- ThrowError<Napi::Error>(env, "Dynamic length member %1 is not an integer", countedby);
250
- return false;
251
- }
252
-
253
- member.countedby = by - type->members.ptr;
254
- } else {
255
- member.countedby = -1;
256
- }
257
- }
258
-
259
- return true;
260
- }
261
-
262
235
  static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
263
236
  {
264
237
  Napi::Env env = info.Env();
@@ -399,8 +372,27 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
399
372
  type->members.Append(member);
400
373
  }
401
374
 
402
- if (!CheckDynamicMembers(env, type))
403
- return env.Null();
375
+ for (RecordMember &member: type->members) {
376
+ const char *countedby = member.type->countedby;
377
+
378
+ if (countedby) {
379
+ const RecordMember *by = std::find_if(type->members.begin(), type->members.end(),
380
+ [&](const RecordMember &member) { return TestStr(member.name, countedby); });
381
+
382
+ if (by == type->members.end()) {
383
+ ThrowError<Napi::Error>(env, "Record type %1 does not have member '%2'", type->name, countedby);
384
+ return env.Null();
385
+ }
386
+ if (!IsInteger(by->type)) {
387
+ ThrowError<Napi::Error>(env, "Dynamic length member %1 is not an integer", countedby);
388
+ return env.Null();
389
+ }
390
+
391
+ member.countedby = by - type->members.ptr;
392
+ } else {
393
+ member.countedby = -1;
394
+ }
395
+ }
404
396
 
405
397
  size = (int32_t)AlignLen(size, type->align);
406
398
  if (!size) {
@@ -537,11 +529,17 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
537
529
  ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a member (maybe try %1 *)", member.type->name);
538
530
  return env.Null();
539
531
  }
532
+ if (member.type->countedby) {
533
+ ThrowError<Napi::TypeError>(env, "Cannot use dynamic-length array or pointer inside of union");
534
+ return env.Null();
535
+ }
540
536
 
541
537
  align = align ? align : member.type->align;
542
538
  size = std::max(size, member.type->size);
543
539
  type->align = std::max(type->align, align);
544
540
 
541
+ member.countedby = -1;
542
+
545
543
  if (TestStr(member.name, "_"))
546
544
  continue;
547
545
 
@@ -561,9 +559,6 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
561
559
  type->members.Append(member);
562
560
  }
563
561
 
564
- if (!CheckDynamicMembers(env, type))
565
- return env.Null();
566
-
567
562
  size = (int32_t)AlignLen(size, type->align);
568
563
  if (!size) {
569
564
  ThrowError<Napi::Error>(env, "Empty union '%1' is not allowed in C", type->name);
@@ -483,6 +483,9 @@ Napi::External<TypeInfo> WrapType(Napi::Env env, InstanceData *instance, const T
483
483
 
484
484
  bool CanPassType(const TypeInfo *type, int directions)
485
485
  {
486
+ if (type->countedby)
487
+ return false;
488
+
486
489
  if (directions & 2) {
487
490
  if (type->primitive == PrimitiveKind::Pointer)
488
491
  return true;
@@ -510,6 +513,9 @@ bool CanPassType(const TypeInfo *type, int directions)
510
513
 
511
514
  bool CanReturnType(const TypeInfo *type)
512
515
  {
516
+ if (type->countedby)
517
+ return false;
518
+
513
519
  if (type->primitive == PrimitiveKind::Void && !TestStr(type->name, "void"))
514
520
  return false;
515
521
  if (type->primitive == PrimitiveKind::Array)