koffi 2.6.0 → 2.6.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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,11 @@
4
4
 
5
5
  ### Koffi 2.6
6
6
 
7
+ #### Koffi 2.6.1 (2023-09-18)
8
+
9
+ - Support string direction qualifiers in classic function definitions
10
+ - Fix possible off-by-one array access when parsing type name
11
+
7
12
  #### Koffi 2.6.0 (2023-09-13)
8
13
 
9
14
  **New features:**
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/variables.md CHANGED
@@ -97,4 +97,4 @@ console.log(koffi.decode(my_int, 'int')) // Prints -1
97
97
  console.log(koffi.decode(my_string, 'const char *')) // Prints "Hello World!"
98
98
  ```
99
99
 
100
- When encoding strings (either directly or embedded in arrays or structs), the memory will be bound to the raw pointer value and managed by Koffi. You can assign to the same string again and again with any leak or risk of use-after-free.
100
+ When encoding strings (either directly or embedded in arrays or structs), the memory will be bound to the raw pointer value and managed by Koffi. You can assign to the same string again and again without any leak or risk of use-after-free.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.6.0",
4
- "stable": "2.6.0",
3
+ "version": "2.6.1",
4
+ "stable": "2.6.1",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
7
7
  "foreign",
package/src/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.6.0",
382
- stable: "2.6.0",
381
+ version: "2.6.1",
382
+ stable: "2.6.1",
383
383
  description: "Fast and simple C FFI (foreign function interface) for Node.js",
384
384
  keywords: [
385
385
  "foreign",
@@ -35,7 +35,7 @@ bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
35
35
 
36
36
  Tokenize(str);
37
37
 
38
- out_func->ret.type = ParseType();
38
+ out_func->ret.type = ParseType(nullptr);
39
39
  if (!CanReturnType(out_func->ret.type)) {
40
40
  MarkError("You are not allowed to directly return %1 values (maybe try %1 *)", out_func->ret.type->name);
41
41
  return false;
@@ -62,17 +62,7 @@ bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
62
62
  break;
63
63
  }
64
64
 
65
- if (Match("_In_")) {
66
- param.directions = 1;
67
- } else if (Match("_Out_")) {
68
- param.directions = 2;
69
- } else if (Match("_Inout_")) {
70
- param.directions = 3;
71
- } else {
72
- param.directions = 1;
73
- }
74
-
75
- param.type = ParseType();
65
+ param.type = ParseType(&param.directions);
76
66
 
77
67
  if (!CanPassType(param.type, param.directions)) {
78
68
  MarkError("Type %1 cannot be used as a parameter", param.type->name);
@@ -145,7 +135,7 @@ void PrototypeParser::Tokenize(const char *str)
145
135
  }
146
136
  }
147
137
 
148
- const TypeInfo *PrototypeParser::ParseType()
138
+ const TypeInfo *PrototypeParser::ParseType(int *out_directions)
149
139
  {
150
140
  Size start = offset;
151
141
 
@@ -166,7 +156,7 @@ const TypeInfo *PrototypeParser::ParseType()
166
156
 
167
157
  while (offset >= start) {
168
158
  Span<const char> str = MakeSpan(tokens[start].ptr, tokens[offset].end() - tokens[start].ptr);
169
- const TypeInfo *type = ResolveType(env, str);
159
+ const TypeInfo *type = ResolveType(env, str, out_directions);
170
160
 
171
161
  if (type) {
172
162
  offset++;
@@ -49,7 +49,7 @@ public:
49
49
  private:
50
50
  void Tokenize(const char *str);
51
51
 
52
- const TypeInfo *ParseType();
52
+ const TypeInfo *ParseType(int *out_directions);
53
53
  const char *ParseIdentifier();
54
54
 
55
55
  bool Consume(const char *expect);
@@ -153,6 +153,22 @@ static inline bool IsIdentifierChar(char c)
153
153
  return IsAsciiAlphaOrDigit(c) || c == '_';
154
154
  }
155
155
 
156
+ static inline Span<const char> SplitIdentifier(Span<const char> str)
157
+ {
158
+ Size offset = 0;
159
+
160
+ if (str.len && IsIdentifierStart(str[0])) {
161
+ offset++;
162
+
163
+ while (offset < str.len && IsIdentifierChar(str[offset])) {
164
+ offset++;
165
+ }
166
+ }
167
+
168
+ Span<const char> token = str.Take(0, offset);
169
+ return token;
170
+ }
171
+
156
172
  const TypeInfo *ResolveType(Napi::Env env, Span<const char> str, int *out_directions)
157
173
  {
158
174
  InstanceData *instance = env.GetInstanceData<InstanceData>();
@@ -160,8 +176,31 @@ const TypeInfo *ResolveType(Napi::Env env, Span<const char> str, int *out_direct
160
176
  int indirect = 0;
161
177
  uint8_t disposables = 0;
162
178
 
179
+ // Consume parameter direction qualifier
180
+ if (out_directions) {
181
+ if (str.len && str[0] == '_') {
182
+ Span<const char> qualifier = SplitIdentifier(str);
183
+
184
+ if (qualifier == "_In_") {
185
+ *out_directions = 1;
186
+ str = str.Take(5, str.len - 5);
187
+ } else if (qualifier == "_Out_") {
188
+ *out_directions = 2;
189
+ str = str.Take(6, str.len - 6);
190
+ } else if (qualifier == "_Inout_") {
191
+ *out_directions = 3;
192
+ str = str.Take(8, str.len - 8);
193
+ } else {
194
+ *out_directions = 1;
195
+ }
196
+ } else {
197
+ *out_directions = 1;
198
+ }
199
+ }
200
+
163
201
  // Skip initial const qualifiers
164
- while (str.len >= 6 && StartsWith(str, "const") && IsAsciiWhite(str[5])) {
202
+ str = TrimStr(str);
203
+ while (SplitIdentifier(str) == "const") {
165
204
  str = str.Take(6, str.len - 6);
166
205
  str = TrimStr(str);
167
206
  }
@@ -173,13 +212,10 @@ const TypeInfo *ResolveType(Napi::Env env, Span<const char> str, int *out_direct
173
212
  for (;;) {
174
213
  remain = TrimStr(remain);
175
214
 
176
- if (!remain.len || !IsIdentifierStart(remain[0]))
215
+ Span<const char> token = SplitIdentifier(remain);
216
+ if (!token.len)
177
217
  break;
178
-
179
- do {
180
- remain.ptr++;
181
- remain.len--;
182
- } while (remain.len && IsIdentifierChar(remain[0]));
218
+ remain = remain.Take(token.len, remain.len - token.len);
183
219
  }
184
220
 
185
221
  Span<const char> name = TrimStr(MakeSpan(str.ptr, remain.ptr - str.ptr));
@@ -197,7 +233,7 @@ const TypeInfo *ResolveType(Napi::Env env, Span<const char> str, int *out_direct
197
233
  } else if (remain[0] == '!') {
198
234
  remain = remain.Take(1, remain.len - 1);
199
235
  disposables |= (1u << indirect);
200
- } else if (remain.len >= 6 && StartsWith(remain, "const") && !IsIdentifierStart(remain[6])) {
236
+ } else if (SplitIdentifier(remain) == "const") {
201
237
  remain = remain.Take(6, remain.len - 6);
202
238
  } else {
203
239
  break;
@@ -263,9 +299,6 @@ const TypeInfo *ResolveType(Napi::Env env, Span<const char> str, int *out_direct
263
299
  RG_ASSERT(type);
264
300
  }
265
301
 
266
- if (out_directions) {
267
- *out_directions = 1;
268
- }
269
302
  return type;
270
303
  }
271
304