@react-native-quickjs/quickjs 1.0.0-alpha.1 → 1.0.0-alpha.3
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 +173 -15
- package/README.md +17 -0
- package/ReactNativeQuickJS.podspec +13 -1
- package/android/CMakeLists.txt +6 -0
- package/android/build.gradle +33 -6
- package/bin/qjsc/darwin-arm64/qjsc +0 -0
- package/bin/qjsc/darwin-x64/qjsc +0 -0
- package/bin/qjsc/linux-arm64/qjsc +0 -0
- package/bin/qjsc/linux-x64/qjsc +0 -0
- package/bin/qjsc/win32-x64/qjsc.exe +0 -0
- package/cmake/quickjs.cmake +9 -0
- package/engine/quickjs-rel/MANIFEST.json +118 -13
- package/engine/quickjs-rel/builtin-array-fromasync.h +100 -92
- package/engine/quickjs-rel/builtin-iterator-zip-keyed.h +288 -273
- package/engine/quickjs-rel/builtin-iterator-zip.h +293 -276
- package/engine/quickjs-rel/libregexp-backtrack.c.inc +583 -0
- package/engine/quickjs-rel/libregexp.c +1021 -573
- package/engine/quickjs-rel/libregexp.h +54 -2
- package/engine/quickjs-rel/libunicode-table.h +71 -84
- package/engine/quickjs-rel/libunicode.c +5 -0
- package/engine/quickjs-rel/quickjs-opcode.h +15 -6
- package/engine/quickjs-rel/quickjs.c +6581 -734
- package/engine/quickjs-rel/quickjs.h +43 -9
- package/package.json +15 -3
- package/src/runtime/QuickJSRuntime.cpp +18 -5
|
@@ -30,6 +30,9 @@
|
|
|
30
30
|
|
|
31
31
|
#include "cutils.h"
|
|
32
32
|
#include "libregexp.h"
|
|
33
|
+
#ifndef JS_RE_PREFILTER
|
|
34
|
+
#define JS_RE_PREFILTER 1
|
|
35
|
+
#endif
|
|
33
36
|
#include "libunicode.h"
|
|
34
37
|
|
|
35
38
|
/* ASCII identifier tables, used by lre_js_is_ident_first/next in libregexp.h
|
|
@@ -75,6 +78,14 @@ typedef enum {
|
|
|
75
78
|
enough to call the interrupt callback often. */
|
|
76
79
|
#define INTERRUPT_COUNTER_INIT 10000
|
|
77
80
|
|
|
81
|
+
/* Use GCC/Clang computed-goto (label-as-value) threaded dispatch in the
|
|
82
|
+
backtracking matcher where available; fall back to a plain switch. */
|
|
83
|
+
#if defined(EMSCRIPTEN) || defined(_MSC_VER)
|
|
84
|
+
#define LRE_DIRECT_DISPATCH 0
|
|
85
|
+
#else
|
|
86
|
+
#define LRE_DIRECT_DISPATCH 1
|
|
87
|
+
#endif
|
|
88
|
+
|
|
78
89
|
/* unicode code points */
|
|
79
90
|
#define CP_LS 0x2028
|
|
80
91
|
#define CP_PS 0x2029
|
|
@@ -132,6 +143,882 @@ static inline int lre_is_digit(int c) {
|
|
|
132
143
|
return c >= '0' && c <= '9';
|
|
133
144
|
}
|
|
134
145
|
|
|
146
|
+
/* ==== RegExp optimization metadata ====================================== *
|
|
147
|
+
* The compiler appends optional metadata after the opcode stream so that the
|
|
148
|
+
* quickjs fast paths can locate matches with direct string searches instead
|
|
149
|
+
* of running the backtracking interpreter at every input position. The three
|
|
150
|
+
* derived kinds are: a raw literal (LRE_META_LITERAL, whole pattern is a
|
|
151
|
+
* substring match), a required literal prefix (LRE_META_PREFIX), and a set of
|
|
152
|
+
* fixed first-character sets (LRE_META_FIRST_SET). */
|
|
153
|
+
|
|
154
|
+
/* Return true if the source pattern is a literal run of characters with no
|
|
155
|
+
metacharacters and no case/unicode folding, i.e. a plain substring. */
|
|
156
|
+
int lre_is_raw_atom(const char *buf, size_t len, int re_flags)
|
|
157
|
+
{
|
|
158
|
+
size_t i;
|
|
159
|
+
|
|
160
|
+
if (len == 0 ||
|
|
161
|
+
(re_flags & (LRE_FLAG_IGNORECASE | LRE_FLAG_STICKY |
|
|
162
|
+
LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS))) {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
for (i = 0; i < len; i++) {
|
|
166
|
+
switch ((uint8_t)buf[i]) {
|
|
167
|
+
case '\\': case '^': case '$': case '.': case '*': case '+':
|
|
168
|
+
case '?': case '(': case ')': case '[': case ']': case '{':
|
|
169
|
+
case '}': case '|':
|
|
170
|
+
return false;
|
|
171
|
+
default:
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* Match the synthetic ".*?" scan prologue emitted by lre_compile for
|
|
179
|
+
non-sticky patterns: split_goto_first(+6), any, goto(-11), save_start 0.
|
|
180
|
+
On success *pentry_pos is the offset of the leading save_start (11). */
|
|
181
|
+
static bool re_get_scan_entry(const uint8_t *bc_buf, size_t bc_buf_len,
|
|
182
|
+
size_t *pentry_pos)
|
|
183
|
+
{
|
|
184
|
+
const uint8_t *code;
|
|
185
|
+
|
|
186
|
+
if (bc_buf_len < RE_HEADER_LEN + 13)
|
|
187
|
+
return false;
|
|
188
|
+
code = bc_buf + RE_HEADER_LEN;
|
|
189
|
+
if (code[0] != REOP_split_goto_first || get_i32(code + 1) != 6 ||
|
|
190
|
+
code[5] != REOP_any || code[6] != REOP_goto ||
|
|
191
|
+
get_i32(code + 7) != -11 || code[11] != REOP_save_start ||
|
|
192
|
+
code[12] != 0) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
*pentry_pos = 11;
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/* Detect a pattern whose whole body is "save_start 0; char...; save_end 0;
|
|
200
|
+
match", i.e. a bare literal wrapped in the implicit capture 0. */
|
|
201
|
+
static bool re_has_literal_body(const uint8_t *bc_buf, size_t bc_buf_len,
|
|
202
|
+
int re_flags, int capture_count,
|
|
203
|
+
size_t *pchar_pos, uint32_t *plength,
|
|
204
|
+
int *pencoding)
|
|
205
|
+
{
|
|
206
|
+
const uint8_t *code;
|
|
207
|
+
size_t pos, char_pos;
|
|
208
|
+
uint32_t length, c;
|
|
209
|
+
int encoding;
|
|
210
|
+
|
|
211
|
+
if (capture_count != 1 ||
|
|
212
|
+
(re_flags & (LRE_FLAG_IGNORECASE | LRE_FLAG_STICKY |
|
|
213
|
+
LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) ||
|
|
214
|
+
bc_buf_len < RE_HEADER_LEN + 16 ||
|
|
215
|
+
!re_get_scan_entry(bc_buf, bc_buf_len, &char_pos)) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
code = bc_buf + RE_HEADER_LEN;
|
|
219
|
+
bc_buf_len -= RE_HEADER_LEN;
|
|
220
|
+
|
|
221
|
+
pos = char_pos = 13;
|
|
222
|
+
length = 0;
|
|
223
|
+
encoding = 0;
|
|
224
|
+
while (pos < bc_buf_len) {
|
|
225
|
+
if (code[pos] == REOP_char) {
|
|
226
|
+
if (pos + 3 > bc_buf_len)
|
|
227
|
+
return false;
|
|
228
|
+
c = get_u16(code + pos + 1);
|
|
229
|
+
pos += 3;
|
|
230
|
+
} else if (code[pos] == REOP_char32) {
|
|
231
|
+
if (pos + 5 > bc_buf_len)
|
|
232
|
+
return false;
|
|
233
|
+
c = get_u32(code + pos + 1);
|
|
234
|
+
if (c > 0xffff)
|
|
235
|
+
return false;
|
|
236
|
+
pos += 5;
|
|
237
|
+
} else {
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
if (c > 0xff)
|
|
241
|
+
encoding = 1;
|
|
242
|
+
if (length == UINT32_MAX)
|
|
243
|
+
return false;
|
|
244
|
+
length++;
|
|
245
|
+
}
|
|
246
|
+
if (length == 0 || pos + 3 != bc_buf_len ||
|
|
247
|
+
code[pos] != REOP_save_end || code[pos + 1] != 0 ||
|
|
248
|
+
code[pos + 2] != REOP_match) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
*pchar_pos = char_pos;
|
|
252
|
+
*plength = length;
|
|
253
|
+
*pencoding = encoding;
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/* Detect a required literal prefix (a run of chars that any match must begin
|
|
258
|
+
with), possibly shared by a leading two-way alternation. */
|
|
259
|
+
static bool re_get_linear_prefix(const uint8_t *bc_buf, size_t bc_buf_len,
|
|
260
|
+
int re_flags, size_t *pentry_pos,
|
|
261
|
+
size_t *pchar_pos, uint32_t *plength,
|
|
262
|
+
int *pencoding)
|
|
263
|
+
{
|
|
264
|
+
const uint8_t *code;
|
|
265
|
+
size_t pos, pos1, pos2, target;
|
|
266
|
+
uint32_t length, c, c1, c2;
|
|
267
|
+
int encoding;
|
|
268
|
+
|
|
269
|
+
if ((re_flags & (LRE_FLAG_IGNORECASE | LRE_FLAG_STICKY |
|
|
270
|
+
LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) ||
|
|
271
|
+
bc_buf_len < RE_HEADER_LEN + 16 ||
|
|
272
|
+
!re_get_scan_entry(bc_buf, bc_buf_len, &pos)) {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
code = bc_buf + RE_HEADER_LEN;
|
|
276
|
+
bc_buf_len -= RE_HEADER_LEN;
|
|
277
|
+
|
|
278
|
+
pos = 13;
|
|
279
|
+
if (code[pos] == REOP_split_goto_first ||
|
|
280
|
+
code[pos] == REOP_split_next_first) {
|
|
281
|
+
if (pos + 5 > bc_buf_len)
|
|
282
|
+
return false;
|
|
283
|
+
target = pos + 5 + get_i32(code + pos + 1);
|
|
284
|
+
if (target >= bc_buf_len)
|
|
285
|
+
return false;
|
|
286
|
+
pos1 = pos + 5;
|
|
287
|
+
pos2 = target;
|
|
288
|
+
length = 0;
|
|
289
|
+
encoding = 0;
|
|
290
|
+
for (;;) {
|
|
291
|
+
if (pos1 >= bc_buf_len || pos2 >= bc_buf_len)
|
|
292
|
+
break;
|
|
293
|
+
if (code[pos1] == REOP_char && pos1 + 3 <= bc_buf_len) {
|
|
294
|
+
c1 = get_u16(code + pos1 + 1);
|
|
295
|
+
pos1 += 3;
|
|
296
|
+
} else if (code[pos1] == REOP_char32 &&
|
|
297
|
+
pos1 + 5 <= bc_buf_len) {
|
|
298
|
+
c1 = get_u32(code + pos1 + 1);
|
|
299
|
+
pos1 += 5;
|
|
300
|
+
} else {
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
if (code[pos2] == REOP_char && pos2 + 3 <= bc_buf_len) {
|
|
304
|
+
c2 = get_u16(code + pos2 + 1);
|
|
305
|
+
pos2 += 3;
|
|
306
|
+
} else if (code[pos2] == REOP_char32 &&
|
|
307
|
+
pos2 + 5 <= bc_buf_len) {
|
|
308
|
+
c2 = get_u32(code + pos2 + 1);
|
|
309
|
+
pos2 += 5;
|
|
310
|
+
} else {
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
if (c1 != c2 || c1 > 0xffff)
|
|
314
|
+
break;
|
|
315
|
+
if (c1 > 0xff)
|
|
316
|
+
encoding = 1;
|
|
317
|
+
length++;
|
|
318
|
+
}
|
|
319
|
+
if (length == 0)
|
|
320
|
+
return false;
|
|
321
|
+
*pentry_pos = 11;
|
|
322
|
+
*pchar_pos = 18;
|
|
323
|
+
*plength = length;
|
|
324
|
+
*pencoding = encoding;
|
|
325
|
+
return true;
|
|
326
|
+
}
|
|
327
|
+
length = 0;
|
|
328
|
+
encoding = 0;
|
|
329
|
+
while (pos < bc_buf_len) {
|
|
330
|
+
if (code[pos] == REOP_char) {
|
|
331
|
+
if (pos + 3 > bc_buf_len)
|
|
332
|
+
return false;
|
|
333
|
+
c = get_u16(code + pos + 1);
|
|
334
|
+
pos += 3;
|
|
335
|
+
} else if (code[pos] == REOP_char32) {
|
|
336
|
+
if (pos + 5 > bc_buf_len)
|
|
337
|
+
return false;
|
|
338
|
+
c = get_u32(code + pos + 1);
|
|
339
|
+
if (c > 0xffff)
|
|
340
|
+
return false;
|
|
341
|
+
pos += 5;
|
|
342
|
+
} else {
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
if (c > 0xff)
|
|
346
|
+
encoding = 1;
|
|
347
|
+
if (length == UINT32_MAX)
|
|
348
|
+
return false;
|
|
349
|
+
length++;
|
|
350
|
+
}
|
|
351
|
+
if (length == 0)
|
|
352
|
+
return false;
|
|
353
|
+
*pentry_pos = 11;
|
|
354
|
+
*pchar_pos = 13;
|
|
355
|
+
*plength = length;
|
|
356
|
+
*pencoding = encoding;
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/* Append a metadata record (24-byte header + optional decoded payload) to the
|
|
361
|
+
compiled bytecode. */
|
|
362
|
+
static int re_append_metadata(REParseState *s, int kind, size_t entry_pos,
|
|
363
|
+
size_t char_pos, uint32_t length, int encoding,
|
|
364
|
+
int metadata_flags)
|
|
365
|
+
{
|
|
366
|
+
uint8_t header[LRE_META_HEADER_LEN];
|
|
367
|
+
size_t primary_payload_size, pos, code_len;
|
|
368
|
+
uint32_t c;
|
|
369
|
+
|
|
370
|
+
if (entry_pos > UINT32_MAX || (encoding && length > UINT32_MAX / 2))
|
|
371
|
+
return 0;
|
|
372
|
+
primary_payload_size = (metadata_flags & LRE_META_FLAG_SOURCE) ? 0 :
|
|
373
|
+
(size_t)length << encoding;
|
|
374
|
+
if (primary_payload_size > UINT32_MAX)
|
|
375
|
+
return 0;
|
|
376
|
+
code_len = get_u32(s->byte_code.buf + RE_HEADER_BYTECODE_LEN);
|
|
377
|
+
memset(header, 0, sizeof(header));
|
|
378
|
+
header[LRE_META_VERSION_OFFSET] = LRE_META_VERSION;
|
|
379
|
+
header[LRE_META_KIND_OFFSET] = kind;
|
|
380
|
+
header[LRE_META_ENCODING_OFFSET] = encoding;
|
|
381
|
+
header[LRE_META_FLAGS_OFFSET] = metadata_flags;
|
|
382
|
+
put_u32(header + LRE_META_PAYLOAD_SIZE_OFFSET, primary_payload_size);
|
|
383
|
+
put_u32(header + LRE_META_LENGTH_OFFSET, length);
|
|
384
|
+
put_u32(header + LRE_META_ENTRY_OFFSET, entry_pos);
|
|
385
|
+
dbuf_put(&s->byte_code, header, sizeof(header));
|
|
386
|
+
if (dbuf_error(&s->byte_code))
|
|
387
|
+
return -1;
|
|
388
|
+
|
|
389
|
+
pos = char_pos;
|
|
390
|
+
while (primary_payload_size != 0 && pos < code_len) {
|
|
391
|
+
if (s->byte_code.buf[RE_HEADER_LEN + pos] == REOP_char) {
|
|
392
|
+
c = get_u16(s->byte_code.buf + RE_HEADER_LEN + pos + 1);
|
|
393
|
+
pos += 3;
|
|
394
|
+
} else if (s->byte_code.buf[RE_HEADER_LEN + pos] == REOP_char32) {
|
|
395
|
+
c = get_u32(s->byte_code.buf + RE_HEADER_LEN + pos + 1);
|
|
396
|
+
pos += 5;
|
|
397
|
+
} else {
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
if (encoding)
|
|
401
|
+
dbuf_put_u16(&s->byte_code, c);
|
|
402
|
+
else
|
|
403
|
+
dbuf_putc(&s->byte_code, c);
|
|
404
|
+
if (--length == 0)
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
407
|
+
put_u16(s->byte_code.buf + RE_HEADER_FLAGS,
|
|
408
|
+
lre_get_flags(s->byte_code.buf) | LRE_FLAG_HAS_META);
|
|
409
|
+
return dbuf_error(&s->byte_code) ? -1 : 1;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
static int re_append_literal_metadata(REParseState *s, int re_flags,
|
|
413
|
+
bool payload_matches_source)
|
|
414
|
+
{
|
|
415
|
+
size_t char_pos, code_len;
|
|
416
|
+
uint32_t length;
|
|
417
|
+
int encoding;
|
|
418
|
+
|
|
419
|
+
code_len = get_u32(s->byte_code.buf + RE_HEADER_BYTECODE_LEN);
|
|
420
|
+
if (!re_has_literal_body(s->byte_code.buf, RE_HEADER_LEN + code_len,
|
|
421
|
+
re_flags, s->capture_count, &char_pos, &length,
|
|
422
|
+
&encoding)) {
|
|
423
|
+
return 0;
|
|
424
|
+
}
|
|
425
|
+
if (!payload_matches_source && length > LRE_LITERAL_MAX_LENGTH)
|
|
426
|
+
return 0;
|
|
427
|
+
if (re_append_metadata(s, LRE_META_LITERAL, 11, char_pos, length,
|
|
428
|
+
encoding, payload_matches_source ?
|
|
429
|
+
LRE_META_FLAG_SOURCE : 0) < 0)
|
|
430
|
+
return -1;
|
|
431
|
+
put_u16(s->byte_code.buf + RE_HEADER_FLAGS,
|
|
432
|
+
lre_get_flags(s->byte_code.buf) | LRE_FLAG_ATOM);
|
|
433
|
+
return 1;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
static int re_append_prefix_metadata(REParseState *s, int re_flags)
|
|
437
|
+
{
|
|
438
|
+
size_t entry_pos, char_pos, code_len, pos;
|
|
439
|
+
uint32_t c, i, length;
|
|
440
|
+
int encoding;
|
|
441
|
+
|
|
442
|
+
code_len = get_u32(s->byte_code.buf + RE_HEADER_BYTECODE_LEN);
|
|
443
|
+
if (!re_get_linear_prefix(s->byte_code.buf, RE_HEADER_LEN + code_len,
|
|
444
|
+
re_flags, &entry_pos, &char_pos, &length,
|
|
445
|
+
&encoding) || length < LRE_PREFIX_MIN_LENGTH) {
|
|
446
|
+
return 0;
|
|
447
|
+
}
|
|
448
|
+
if (length > LRE_PREFIX_MAX_LENGTH) {
|
|
449
|
+
length = LRE_PREFIX_MAX_LENGTH;
|
|
450
|
+
encoding = 0;
|
|
451
|
+
pos = char_pos;
|
|
452
|
+
for(i = 0; i < length; i++) {
|
|
453
|
+
if (s->byte_code.buf[RE_HEADER_LEN + pos] == REOP_char) {
|
|
454
|
+
c = get_u16(s->byte_code.buf + RE_HEADER_LEN + pos + 1);
|
|
455
|
+
pos += 3;
|
|
456
|
+
} else {
|
|
457
|
+
c = get_u32(s->byte_code.buf + RE_HEADER_LEN + pos + 1);
|
|
458
|
+
pos += 5;
|
|
459
|
+
}
|
|
460
|
+
if (c > 0xff)
|
|
461
|
+
encoding = 1;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return re_append_metadata(s, LRE_META_PREFIX, entry_pos, char_pos,
|
|
465
|
+
length, encoding, 0);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
static bool re_get_first_char_set(const uint8_t *bc_buf, size_t bc_buf_len,
|
|
469
|
+
int re_flags, uint8_t *bitmap, int *phas_wide);
|
|
470
|
+
|
|
471
|
+
/* Derive the set of characters that a match must begin with, when the pattern
|
|
472
|
+
opens with a single mandatory character or character class. Fills a 256-bit
|
|
473
|
+
bitmap for code points 0..255 and sets *phas_wide if the first character may
|
|
474
|
+
be > 0xff. Returns false (no filter) for anything not provably a mandatory
|
|
475
|
+
leading char/class, which is always sound: falling back to a full scan can
|
|
476
|
+
never produce a wrong match. */
|
|
477
|
+
#define RE_FIRST_SET_MAX_DEPTH 24
|
|
478
|
+
|
|
479
|
+
/* Recursively OR the set of possible first characters reachable from 'pos'
|
|
480
|
+
into 'bitmap', following alternation splits and gotos and skipping
|
|
481
|
+
zero-width capture bookkeeping. This lets alternation-prefixed patterns
|
|
482
|
+
(e.g. /foo|bar|baz/) benefit from the leading-scan prefilter, not just
|
|
483
|
+
single-char/class prefixes. Returns false (sound: caller falls back to a
|
|
484
|
+
full scan, never a wrong match) for any op it can't statically resolve or
|
|
485
|
+
if the structure is too deep. *phas_wide is OR-accumulated. */
|
|
486
|
+
static bool re_first_set_scan(const uint8_t *code, size_t bc_buf_len,
|
|
487
|
+
size_t pos, uint8_t *bitmap, int *phas_wide,
|
|
488
|
+
int *phas_fold, int depth)
|
|
489
|
+
{
|
|
490
|
+
uint32_t low, high, c;
|
|
491
|
+
int i, n;
|
|
492
|
+
|
|
493
|
+
if (depth > RE_FIRST_SET_MAX_DEPTH)
|
|
494
|
+
return false;
|
|
495
|
+
/* Skip zero-width bookkeeping to reach the first consuming op. REOP_set_i32
|
|
496
|
+
/ REOP_set_char_pos as a *leading* op is the counter setup of a counted
|
|
497
|
+
quantifier with quant_min >= 1 (e.g. \d{3}, [ab]{2,5}): the atom that
|
|
498
|
+
follows is executed unconditionally at least once, so its first-char set
|
|
499
|
+
is the mandatory first set of the whole term. (quant_min == 0 quantifiers
|
|
500
|
+
lead with REOP_split_goto_first, handled by the split case below, which
|
|
501
|
+
correctly unions the optional atom with what follows.) This lets counted-
|
|
502
|
+
quantifier-prefixed patterns get the leading scan instead of a full
|
|
503
|
+
position-by-position VM walk. */
|
|
504
|
+
for (;;) {
|
|
505
|
+
if (pos >= bc_buf_len)
|
|
506
|
+
return false;
|
|
507
|
+
if (code[pos] == REOP_save_start || code[pos] == REOP_save_end) {
|
|
508
|
+
pos += 2;
|
|
509
|
+
} else if (code[pos] == REOP_save_reset) {
|
|
510
|
+
pos += 3;
|
|
511
|
+
} else if (code[pos] == REOP_set_i32) {
|
|
512
|
+
pos += 6;
|
|
513
|
+
} else if (code[pos] == REOP_set_char_pos) {
|
|
514
|
+
pos += 2;
|
|
515
|
+
} else {
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
switch (code[pos]) {
|
|
520
|
+
case REOP_split_goto_first:
|
|
521
|
+
case REOP_split_next_first:
|
|
522
|
+
if (pos + 5 > bc_buf_len)
|
|
523
|
+
return false;
|
|
524
|
+
{
|
|
525
|
+
int32_t off = (int32_t)get_u32(code + pos + 1);
|
|
526
|
+
size_t target = pos + 5 + (size_t)off;
|
|
527
|
+
/* both the fall-through and the goto target can start a match */
|
|
528
|
+
if (!re_first_set_scan(code, bc_buf_len, pos + 5, bitmap,
|
|
529
|
+
phas_wide, phas_fold, depth + 1))
|
|
530
|
+
return false;
|
|
531
|
+
if (target > bc_buf_len)
|
|
532
|
+
return false;
|
|
533
|
+
return re_first_set_scan(code, bc_buf_len, target, bitmap,
|
|
534
|
+
phas_wide, phas_fold, depth + 1);
|
|
535
|
+
}
|
|
536
|
+
case REOP_goto:
|
|
537
|
+
if (pos + 5 > bc_buf_len)
|
|
538
|
+
return false;
|
|
539
|
+
{
|
|
540
|
+
int32_t off = (int32_t)get_u32(code + pos + 1);
|
|
541
|
+
size_t target = pos + 5 + (size_t)off;
|
|
542
|
+
if (target > bc_buf_len)
|
|
543
|
+
return false;
|
|
544
|
+
return re_first_set_scan(code, bc_buf_len, target, bitmap,
|
|
545
|
+
phas_wide, phas_fold, depth + 1);
|
|
546
|
+
}
|
|
547
|
+
case REOP_char_i:
|
|
548
|
+
*phas_fold = 1;
|
|
549
|
+
/* fallthrough */
|
|
550
|
+
case REOP_char:
|
|
551
|
+
if (pos + 3 > bc_buf_len)
|
|
552
|
+
return false;
|
|
553
|
+
c = get_u16(code + pos + 1);
|
|
554
|
+
if (c <= 0xff)
|
|
555
|
+
bitmap[c >> 3] |= 1 << (c & 7);
|
|
556
|
+
else
|
|
557
|
+
*phas_wide = 1;
|
|
558
|
+
return true;
|
|
559
|
+
case REOP_char32_i:
|
|
560
|
+
*phas_fold = 1;
|
|
561
|
+
/* fallthrough */
|
|
562
|
+
case REOP_char32:
|
|
563
|
+
if (pos + 5 > bc_buf_len)
|
|
564
|
+
return false;
|
|
565
|
+
c = get_u32(code + pos + 1);
|
|
566
|
+
if (c <= 0xff)
|
|
567
|
+
bitmap[c >> 3] |= 1 << (c & 7);
|
|
568
|
+
else
|
|
569
|
+
*phas_wide = 1;
|
|
570
|
+
return true;
|
|
571
|
+
#if JS_RE_PREFILTER
|
|
572
|
+
case REOP_space:
|
|
573
|
+
/* W2: \s has its own opcode, so it fell through to `default: return
|
|
574
|
+
false` and every \s-led pattern got NO prefilter at all. The executor tests lre_is_space(), which
|
|
575
|
+
for c < 256 is exactly lre_is_space_byte(); the non-ASCII members
|
|
576
|
+
(U+1680, U+2000..U+200A, U+2028/9, U+202F, U+205F, U+3000, U+FEFF)
|
|
577
|
+
are covered by has_wide. */
|
|
578
|
+
{
|
|
579
|
+
int b;
|
|
580
|
+
for (b = 0; b < 256; b++)
|
|
581
|
+
if (lre_is_space_byte((uint8_t)b))
|
|
582
|
+
bitmap[b >> 3] |= 1 << (b & 7);
|
|
583
|
+
}
|
|
584
|
+
*phas_wide = 1;
|
|
585
|
+
return true;
|
|
586
|
+
#endif /* JS_RE_PREFILTER -- REOP_space first set */
|
|
587
|
+
case REOP_range_i:
|
|
588
|
+
*phas_fold = 1;
|
|
589
|
+
/* fallthrough */
|
|
590
|
+
case REOP_range:
|
|
591
|
+
if (pos + 3 > bc_buf_len)
|
|
592
|
+
return false;
|
|
593
|
+
n = get_u16(code + pos + 1);
|
|
594
|
+
if (n == 0 || (size_t)n > (bc_buf_len - pos - 3) / 4)
|
|
595
|
+
return false;
|
|
596
|
+
for (i = 0; i < n; i++) {
|
|
597
|
+
low = get_u16(code + pos + 3 + i * 4);
|
|
598
|
+
high = get_u16(code + pos + 5 + i * 4);
|
|
599
|
+
if (high > 0xff)
|
|
600
|
+
*phas_wide = 1;
|
|
601
|
+
if (low > 0xff)
|
|
602
|
+
continue;
|
|
603
|
+
if (high > 0xff)
|
|
604
|
+
high = 0xff;
|
|
605
|
+
for (c = low; c <= high; c++)
|
|
606
|
+
bitmap[c >> 3] |= 1 << (c & 7);
|
|
607
|
+
}
|
|
608
|
+
return true;
|
|
609
|
+
case REOP_range32_i:
|
|
610
|
+
*phas_fold = 1;
|
|
611
|
+
/* fallthrough */
|
|
612
|
+
case REOP_range32:
|
|
613
|
+
if (pos + 3 > bc_buf_len)
|
|
614
|
+
return false;
|
|
615
|
+
n = get_u16(code + pos + 1);
|
|
616
|
+
if (n == 0 || (size_t)n > (bc_buf_len - pos - 3) / 8)
|
|
617
|
+
return false;
|
|
618
|
+
for (i = 0; i < n; i++) {
|
|
619
|
+
low = get_u32(code + pos + 3 + i * 8);
|
|
620
|
+
high = get_u32(code + pos + 7 + i * 8);
|
|
621
|
+
if (high > 0xff)
|
|
622
|
+
*phas_wide = 1;
|
|
623
|
+
if (low > 0xff)
|
|
624
|
+
continue;
|
|
625
|
+
if (high > 0xff)
|
|
626
|
+
high = 0xff;
|
|
627
|
+
for (c = low; c <= high; c++)
|
|
628
|
+
bitmap[c >> 3] |= 1 << (c & 7);
|
|
629
|
+
}
|
|
630
|
+
return true;
|
|
631
|
+
default:
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
static bool re_get_first_char_set(const uint8_t *bc_buf, size_t bc_buf_len,
|
|
637
|
+
int re_flags, uint8_t *bitmap, int *phas_wide)
|
|
638
|
+
{
|
|
639
|
+
const uint8_t *code;
|
|
640
|
+
size_t entry_pos;
|
|
641
|
+
int has_fold;
|
|
642
|
+
|
|
643
|
+
/* Case-insensitive first sets use the canonicalized character closure.
|
|
644
|
+
Sticky and Unicode-surrogate cases remain on the generic path. */
|
|
645
|
+
if ((re_flags & (LRE_FLAG_STICKY |
|
|
646
|
+
LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) ||
|
|
647
|
+
bc_buf_len < RE_HEADER_LEN + 14 ||
|
|
648
|
+
!re_get_scan_entry(bc_buf, bc_buf_len, &entry_pos)) {
|
|
649
|
+
return false;
|
|
650
|
+
}
|
|
651
|
+
code = bc_buf + RE_HEADER_LEN;
|
|
652
|
+
bc_buf_len -= RE_HEADER_LEN;
|
|
653
|
+
|
|
654
|
+
memset(bitmap, 0, LRE_FIRST_SET_BITMAP_LEN);
|
|
655
|
+
*phas_wide = 0;
|
|
656
|
+
has_fold = 0;
|
|
657
|
+
/* Scan from pos 13 (past the ".*?" scan prologue + its save_start 0),
|
|
658
|
+
following alternation splits/gotos to union every branch's first char.
|
|
659
|
+
Case-folding (_i) leading ops store canonical values and set has_fold. */
|
|
660
|
+
if (!re_first_set_scan(code, bc_buf_len, 13, bitmap, phas_wide, &has_fold, 0))
|
|
661
|
+
return false;
|
|
662
|
+
|
|
663
|
+
if (has_fold) {
|
|
664
|
+
/* Add every input byte that canonicalizes into the scanned set (e.g.
|
|
665
|
+
'H' -> {'h','H'}), so the NEON scan can locate /i candidates that
|
|
666
|
+
lre_exec_at then verifies. UNION with — never replace — the scanned
|
|
667
|
+
bits: a case-sensitive REOP_char (from (?-i:...)) may store a value
|
|
668
|
+
that is not a fixed-point of canonicalization, so replacing would
|
|
669
|
+
drop it and miss real matches. Over-inclusion is always sound; a wide
|
|
670
|
+
char may also fold into the set, so mark has_wide (the wide path
|
|
671
|
+
rechecks every position). Non-unicode canonicalization only. */
|
|
672
|
+
uint8_t closure[LRE_FIRST_SET_BITMAP_LEN];
|
|
673
|
+
int b;
|
|
674
|
+
uint32_t cb;
|
|
675
|
+
memset(closure, 0, sizeof(closure));
|
|
676
|
+
for (b = 0; b < 256; b++) {
|
|
677
|
+
cb = lre_canonicalize(b, false);
|
|
678
|
+
if (cb <= 0xff && ((bitmap[cb >> 3] >> (cb & 7)) & 1))
|
|
679
|
+
closure[b >> 3] |= 1 << (b & 7);
|
|
680
|
+
}
|
|
681
|
+
for (b = 0; b < LRE_FIRST_SET_BITMAP_LEN; b++)
|
|
682
|
+
bitmap[b] |= closure[b];
|
|
683
|
+
*phas_wide = 1;
|
|
684
|
+
}
|
|
685
|
+
return true;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
static int re_append_first_set_metadata(REParseState *s, int re_flags)
|
|
689
|
+
{
|
|
690
|
+
uint8_t header[LRE_META_HEADER_LEN];
|
|
691
|
+
uint8_t bitmap[LRE_FIRST_SET_BITMAP_LEN];
|
|
692
|
+
size_t code_len;
|
|
693
|
+
int has_wide;
|
|
694
|
+
|
|
695
|
+
code_len = get_u32(s->byte_code.buf + RE_HEADER_BYTECODE_LEN);
|
|
696
|
+
if (!re_get_first_char_set(s->byte_code.buf, RE_HEADER_LEN + code_len,
|
|
697
|
+
re_flags, bitmap, &has_wide)) {
|
|
698
|
+
return 0;
|
|
699
|
+
}
|
|
700
|
+
memset(header, 0, sizeof(header));
|
|
701
|
+
header[LRE_META_VERSION_OFFSET] = LRE_META_VERSION;
|
|
702
|
+
header[LRE_META_KIND_OFFSET] = LRE_META_FIRST_SET;
|
|
703
|
+
put_u32(header + LRE_META_PAYLOAD_SIZE_OFFSET, LRE_FIRST_SET_PAYLOAD_LEN);
|
|
704
|
+
put_u32(header + LRE_META_LENGTH_OFFSET, 0);
|
|
705
|
+
put_u32(header + LRE_META_ENTRY_OFFSET, 11);
|
|
706
|
+
dbuf_put(&s->byte_code, header, sizeof(header));
|
|
707
|
+
dbuf_putc(&s->byte_code, has_wide);
|
|
708
|
+
dbuf_put(&s->byte_code, bitmap, sizeof(bitmap));
|
|
709
|
+
put_u16(s->byte_code.buf + RE_HEADER_FLAGS,
|
|
710
|
+
lre_get_flags(s->byte_code.buf) | LRE_FLAG_HAS_META);
|
|
711
|
+
return dbuf_error(&s->byte_code) ? -1 : 1;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/* Return the complete length of one serialized instruction, or false when
|
|
715
|
+
the instruction is truncated or its opcode is not in the table. */
|
|
716
|
+
static bool re_checked_op_len(const uint8_t *code, size_t remaining,
|
|
717
|
+
size_t *plen)
|
|
718
|
+
{
|
|
719
|
+
uint8_t opcode;
|
|
720
|
+
size_t len;
|
|
721
|
+
uint32_t count;
|
|
722
|
+
|
|
723
|
+
if (remaining == 0)
|
|
724
|
+
return false;
|
|
725
|
+
opcode = code[0];
|
|
726
|
+
if (opcode >= REOP_COUNT || opcode == REOP_invalid)
|
|
727
|
+
return false;
|
|
728
|
+
len = reopcode_info[opcode].size;
|
|
729
|
+
if (len == 0 || len > remaining)
|
|
730
|
+
return false;
|
|
731
|
+
switch (opcode) {
|
|
732
|
+
case REOP_back_reference:
|
|
733
|
+
case REOP_back_reference_i:
|
|
734
|
+
case REOP_backward_back_reference:
|
|
735
|
+
case REOP_backward_back_reference_i:
|
|
736
|
+
if (remaining < 2 || code[1] > remaining - 2)
|
|
737
|
+
return false;
|
|
738
|
+
len = 2 + code[1];
|
|
739
|
+
break;
|
|
740
|
+
case REOP_range:
|
|
741
|
+
case REOP_range_i:
|
|
742
|
+
if (remaining < 3)
|
|
743
|
+
return false;
|
|
744
|
+
count = get_u16(code + 1);
|
|
745
|
+
if (count == 0 || count > (remaining - 3) / 4)
|
|
746
|
+
return false;
|
|
747
|
+
len = 3 + (size_t)count * 4;
|
|
748
|
+
break;
|
|
749
|
+
case REOP_range32:
|
|
750
|
+
case REOP_range32_i:
|
|
751
|
+
if (remaining < 3)
|
|
752
|
+
return false;
|
|
753
|
+
count = get_u16(code + 1);
|
|
754
|
+
if (count == 0 || count > (remaining - 3) / 8)
|
|
755
|
+
return false;
|
|
756
|
+
len = 3 + (size_t)count * 8;
|
|
757
|
+
break;
|
|
758
|
+
default:
|
|
759
|
+
break;
|
|
760
|
+
}
|
|
761
|
+
if (len > remaining)
|
|
762
|
+
return false;
|
|
763
|
+
*plen = len;
|
|
764
|
+
return true;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
static bool re_boundary_get(const uint8_t *boundary_bits, size_t pos)
|
|
768
|
+
{
|
|
769
|
+
return (boundary_bits[pos >> 3] >> (pos & 7)) & 1;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
static void re_boundary_set(uint8_t *boundary_bits, size_t pos)
|
|
773
|
+
{
|
|
774
|
+
boundary_bits[pos >> 3] |= (uint8_t)1 << (pos & 7);
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
static bool re_validate_target(const uint8_t *boundary_bits, size_t code_len,
|
|
778
|
+
size_t base, uint32_t raw_offset);
|
|
779
|
+
|
|
780
|
+
static bool re_validate_code(const uint8_t *code, size_t code_len,
|
|
781
|
+
uint8_t capture_count, uint8_t register_count,
|
|
782
|
+
void *opaque)
|
|
783
|
+
{
|
|
784
|
+
uint8_t *boundary_bits;
|
|
785
|
+
size_t boundary_size;
|
|
786
|
+
size_t pos = 0, len;
|
|
787
|
+
uint8_t last_opcode = REOP_invalid;
|
|
788
|
+
bool valid = false;
|
|
789
|
+
|
|
790
|
+
if (code_len == 0 || code_len > (SIZE_MAX - 7) / 8)
|
|
791
|
+
return false;
|
|
792
|
+
boundary_size = (code_len + 7) / 8;
|
|
793
|
+
/* Keep the map compact; the caller supplies the real allocator context. */
|
|
794
|
+
boundary_bits = lre_realloc(opaque, NULL, boundary_size);
|
|
795
|
+
if (!boundary_bits)
|
|
796
|
+
return false;
|
|
797
|
+
memset(boundary_bits, 0, boundary_size);
|
|
798
|
+
re_boundary_set(boundary_bits, 0);
|
|
799
|
+
pos = 0;
|
|
800
|
+
while (pos < code_len) {
|
|
801
|
+
if (!re_checked_op_len(code + pos, code_len - pos, &len))
|
|
802
|
+
goto done;
|
|
803
|
+
last_opcode = code[pos];
|
|
804
|
+
pos += len;
|
|
805
|
+
if (pos < code_len)
|
|
806
|
+
re_boundary_set(boundary_bits, pos);
|
|
807
|
+
}
|
|
808
|
+
if (pos != code_len ||
|
|
809
|
+
code[0] == REOP_lookahead_match ||
|
|
810
|
+
code[0] == REOP_negative_lookahead_match)
|
|
811
|
+
goto done;
|
|
812
|
+
/* Every executable path must have a terminating matcher instruction.
|
|
813
|
+
Matcher-stack state is still part of the trusted bytecode contract. */
|
|
814
|
+
if (last_opcode != REOP_match)
|
|
815
|
+
goto done;
|
|
816
|
+
pos = 0;
|
|
817
|
+
while (pos < code_len) {
|
|
818
|
+
uint8_t opcode = code[pos];
|
|
819
|
+
uint32_t val, val2;
|
|
820
|
+
|
|
821
|
+
if (!re_checked_op_len(code + pos, code_len - pos, &len))
|
|
822
|
+
goto done;
|
|
823
|
+
switch (opcode) {
|
|
824
|
+
case REOP_save_start:
|
|
825
|
+
case REOP_save_end:
|
|
826
|
+
if (code[pos + 1] >= capture_count)
|
|
827
|
+
goto done;
|
|
828
|
+
break;
|
|
829
|
+
case REOP_save_reset:
|
|
830
|
+
val = code[pos + 1];
|
|
831
|
+
val2 = code[pos + 2];
|
|
832
|
+
if (val > val2 || val2 >= capture_count)
|
|
833
|
+
goto done;
|
|
834
|
+
break;
|
|
835
|
+
case REOP_set_i32:
|
|
836
|
+
case REOP_set_char_pos:
|
|
837
|
+
case REOP_check_advance:
|
|
838
|
+
if (code[pos + 1] >= register_count)
|
|
839
|
+
goto done;
|
|
840
|
+
break;
|
|
841
|
+
case REOP_back_reference:
|
|
842
|
+
case REOP_back_reference_i:
|
|
843
|
+
case REOP_backward_back_reference:
|
|
844
|
+
case REOP_backward_back_reference_i:
|
|
845
|
+
for (val = 0; val < code[pos + 1]; val++)
|
|
846
|
+
if (code[pos + 2 + val] >= capture_count)
|
|
847
|
+
goto done;
|
|
848
|
+
break;
|
|
849
|
+
case REOP_goto:
|
|
850
|
+
case REOP_split_goto_first:
|
|
851
|
+
case REOP_split_next_first:
|
|
852
|
+
case REOP_lookahead:
|
|
853
|
+
case REOP_negative_lookahead:
|
|
854
|
+
val = get_u32(code + pos + 1);
|
|
855
|
+
if (!re_validate_target(boundary_bits, code_len, pos + 5, val))
|
|
856
|
+
goto done;
|
|
857
|
+
break;
|
|
858
|
+
case REOP_loop:
|
|
859
|
+
if (code[pos + 1] >= register_count)
|
|
860
|
+
goto done;
|
|
861
|
+
val = get_u32(code + pos + 2);
|
|
862
|
+
if (!re_validate_target(boundary_bits, code_len, pos + 6, val))
|
|
863
|
+
goto done;
|
|
864
|
+
break;
|
|
865
|
+
case REOP_loop_split_goto_first:
|
|
866
|
+
case REOP_loop_split_next_first:
|
|
867
|
+
if (code[pos + 1] >= register_count)
|
|
868
|
+
goto done;
|
|
869
|
+
val = get_u32(code + pos + 6);
|
|
870
|
+
if (!re_validate_target(boundary_bits, code_len, pos + 10, val))
|
|
871
|
+
goto done;
|
|
872
|
+
break;
|
|
873
|
+
case REOP_loop_check_adv_split_goto_first:
|
|
874
|
+
case REOP_loop_check_adv_split_next_first:
|
|
875
|
+
if (register_count < 2 || code[pos + 1] >= register_count - 1)
|
|
876
|
+
goto done;
|
|
877
|
+
val = get_u32(code + pos + 6);
|
|
878
|
+
if (!re_validate_target(boundary_bits, code_len, pos + 10, val))
|
|
879
|
+
goto done;
|
|
880
|
+
break;
|
|
881
|
+
default:
|
|
882
|
+
break;
|
|
883
|
+
}
|
|
884
|
+
pos += len;
|
|
885
|
+
}
|
|
886
|
+
valid = true;
|
|
887
|
+
done:
|
|
888
|
+
lre_realloc(opaque, boundary_bits, 0);
|
|
889
|
+
return valid;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
/* Metadata entry offsets must land on an instruction boundary and identify
|
|
893
|
+
the synthetic save_start 0 used by lre_exec_at(). */
|
|
894
|
+
static bool re_validate_entry(const uint8_t *code, size_t code_len,
|
|
895
|
+
uint32_t entry_offset)
|
|
896
|
+
{
|
|
897
|
+
size_t pos = 0, len;
|
|
898
|
+
|
|
899
|
+
if (entry_offset > code_len || code_len - entry_offset < 2)
|
|
900
|
+
return false;
|
|
901
|
+
while (pos < entry_offset) {
|
|
902
|
+
if (!re_checked_op_len(code + pos, entry_offset - pos, &len))
|
|
903
|
+
return false;
|
|
904
|
+
pos += len;
|
|
905
|
+
}
|
|
906
|
+
return pos == entry_offset && code[pos] == REOP_save_start &&
|
|
907
|
+
code[pos + 1] == 0;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
static bool re_validate_target(const uint8_t *boundary_bits, size_t code_len,
|
|
911
|
+
size_t base, uint32_t raw_offset)
|
|
912
|
+
{
|
|
913
|
+
int32_t offset = (int32_t)raw_offset;
|
|
914
|
+
size_t target;
|
|
915
|
+
|
|
916
|
+
if (offset < 0) {
|
|
917
|
+
size_t distance = (size_t)(-(int64_t)offset);
|
|
918
|
+
if (distance > base)
|
|
919
|
+
return false;
|
|
920
|
+
target = base - distance;
|
|
921
|
+
} else {
|
|
922
|
+
size_t distance = (size_t)offset;
|
|
923
|
+
if (distance > SIZE_MAX - base)
|
|
924
|
+
return false;
|
|
925
|
+
target = base + distance;
|
|
926
|
+
}
|
|
927
|
+
return target < code_len && re_boundary_get(boundary_bits, target);
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/* Parse the metadata trailer. Returns 1 if present and well-formed, 0 if
|
|
931
|
+
absent, -1 if malformed. *ptrailer (if given) receives the byte following
|
|
932
|
+
the metadata (where group names begin). */
|
|
933
|
+
static int lre_parse_metadata(const uint8_t *bc_buf, size_t bc_buf_len,
|
|
934
|
+
LREMetadata *meta, const uint8_t **ptrailer)
|
|
935
|
+
{
|
|
936
|
+
const uint8_t *p, *end;
|
|
937
|
+
size_t code_len;
|
|
938
|
+
uint32_t payload_size;
|
|
939
|
+
int flags;
|
|
940
|
+
|
|
941
|
+
if (meta)
|
|
942
|
+
memset(meta, 0, sizeof(*meta));
|
|
943
|
+
if (!bc_buf || bc_buf_len < RE_HEADER_LEN)
|
|
944
|
+
return -1;
|
|
945
|
+
code_len = get_u32(bc_buf + RE_HEADER_BYTECODE_LEN);
|
|
946
|
+
if (code_len > bc_buf_len - RE_HEADER_LEN)
|
|
947
|
+
return -1;
|
|
948
|
+
p = bc_buf + RE_HEADER_LEN + code_len;
|
|
949
|
+
end = bc_buf + bc_buf_len;
|
|
950
|
+
flags = get_u16(bc_buf + RE_HEADER_FLAGS);
|
|
951
|
+
if (!(flags & LRE_FLAG_HAS_META)) {
|
|
952
|
+
if (ptrailer)
|
|
953
|
+
*ptrailer = p;
|
|
954
|
+
return 0;
|
|
955
|
+
}
|
|
956
|
+
if ((size_t)(end - p) < LRE_META_HEADER_LEN ||
|
|
957
|
+
p[LRE_META_VERSION_OFFSET] != LRE_META_VERSION ||
|
|
958
|
+
p[LRE_META_KIND_OFFSET] < LRE_META_LITERAL ||
|
|
959
|
+
p[LRE_META_KIND_OFFSET] > LRE_META_FIRST_SET ||
|
|
960
|
+
p[LRE_META_ENCODING_OFFSET] > 1 ||
|
|
961
|
+
(p[LRE_META_FLAGS_OFFSET] & ~LRE_META_FLAG_SOURCE)) {
|
|
962
|
+
return -1;
|
|
963
|
+
}
|
|
964
|
+
payload_size = get_u32(p + LRE_META_PAYLOAD_SIZE_OFFSET);
|
|
965
|
+
if (payload_size > (size_t)(end - p - LRE_META_HEADER_LEN))
|
|
966
|
+
return -1;
|
|
967
|
+
switch (p[LRE_META_KIND_OFFSET]) {
|
|
968
|
+
case LRE_META_LITERAL:
|
|
969
|
+
if (p[LRE_META_FLAGS_OFFSET] & ~LRE_META_FLAG_SOURCE)
|
|
970
|
+
return -1;
|
|
971
|
+
if (p[LRE_META_FLAGS_OFFSET] & LRE_META_FLAG_SOURCE) {
|
|
972
|
+
if (payload_size != 0)
|
|
973
|
+
return -1;
|
|
974
|
+
} else if (get_u32(p + LRE_META_LENGTH_OFFSET) > LRE_LITERAL_MAX_LENGTH ||
|
|
975
|
+
((uint64_t)get_u32(p + LRE_META_LENGTH_OFFSET) <<
|
|
976
|
+
p[LRE_META_ENCODING_OFFSET]) != payload_size) {
|
|
977
|
+
return -1;
|
|
978
|
+
}
|
|
979
|
+
break;
|
|
980
|
+
case LRE_META_PREFIX:
|
|
981
|
+
if (p[LRE_META_FLAGS_OFFSET] != 0 ||
|
|
982
|
+
get_u32(p + LRE_META_LENGTH_OFFSET) < LRE_PREFIX_MIN_LENGTH ||
|
|
983
|
+
get_u32(p + LRE_META_LENGTH_OFFSET) > LRE_PREFIX_MAX_LENGTH ||
|
|
984
|
+
((uint64_t)get_u32(p + LRE_META_LENGTH_OFFSET) <<
|
|
985
|
+
p[LRE_META_ENCODING_OFFSET]) != payload_size)
|
|
986
|
+
return -1;
|
|
987
|
+
break;
|
|
988
|
+
case LRE_META_FIRST_SET:
|
|
989
|
+
if (p[LRE_META_ENCODING_OFFSET] != 0 ||
|
|
990
|
+
p[LRE_META_FLAGS_OFFSET] != 0 ||
|
|
991
|
+
get_u32(p + LRE_META_LENGTH_OFFSET) != 0 ||
|
|
992
|
+
payload_size != LRE_FIRST_SET_PAYLOAD_LEN)
|
|
993
|
+
return -1;
|
|
994
|
+
break;
|
|
995
|
+
default:
|
|
996
|
+
return -1;
|
|
997
|
+
}
|
|
998
|
+
if (meta) {
|
|
999
|
+
meta->kind = p[LRE_META_KIND_OFFSET];
|
|
1000
|
+
meta->encoding = p[LRE_META_ENCODING_OFFSET];
|
|
1001
|
+
meta->flags = p[LRE_META_FLAGS_OFFSET];
|
|
1002
|
+
meta->payload_size = payload_size;
|
|
1003
|
+
meta->primary_payload_size = payload_size;
|
|
1004
|
+
meta->length = get_u32(p + LRE_META_LENGTH_OFFSET);
|
|
1005
|
+
meta->entry_offset = get_u32(p + LRE_META_ENTRY_OFFSET);
|
|
1006
|
+
meta->payload = p + LRE_META_HEADER_LEN;
|
|
1007
|
+
meta->leading_chars = NULL;
|
|
1008
|
+
}
|
|
1009
|
+
if (ptrailer)
|
|
1010
|
+
*ptrailer = p + LRE_META_HEADER_LEN + payload_size;
|
|
1011
|
+
return 1;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
int lre_get_metadata(const uint8_t *bc_buf, size_t bc_buf_len,
|
|
1015
|
+
LREMetadata *meta)
|
|
1016
|
+
{
|
|
1017
|
+
if (!meta)
|
|
1018
|
+
return -1;
|
|
1019
|
+
return lre_parse_metadata(bc_buf, bc_buf_len, meta, NULL);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
135
1022
|
/* insert 'len' bytes at position 'pos'. Return < 0 if error. */
|
|
136
1023
|
static int dbuf_insert(DynBuf *s, int pos, int len)
|
|
137
1024
|
{
|
|
@@ -239,6 +1126,8 @@ static __maybe_unused void re_string_list_dump(const char *str, const REStringLi
|
|
|
239
1126
|
}
|
|
240
1127
|
#endif /* DUMP_REOP */
|
|
241
1128
|
|
|
1129
|
+
/* 'buf' is NULL if 'len' is zero: the empty string is a valid member of a
|
|
1130
|
+
string set, e.g. /[\q{}]/v */
|
|
242
1131
|
static int re_string_find2(REStringList *s, int len, const uint32_t *buf,
|
|
243
1132
|
uint32_t h0, bool add_flag)
|
|
244
1133
|
{
|
|
@@ -248,7 +1137,8 @@ static int re_string_find2(REStringList *s, int len, const uint32_t *buf,
|
|
|
248
1137
|
h = h0 >> (32 - s->hash_bits);
|
|
249
1138
|
for(p = s->hash_table[h]; p != NULL; p = p->next) {
|
|
250
1139
|
if (p->hash == h0 && p->len == len &&
|
|
251
|
-
|
|
1140
|
+
(len == 0 ||
|
|
1141
|
+
!memcmp(p->buf, buf, len * sizeof(buf[0])))) {
|
|
252
1142
|
return 1;
|
|
253
1143
|
}
|
|
254
1144
|
}
|
|
@@ -291,7 +1181,8 @@ static int re_string_find2(REStringList *s, int len, const uint32_t *buf,
|
|
|
291
1181
|
s->n_strings++;
|
|
292
1182
|
p->hash = h0;
|
|
293
1183
|
p->len = len;
|
|
294
|
-
|
|
1184
|
+
if (len != 0)
|
|
1185
|
+
memcpy(p->buf, buf, sizeof(buf[0]) * len);
|
|
295
1186
|
return 1;
|
|
296
1187
|
}
|
|
297
1188
|
|
|
@@ -1021,7 +1912,7 @@ static int parse_class_string_disjunction(REParseState *s, REStringList *cr,
|
|
|
1021
1912
|
for(;;) {
|
|
1022
1913
|
str.size = 0;
|
|
1023
1914
|
while (*p != '}' && *p != '|') {
|
|
1024
|
-
c = get_class_atom(s, NULL, &p,
|
|
1915
|
+
c = get_class_atom(s, NULL, &p, true);
|
|
1025
1916
|
if (c < 0)
|
|
1026
1917
|
goto fail;
|
|
1027
1918
|
if (dbuf_put_u32(&str, c)) {
|
|
@@ -1115,6 +2006,23 @@ static int get_class_atom(REParseState *s, REStringList *cr,
|
|
|
1115
2006
|
if (!inclass && s->is_unicode)
|
|
1116
2007
|
goto invalid_escape;
|
|
1117
2008
|
break;
|
|
2009
|
+
case '&':
|
|
2010
|
+
case '!':
|
|
2011
|
+
case '#':
|
|
2012
|
+
case '%':
|
|
2013
|
+
case ',':
|
|
2014
|
+
case ':':
|
|
2015
|
+
case ';':
|
|
2016
|
+
case '<':
|
|
2017
|
+
case '=':
|
|
2018
|
+
case '>':
|
|
2019
|
+
case '@':
|
|
2020
|
+
case '`':
|
|
2021
|
+
case '~':
|
|
2022
|
+
if (s->is_unicode && (!inclass || !s->unicode_sets))
|
|
2023
|
+
/* Only illegal if in unicode mode and not in a class */
|
|
2024
|
+
goto invalid_escape;
|
|
2025
|
+
break;
|
|
1118
2026
|
case '^':
|
|
1119
2027
|
case '$':
|
|
1120
2028
|
case '\\':
|
|
@@ -1331,6 +2239,10 @@ static int re_emit_string_list(REParseState *s, const REStringList *sl)
|
|
|
1331
2239
|
}
|
|
1332
2240
|
if (!is_last) {
|
|
1333
2241
|
last_match_pos = re_emit_op_u32(s, REOP_goto, last_match_pos);
|
|
2242
|
+
/* the positions to patch are only valid if all the byte code
|
|
2243
|
+
could be emitted */
|
|
2244
|
+
if (dbuf_error(&s->byte_code))
|
|
2245
|
+
goto out_of_memory;
|
|
1334
2246
|
put_u32(s->byte_code.buf + split_pos, s->byte_code.size - (split_pos + 4));
|
|
1335
2247
|
}
|
|
1336
2248
|
}
|
|
@@ -1342,15 +2254,18 @@ static int re_emit_string_list(REParseState *s, const REStringList *sl)
|
|
|
1342
2254
|
split_pos = re_emit_op_u32(s, REOP_split_next_first, 0);
|
|
1343
2255
|
else
|
|
1344
2256
|
split_pos = 0; /* not used */
|
|
1345
|
-
if (re_emit_range(s, &sl->cr))
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
2257
|
+
if (re_emit_range(s, &sl->cr))
|
|
2258
|
+
goto fail;
|
|
2259
|
+
if (!is_last) {
|
|
2260
|
+
if (dbuf_error(&s->byte_code))
|
|
2261
|
+
goto out_of_memory;
|
|
1350
2262
|
put_u32(s->byte_code.buf + split_pos, s->byte_code.size - (split_pos + 4));
|
|
2263
|
+
}
|
|
1351
2264
|
}
|
|
1352
2265
|
|
|
1353
2266
|
/* patch the 'goto match' */
|
|
2267
|
+
if (dbuf_error(&s->byte_code))
|
|
2268
|
+
goto out_of_memory;
|
|
1354
2269
|
while (last_match_pos != -1) {
|
|
1355
2270
|
int next_pos = get_u32(s->byte_code.buf + last_match_pos);
|
|
1356
2271
|
put_u32(s->byte_code.buf + last_match_pos, s->byte_code.size - (last_match_pos + 4));
|
|
@@ -1360,6 +2275,11 @@ static int re_emit_string_list(REParseState *s, const REStringList *sl)
|
|
|
1360
2275
|
lre_realloc(s->opaque, tab, 0);
|
|
1361
2276
|
}
|
|
1362
2277
|
return 0;
|
|
2278
|
+
out_of_memory:
|
|
2279
|
+
re_parse_out_of_memory(s);
|
|
2280
|
+
fail:
|
|
2281
|
+
lre_realloc(s->opaque, tab, 0);
|
|
2282
|
+
return -1;
|
|
1363
2283
|
}
|
|
1364
2284
|
|
|
1365
2285
|
static int re_parse_nested_class(REParseState *s, REStringList *cr, const uint8_t **pp);
|
|
@@ -1860,6 +2780,11 @@ static int re_parse_term(REParseState *s, bool is_backward_dir)
|
|
|
1860
2780
|
bool greedy, is_neg, is_backward_lookahead;
|
|
1861
2781
|
REStringList cr_s, *cr = &cr_s;
|
|
1862
2782
|
|
|
2783
|
+
/* after a failed allocation the byte code is incomplete and 'buf' may
|
|
2784
|
+
still be NULL: stop before computing positions inside it */
|
|
2785
|
+
if (dbuf_error(&s->byte_code))
|
|
2786
|
+
return re_parse_out_of_memory(s);
|
|
2787
|
+
|
|
1863
2788
|
last_atom_start = -1;
|
|
1864
2789
|
last_capture_count = 0;
|
|
1865
2790
|
p = s->buf_ptr;
|
|
@@ -1988,7 +2913,7 @@ static int re_parse_term(REParseState *s, bool is_backward_dir)
|
|
|
1988
2913
|
re_emit_op(s, REOP_lookahead_match + is_neg);
|
|
1989
2914
|
/* jump after the 'match' after the lookahead is successful */
|
|
1990
2915
|
if (dbuf_error(&s->byte_code))
|
|
1991
|
-
return
|
|
2916
|
+
return re_parse_out_of_memory(s);
|
|
1992
2917
|
put_u32(s->byte_code.buf + pos, s->byte_code.size - (pos + 4));
|
|
1993
2918
|
} else if (p[2] == '<') {
|
|
1994
2919
|
p += 3;
|
|
@@ -2403,7 +3328,7 @@ static int re_parse_alternative(REParseState *s, bool is_backward_dir)
|
|
|
2403
3328
|
end = s->byte_code.size;
|
|
2404
3329
|
term_size = end - term_start;
|
|
2405
3330
|
if (dbuf_claim(&s->byte_code, term_size))
|
|
2406
|
-
return
|
|
3331
|
+
return re_parse_out_of_memory(s);
|
|
2407
3332
|
memmove(s->byte_code.buf + start + term_size,
|
|
2408
3333
|
s->byte_code.buf + start,
|
|
2409
3334
|
end - start);
|
|
@@ -2446,7 +3371,10 @@ static int re_parse_disjunction(REParseState *s, bool is_backward_dir)
|
|
|
2446
3371
|
if (re_parse_alternative(s, is_backward_dir))
|
|
2447
3372
|
return -1;
|
|
2448
3373
|
|
|
2449
|
-
/* patch the goto
|
|
3374
|
+
/* patch the goto ('pos' is only valid if the placeholder for the
|
|
3375
|
+
offset could be emitted) */
|
|
3376
|
+
if (dbuf_error(&s->byte_code))
|
|
3377
|
+
return re_parse_out_of_memory(s);
|
|
2450
3378
|
len = s->byte_code.size - (pos + 4);
|
|
2451
3379
|
put_u32(s->byte_code.buf + pos, len);
|
|
2452
3380
|
}
|
|
@@ -2521,7 +3449,7 @@ static int compute_register_count(uint8_t *bc_buf, int bc_buf_len)
|
|
|
2521
3449
|
static void *lre_bytecode_realloc(void *opaque, void *ptr, size_t size)
|
|
2522
3450
|
{
|
|
2523
3451
|
if (size > (INT32_MAX / 2)) {
|
|
2524
|
-
/* the bytecode cannot be larger than 2G. Leave some slack to
|
|
3452
|
+
/* the bytecode cannot be larger than 2G. Leave some slack to
|
|
2525
3453
|
avoid some overflows. */
|
|
2526
3454
|
return NULL;
|
|
2527
3455
|
} else {
|
|
@@ -2538,8 +3466,9 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
|
|
|
2538
3466
|
void *opaque)
|
|
2539
3467
|
{
|
|
2540
3468
|
REParseState s_s, *s = &s_s;
|
|
2541
|
-
int register_count;
|
|
3469
|
+
int register_count, metadata_result;
|
|
2542
3470
|
bool is_sticky;
|
|
3471
|
+
bool payload_matches_source;
|
|
2543
3472
|
|
|
2544
3473
|
memset(s, 0, sizeof(*s));
|
|
2545
3474
|
s->opaque = opaque;
|
|
@@ -2556,6 +3485,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
|
|
|
2556
3485
|
s->capture_count = 1;
|
|
2557
3486
|
s->total_capture_count = -1;
|
|
2558
3487
|
s->has_named_captures = -1;
|
|
3488
|
+
payload_matches_source = lre_is_raw_atom(buf, buf_len, re_flags);
|
|
2559
3489
|
|
|
2560
3490
|
dbuf_init2(&s->byte_code, opaque, lre_bytecode_realloc);
|
|
2561
3491
|
dbuf_init2(&s->group_names, opaque, lre_realloc);
|
|
@@ -2610,9 +3540,24 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
|
|
|
2610
3540
|
put_u32(s->byte_code.buf + RE_HEADER_BYTECODE_LEN,
|
|
2611
3541
|
s->byte_code.size - RE_HEADER_LEN);
|
|
2612
3542
|
|
|
3543
|
+
/* Append the optional search metadata before the named-group trailer. */
|
|
3544
|
+
metadata_result = re_append_literal_metadata(s, re_flags,
|
|
3545
|
+
payload_matches_source);
|
|
3546
|
+
if (metadata_result == 0)
|
|
3547
|
+
metadata_result = re_append_prefix_metadata(s, re_flags);
|
|
3548
|
+
if (metadata_result == 0)
|
|
3549
|
+
metadata_result = re_append_first_set_metadata(s, re_flags);
|
|
3550
|
+
if (metadata_result < 0) {
|
|
3551
|
+
re_parse_out_of_memory(s);
|
|
3552
|
+
goto error;
|
|
3553
|
+
}
|
|
3554
|
+
|
|
2613
3555
|
/* add the named groups if needed */
|
|
2614
3556
|
if (s->group_names.size > (s->capture_count - 1) * LRE_GROUP_NAME_TRAILER_LEN) {
|
|
2615
|
-
dbuf_put(&s->byte_code, s->group_names.buf, s->group_names.size)
|
|
3557
|
+
if (dbuf_put(&s->byte_code, s->group_names.buf, s->group_names.size)) {
|
|
3558
|
+
re_parse_out_of_memory(s);
|
|
3559
|
+
goto error;
|
|
3560
|
+
}
|
|
2616
3561
|
put_u16(s->byte_code.buf + RE_HEADER_FLAGS,
|
|
2617
3562
|
lre_get_flags(s->byte_code.buf) | LRE_FLAG_NAMED_GROUPS);
|
|
2618
3563
|
}
|
|
@@ -2785,563 +3730,19 @@ static no_inline int stack_realloc(REExecContext *s, size_t n)
|
|
|
2785
3730
|
}
|
|
2786
3731
|
|
|
2787
3732
|
/* return 1 if match, 0 if not match or < 0 if error. */
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
uint32_t val, c, idx;
|
|
2794
|
-
const uint8_t *cbuf_end;
|
|
2795
|
-
StackElem *sp, *bp, *stack_end;
|
|
2796
|
-
#ifdef DUMP_EXEC
|
|
2797
|
-
const uint8_t *pc_start = pc; /* TEST */
|
|
2798
|
-
#endif
|
|
2799
|
-
cbuf_type = s->cbuf_type;
|
|
2800
|
-
cbuf_end = s->cbuf_end;
|
|
2801
|
-
|
|
2802
|
-
sp = s->stack_buf;
|
|
2803
|
-
bp = s->stack_buf;
|
|
2804
|
-
stack_end = s->stack_buf + s->stack_size;
|
|
2805
|
-
|
|
2806
|
-
#define CHECK_STACK_SPACE(n) \
|
|
2807
|
-
if (unlikely((stack_end - sp) < (n))) { \
|
|
2808
|
-
size_t saved_sp = sp - s->stack_buf; \
|
|
2809
|
-
size_t saved_bp = bp - s->stack_buf; \
|
|
2810
|
-
if (stack_realloc(s, sp - s->stack_buf + (n))) \
|
|
2811
|
-
return LRE_RET_MEMORY_ERROR; \
|
|
2812
|
-
stack_end = s->stack_buf + s->stack_size; \
|
|
2813
|
-
sp = s->stack_buf + saved_sp; \
|
|
2814
|
-
bp = s->stack_buf + saved_bp; \
|
|
2815
|
-
}
|
|
2816
|
-
|
|
2817
|
-
/* XXX: could test if the value was saved to reduce the stack size
|
|
2818
|
-
but slower */
|
|
2819
|
-
#define SAVE_CAPTURE(idx, value) \
|
|
2820
|
-
{ \
|
|
2821
|
-
CHECK_STACK_SPACE(2); \
|
|
2822
|
-
sp[0].val = idx; \
|
|
2823
|
-
sp[1].ptr = capture[idx]; \
|
|
2824
|
-
sp += 2; \
|
|
2825
|
-
capture[idx] = (value); \
|
|
2826
|
-
}
|
|
2827
|
-
|
|
2828
|
-
/* avoid saving the previous value if already saved */
|
|
2829
|
-
#define SAVE_CAPTURE_CHECK(idx, value) \
|
|
2830
|
-
{ \
|
|
2831
|
-
StackElem *sp1; \
|
|
2832
|
-
sp1 = sp; \
|
|
2833
|
-
for(;;) { \
|
|
2834
|
-
if (sp1 > bp) { \
|
|
2835
|
-
if (sp1[-2].val == idx) \
|
|
2836
|
-
break; \
|
|
2837
|
-
sp1 -= 2; \
|
|
2838
|
-
} else { \
|
|
2839
|
-
CHECK_STACK_SPACE(2); \
|
|
2840
|
-
sp[0].val = idx; \
|
|
2841
|
-
sp[1].ptr = capture[idx]; \
|
|
2842
|
-
sp += 2; \
|
|
2843
|
-
break; \
|
|
2844
|
-
} \
|
|
2845
|
-
} \
|
|
2846
|
-
capture[idx] = (value); \
|
|
2847
|
-
}
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
#ifdef DUMP_EXEC
|
|
2851
|
-
printf("%5s %5s %5s %5s %s\n", "PC", "CP", "BP", "SP", "OPCODE");
|
|
2852
|
-
#endif
|
|
2853
|
-
for(;;) {
|
|
2854
|
-
opcode = *pc++;
|
|
2855
|
-
#ifdef DUMP_EXEC
|
|
2856
|
-
printf("%5ld %5ld %5ld %5ld %s\n",
|
|
2857
|
-
pc - 1 - pc_start,
|
|
2858
|
-
cbuf_type == 0 ? cptr - s->cbuf : (cptr - s->cbuf) / 2,
|
|
2859
|
-
bp - s->stack_buf,
|
|
2860
|
-
sp - s->stack_buf,
|
|
2861
|
-
reopcode_info[opcode].name);
|
|
2862
|
-
#endif
|
|
2863
|
-
switch(opcode) {
|
|
2864
|
-
case REOP_match:
|
|
2865
|
-
return 1;
|
|
2866
|
-
no_match:
|
|
2867
|
-
for(;;) {
|
|
2868
|
-
REExecStateEnum type;
|
|
2869
|
-
if (bp == s->stack_buf)
|
|
2870
|
-
return 0;
|
|
2871
|
-
/* undo the modifications to capture[] */
|
|
2872
|
-
while (sp > bp) {
|
|
2873
|
-
capture[sp[-2].val] = sp[-1].ptr;
|
|
2874
|
-
sp -= 2;
|
|
2875
|
-
}
|
|
2876
|
-
|
|
2877
|
-
pc = sp[-3].ptr;
|
|
2878
|
-
cptr = sp[-2].ptr;
|
|
2879
|
-
type = sp[-1].bp.type;
|
|
2880
|
-
bp = s->stack_buf + sp[-1].bp.val;
|
|
2881
|
-
sp -= 3;
|
|
2882
|
-
if (type != RE_EXEC_STATE_LOOKAHEAD)
|
|
2883
|
-
break;
|
|
2884
|
-
}
|
|
2885
|
-
if (lre_poll_timeout(s))
|
|
2886
|
-
return LRE_RET_TIMEOUT;
|
|
2887
|
-
break;
|
|
2888
|
-
case REOP_lookahead_match:
|
|
2889
|
-
/* pop all the saved states until reaching the start of
|
|
2890
|
-
the lookahead and keep the updated captures and
|
|
2891
|
-
variables and the corresponding undo info. */
|
|
2892
|
-
{
|
|
2893
|
-
StackElem *sp1, *sp_top, *next_sp;
|
|
2894
|
-
REExecStateEnum type;
|
|
2895
|
-
|
|
2896
|
-
sp_top = sp;
|
|
2897
|
-
for(;;) {
|
|
2898
|
-
sp1 = sp;
|
|
2899
|
-
sp = bp;
|
|
2900
|
-
pc = sp[-3].ptr;
|
|
2901
|
-
cptr = sp[-2].ptr;
|
|
2902
|
-
type = sp[-1].bp.type;
|
|
2903
|
-
bp = s->stack_buf + sp[-1].bp.val;
|
|
2904
|
-
sp[-1].ptr = (void *)sp1; /* save the next value for the copy step */
|
|
2905
|
-
sp -= 3;
|
|
2906
|
-
if (type == RE_EXEC_STATE_LOOKAHEAD)
|
|
2907
|
-
break;
|
|
2908
|
-
}
|
|
2909
|
-
if (sp != s->stack_buf) {
|
|
2910
|
-
/* keep the undo info if there is a saved state */
|
|
2911
|
-
sp1 = sp;
|
|
2912
|
-
while (sp1 < sp_top) {
|
|
2913
|
-
next_sp = (void *)sp1[2].ptr;
|
|
2914
|
-
sp1 += 3;
|
|
2915
|
-
while (sp1 < next_sp)
|
|
2916
|
-
*sp++ = *sp1++;
|
|
2917
|
-
}
|
|
2918
|
-
}
|
|
2919
|
-
}
|
|
2920
|
-
break;
|
|
2921
|
-
case REOP_negative_lookahead_match:
|
|
2922
|
-
/* pop all the saved states until reaching start of the negative lookahead */
|
|
2923
|
-
for(;;) {
|
|
2924
|
-
REExecStateEnum type;
|
|
2925
|
-
type = bp[-1].bp.type;
|
|
2926
|
-
/* undo the modifications to capture[] */
|
|
2927
|
-
while (sp > bp) {
|
|
2928
|
-
capture[sp[-2].val] = sp[-1].ptr;
|
|
2929
|
-
sp -= 2;
|
|
2930
|
-
}
|
|
2931
|
-
pc = sp[-3].ptr;
|
|
2932
|
-
cptr = sp[-2].ptr;
|
|
2933
|
-
type = sp[-1].bp.type;
|
|
2934
|
-
bp = s->stack_buf + sp[-1].bp.val;
|
|
2935
|
-
sp -= 3;
|
|
2936
|
-
if (type == RE_EXEC_STATE_NEGATIVE_LOOKAHEAD)
|
|
2937
|
-
break;
|
|
2938
|
-
}
|
|
2939
|
-
goto no_match;
|
|
2940
|
-
case REOP_char32:
|
|
2941
|
-
case REOP_char32_i:
|
|
2942
|
-
val = get_u32(pc);
|
|
2943
|
-
pc += 4;
|
|
2944
|
-
goto test_char;
|
|
2945
|
-
case REOP_char:
|
|
2946
|
-
case REOP_char_i:
|
|
2947
|
-
val = get_u16(pc);
|
|
2948
|
-
pc += 2;
|
|
2949
|
-
test_char:
|
|
2950
|
-
if (cptr >= cbuf_end)
|
|
2951
|
-
goto no_match;
|
|
2952
|
-
GET_CHAR(c, cptr, cbuf_end, cbuf_type);
|
|
2953
|
-
if (opcode == REOP_char_i || opcode == REOP_char32_i) {
|
|
2954
|
-
c = lre_canonicalize(c, s->is_unicode);
|
|
2955
|
-
}
|
|
2956
|
-
if (val != c)
|
|
2957
|
-
goto no_match;
|
|
2958
|
-
break;
|
|
2959
|
-
case REOP_split_goto_first:
|
|
2960
|
-
case REOP_split_next_first:
|
|
2961
|
-
{
|
|
2962
|
-
const uint8_t *pc1;
|
|
2963
|
-
|
|
2964
|
-
val = get_u32(pc);
|
|
2965
|
-
pc += 4;
|
|
2966
|
-
if (opcode == REOP_split_next_first) {
|
|
2967
|
-
pc1 = pc + (int)val;
|
|
2968
|
-
} else {
|
|
2969
|
-
pc1 = pc;
|
|
2970
|
-
pc = pc + (int)val;
|
|
2971
|
-
}
|
|
2972
|
-
CHECK_STACK_SPACE(3);
|
|
2973
|
-
sp[0].ptr = (uint8_t *)pc1;
|
|
2974
|
-
sp[1].ptr = (uint8_t *)cptr;
|
|
2975
|
-
sp[2].bp.val = bp - s->stack_buf;
|
|
2976
|
-
sp[2].bp.type = RE_EXEC_STATE_SPLIT;
|
|
2977
|
-
sp += 3;
|
|
2978
|
-
bp = sp;
|
|
2979
|
-
}
|
|
2980
|
-
break;
|
|
2981
|
-
case REOP_lookahead:
|
|
2982
|
-
case REOP_negative_lookahead:
|
|
2983
|
-
val = get_u32(pc);
|
|
2984
|
-
pc += 4;
|
|
2985
|
-
CHECK_STACK_SPACE(3);
|
|
2986
|
-
sp[0].ptr = (uint8_t *)(pc + (int)val);
|
|
2987
|
-
sp[1].ptr = (uint8_t *)cptr;
|
|
2988
|
-
sp[2].bp.val = bp - s->stack_buf;
|
|
2989
|
-
sp[2].bp.type = RE_EXEC_STATE_LOOKAHEAD + opcode - REOP_lookahead;
|
|
2990
|
-
sp += 3;
|
|
2991
|
-
bp = sp;
|
|
2992
|
-
break;
|
|
2993
|
-
case REOP_goto:
|
|
2994
|
-
val = get_u32(pc);
|
|
2995
|
-
pc += 4 + (int)val;
|
|
2996
|
-
if (lre_poll_timeout(s))
|
|
2997
|
-
return LRE_RET_TIMEOUT;
|
|
2998
|
-
break;
|
|
2999
|
-
case REOP_line_start:
|
|
3000
|
-
case REOP_line_start_m:
|
|
3001
|
-
if (cptr == s->cbuf)
|
|
3002
|
-
break;
|
|
3003
|
-
if (opcode == REOP_line_start)
|
|
3004
|
-
goto no_match;
|
|
3005
|
-
PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type);
|
|
3006
|
-
if (!is_line_terminator(c))
|
|
3007
|
-
goto no_match;
|
|
3008
|
-
break;
|
|
3009
|
-
case REOP_line_end:
|
|
3010
|
-
case REOP_line_end_m:
|
|
3011
|
-
if (cptr == cbuf_end)
|
|
3012
|
-
break;
|
|
3013
|
-
if (opcode == REOP_line_end)
|
|
3014
|
-
goto no_match;
|
|
3015
|
-
PEEK_CHAR(c, cptr, cbuf_end, cbuf_type);
|
|
3016
|
-
if (!is_line_terminator(c))
|
|
3017
|
-
goto no_match;
|
|
3018
|
-
break;
|
|
3019
|
-
case REOP_dot:
|
|
3020
|
-
if (cptr == cbuf_end)
|
|
3021
|
-
goto no_match;
|
|
3022
|
-
GET_CHAR(c, cptr, cbuf_end, cbuf_type);
|
|
3023
|
-
if (is_line_terminator(c))
|
|
3024
|
-
goto no_match;
|
|
3025
|
-
break;
|
|
3026
|
-
case REOP_any:
|
|
3027
|
-
if (cptr == cbuf_end)
|
|
3028
|
-
goto no_match;
|
|
3029
|
-
GET_CHAR(c, cptr, cbuf_end, cbuf_type);
|
|
3030
|
-
break;
|
|
3031
|
-
case REOP_space:
|
|
3032
|
-
if (cptr == cbuf_end)
|
|
3033
|
-
goto no_match;
|
|
3034
|
-
GET_CHAR(c, cptr, cbuf_end, cbuf_type);
|
|
3035
|
-
if (!lre_is_space(c))
|
|
3036
|
-
goto no_match;
|
|
3037
|
-
break;
|
|
3038
|
-
case REOP_not_space:
|
|
3039
|
-
if (cptr == cbuf_end)
|
|
3040
|
-
goto no_match;
|
|
3041
|
-
GET_CHAR(c, cptr, cbuf_end, cbuf_type);
|
|
3042
|
-
if (lre_is_space(c))
|
|
3043
|
-
goto no_match;
|
|
3044
|
-
break;
|
|
3045
|
-
case REOP_save_start:
|
|
3046
|
-
case REOP_save_end:
|
|
3047
|
-
val = *pc++;
|
|
3048
|
-
if (val >= (uint32_t)s->capture_count)
|
|
3049
|
-
return LRE_RET_BYTECODE_ERROR;
|
|
3050
|
-
idx = 2 * val + opcode - REOP_save_start;
|
|
3051
|
-
SAVE_CAPTURE(idx, (uint8_t *)cptr);
|
|
3052
|
-
break;
|
|
3053
|
-
case REOP_save_reset:
|
|
3054
|
-
{
|
|
3055
|
-
uint32_t val2;
|
|
3056
|
-
val = pc[0];
|
|
3057
|
-
val2 = pc[1];
|
|
3058
|
-
pc += 2;
|
|
3059
|
-
if (val2 >= (uint32_t)s->capture_count)
|
|
3060
|
-
return LRE_RET_BYTECODE_ERROR;
|
|
3061
|
-
CHECK_STACK_SPACE(2 * (val2 - val + 1));
|
|
3062
|
-
while (val <= val2) {
|
|
3063
|
-
idx = 2 * val;
|
|
3064
|
-
SAVE_CAPTURE(idx, NULL);
|
|
3065
|
-
idx = 2 * val + 1;
|
|
3066
|
-
SAVE_CAPTURE(idx, NULL);
|
|
3067
|
-
val++;
|
|
3068
|
-
}
|
|
3069
|
-
}
|
|
3070
|
-
break;
|
|
3071
|
-
case REOP_set_i32:
|
|
3072
|
-
idx = 2 * s->capture_count + pc[0];
|
|
3073
|
-
val = get_u32(pc + 1);
|
|
3074
|
-
pc += 5;
|
|
3075
|
-
SAVE_CAPTURE_CHECK(idx, (void *)(uintptr_t)val);
|
|
3076
|
-
break;
|
|
3077
|
-
case REOP_loop:
|
|
3078
|
-
{
|
|
3079
|
-
uint32_t val2;
|
|
3080
|
-
idx = 2 * s->capture_count + pc[0];
|
|
3081
|
-
val = get_u32(pc + 1);
|
|
3082
|
-
pc += 5;
|
|
3083
|
-
|
|
3084
|
-
val2 = (uintptr_t)capture[idx] - 1;
|
|
3085
|
-
SAVE_CAPTURE_CHECK(idx, (void *)(uintptr_t)val2);
|
|
3086
|
-
if (val2 != 0) {
|
|
3087
|
-
pc += (int)val;
|
|
3088
|
-
if (lre_poll_timeout(s))
|
|
3089
|
-
return LRE_RET_TIMEOUT;
|
|
3090
|
-
}
|
|
3091
|
-
}
|
|
3092
|
-
break;
|
|
3093
|
-
case REOP_loop_split_goto_first:
|
|
3094
|
-
case REOP_loop_split_next_first:
|
|
3095
|
-
case REOP_loop_check_adv_split_goto_first:
|
|
3096
|
-
case REOP_loop_check_adv_split_next_first:
|
|
3097
|
-
{
|
|
3098
|
-
const uint8_t *pc1;
|
|
3099
|
-
uint32_t val2, limit;
|
|
3100
|
-
idx = 2 * s->capture_count + pc[0];
|
|
3101
|
-
limit = get_u32(pc + 1);
|
|
3102
|
-
val = get_u32(pc + 5);
|
|
3103
|
-
pc += 9;
|
|
3104
|
-
|
|
3105
|
-
/* decrement the counter */
|
|
3106
|
-
val2 = (uintptr_t)capture[idx] - 1;
|
|
3107
|
-
SAVE_CAPTURE_CHECK(idx, (void *)(uintptr_t)val2);
|
|
3108
|
-
|
|
3109
|
-
if (val2 > limit) {
|
|
3110
|
-
/* normal loop if counter > limit */
|
|
3111
|
-
pc += (int)val;
|
|
3112
|
-
if (lre_poll_timeout(s))
|
|
3113
|
-
return LRE_RET_TIMEOUT;
|
|
3114
|
-
} else {
|
|
3115
|
-
/* check advance */
|
|
3116
|
-
if ((opcode == REOP_loop_check_adv_split_goto_first ||
|
|
3117
|
-
opcode == REOP_loop_check_adv_split_next_first) &&
|
|
3118
|
-
capture[idx + 1] == cptr &&
|
|
3119
|
-
val2 != limit) {
|
|
3120
|
-
goto no_match;
|
|
3121
|
-
}
|
|
3122
|
-
|
|
3123
|
-
/* otherwise conditional split */
|
|
3124
|
-
if (val2 != 0) {
|
|
3125
|
-
if (opcode == REOP_loop_split_next_first ||
|
|
3126
|
-
opcode == REOP_loop_check_adv_split_next_first) {
|
|
3127
|
-
pc1 = pc + (int)val;
|
|
3128
|
-
} else {
|
|
3129
|
-
pc1 = pc;
|
|
3130
|
-
pc = pc + (int)val;
|
|
3131
|
-
}
|
|
3132
|
-
CHECK_STACK_SPACE(3);
|
|
3133
|
-
sp[0].ptr = (uint8_t *)pc1;
|
|
3134
|
-
sp[1].ptr = (uint8_t *)cptr;
|
|
3135
|
-
sp[2].bp.val = bp - s->stack_buf;
|
|
3136
|
-
sp[2].bp.type = RE_EXEC_STATE_SPLIT;
|
|
3137
|
-
sp += 3;
|
|
3138
|
-
bp = sp;
|
|
3139
|
-
}
|
|
3140
|
-
}
|
|
3141
|
-
}
|
|
3142
|
-
break;
|
|
3143
|
-
case REOP_set_char_pos:
|
|
3144
|
-
idx = 2 * s->capture_count + pc[0];
|
|
3145
|
-
pc++;
|
|
3146
|
-
SAVE_CAPTURE_CHECK(idx, (uint8_t *)cptr);
|
|
3147
|
-
break;
|
|
3148
|
-
case REOP_check_advance:
|
|
3149
|
-
idx = 2 * s->capture_count + pc[0];
|
|
3150
|
-
pc++;
|
|
3151
|
-
if (capture[idx] == cptr)
|
|
3152
|
-
goto no_match;
|
|
3153
|
-
break;
|
|
3154
|
-
case REOP_word_boundary:
|
|
3155
|
-
case REOP_word_boundary_i:
|
|
3156
|
-
case REOP_not_word_boundary:
|
|
3157
|
-
case REOP_not_word_boundary_i:
|
|
3158
|
-
{
|
|
3159
|
-
bool v1, v2;
|
|
3160
|
-
int ignore_case = (opcode == REOP_word_boundary_i || opcode == REOP_not_word_boundary_i);
|
|
3161
|
-
bool is_boundary = (opcode == REOP_word_boundary || opcode == REOP_word_boundary_i);
|
|
3162
|
-
/* char before */
|
|
3163
|
-
if (cptr == s->cbuf) {
|
|
3164
|
-
v1 = false;
|
|
3165
|
-
} else {
|
|
3166
|
-
PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type);
|
|
3167
|
-
if (c < 256) {
|
|
3168
|
-
v1 = (lre_is_word_byte(c) != 0);
|
|
3169
|
-
} else {
|
|
3170
|
-
v1 = ignore_case && (c == 0x017f || c == 0x212a);
|
|
3171
|
-
}
|
|
3172
|
-
}
|
|
3173
|
-
/* current char */
|
|
3174
|
-
if (cptr >= cbuf_end) {
|
|
3175
|
-
v2 = false;
|
|
3176
|
-
} else {
|
|
3177
|
-
PEEK_CHAR(c, cptr, cbuf_end, cbuf_type);
|
|
3178
|
-
if (c < 256) {
|
|
3179
|
-
v2 = (lre_is_word_byte(c) != 0);
|
|
3180
|
-
} else {
|
|
3181
|
-
v2 = ignore_case && (c == 0x017f || c == 0x212a);
|
|
3182
|
-
}
|
|
3183
|
-
}
|
|
3184
|
-
if (v1 ^ v2 ^ is_boundary)
|
|
3185
|
-
goto no_match;
|
|
3186
|
-
}
|
|
3187
|
-
break;
|
|
3188
|
-
case REOP_back_reference:
|
|
3189
|
-
case REOP_back_reference_i:
|
|
3190
|
-
case REOP_backward_back_reference:
|
|
3191
|
-
case REOP_backward_back_reference_i:
|
|
3192
|
-
{
|
|
3193
|
-
const uint8_t *cptr1, *cptr1_end, *cptr1_start;
|
|
3194
|
-
const uint8_t *pc1;
|
|
3195
|
-
uint32_t c1, c2;
|
|
3196
|
-
int i, n;
|
|
3197
|
-
|
|
3198
|
-
n = *pc++;
|
|
3199
|
-
pc1 = pc;
|
|
3200
|
-
pc += n;
|
|
3201
|
-
|
|
3202
|
-
for(i = 0; i < n; i++) {
|
|
3203
|
-
val = pc1[i];
|
|
3204
|
-
if (val >= s->capture_count)
|
|
3205
|
-
goto no_match;
|
|
3206
|
-
cptr1_start = capture[2 * val];
|
|
3207
|
-
cptr1_end = capture[2 * val + 1];
|
|
3208
|
-
/* test the first not empty capture */
|
|
3209
|
-
if (cptr1_start && cptr1_end) {
|
|
3210
|
-
if (opcode == REOP_back_reference ||
|
|
3211
|
-
opcode == REOP_back_reference_i) {
|
|
3212
|
-
cptr1 = cptr1_start;
|
|
3213
|
-
while (cptr1 < cptr1_end) {
|
|
3214
|
-
if (cptr >= cbuf_end)
|
|
3215
|
-
goto no_match;
|
|
3216
|
-
GET_CHAR(c1, cptr1, cptr1_end, cbuf_type);
|
|
3217
|
-
GET_CHAR(c2, cptr, cbuf_end, cbuf_type);
|
|
3218
|
-
if (opcode == REOP_back_reference_i) {
|
|
3219
|
-
c1 = lre_canonicalize(c1, s->is_unicode);
|
|
3220
|
-
c2 = lre_canonicalize(c2, s->is_unicode);
|
|
3221
|
-
}
|
|
3222
|
-
if (c1 != c2)
|
|
3223
|
-
goto no_match;
|
|
3224
|
-
}
|
|
3225
|
-
} else {
|
|
3226
|
-
cptr1 = cptr1_end;
|
|
3227
|
-
while (cptr1 > cptr1_start) {
|
|
3228
|
-
if (cptr == s->cbuf)
|
|
3229
|
-
goto no_match;
|
|
3230
|
-
GET_PREV_CHAR(c1, cptr1, cptr1_start, cbuf_type);
|
|
3231
|
-
GET_PREV_CHAR(c2, cptr, s->cbuf, cbuf_type);
|
|
3232
|
-
if (opcode == REOP_backward_back_reference_i) {
|
|
3233
|
-
c1 = lre_canonicalize(c1, s->is_unicode);
|
|
3234
|
-
c2 = lre_canonicalize(c2, s->is_unicode);
|
|
3235
|
-
}
|
|
3236
|
-
if (c1 != c2)
|
|
3237
|
-
goto no_match;
|
|
3238
|
-
}
|
|
3239
|
-
}
|
|
3240
|
-
break;
|
|
3241
|
-
}
|
|
3242
|
-
}
|
|
3243
|
-
}
|
|
3244
|
-
break;
|
|
3245
|
-
case REOP_range:
|
|
3246
|
-
case REOP_range_i:
|
|
3247
|
-
{
|
|
3248
|
-
int n;
|
|
3249
|
-
uint32_t low, high, idx_min, idx_max, idx;
|
|
3250
|
-
|
|
3251
|
-
n = get_u16(pc); /* n must be >= 1 */
|
|
3252
|
-
pc += 2;
|
|
3253
|
-
if (cptr >= cbuf_end)
|
|
3254
|
-
goto no_match;
|
|
3255
|
-
GET_CHAR(c, cptr, cbuf_end, cbuf_type);
|
|
3256
|
-
if (opcode == REOP_range_i) {
|
|
3257
|
-
c = lre_canonicalize(c, s->is_unicode);
|
|
3258
|
-
}
|
|
3259
|
-
idx_min = 0;
|
|
3260
|
-
low = get_u16(pc + 0 * 4);
|
|
3261
|
-
if (c < low)
|
|
3262
|
-
goto no_match;
|
|
3263
|
-
idx_max = n - 1;
|
|
3264
|
-
high = get_u16(pc + idx_max * 4 + 2);
|
|
3265
|
-
/* 0xffff in for last value means +infinity */
|
|
3266
|
-
if (unlikely(c >= 0xffff) && high == 0xffff)
|
|
3267
|
-
goto range_match;
|
|
3268
|
-
if (c > high)
|
|
3269
|
-
goto no_match;
|
|
3270
|
-
while (idx_min <= idx_max) {
|
|
3271
|
-
idx = (idx_min + idx_max) / 2;
|
|
3272
|
-
low = get_u16(pc + idx * 4);
|
|
3273
|
-
high = get_u16(pc + idx * 4 + 2);
|
|
3274
|
-
if (c < low)
|
|
3275
|
-
idx_max = idx - 1;
|
|
3276
|
-
else if (c > high)
|
|
3277
|
-
idx_min = idx + 1;
|
|
3278
|
-
else
|
|
3279
|
-
goto range_match;
|
|
3280
|
-
}
|
|
3281
|
-
goto no_match;
|
|
3282
|
-
range_match:
|
|
3283
|
-
pc += 4 * n;
|
|
3284
|
-
}
|
|
3285
|
-
break;
|
|
3286
|
-
case REOP_range32:
|
|
3287
|
-
case REOP_range32_i:
|
|
3288
|
-
{
|
|
3289
|
-
int n;
|
|
3290
|
-
uint32_t low, high, idx_min, idx_max, idx;
|
|
3291
|
-
|
|
3292
|
-
n = get_u16(pc); /* n must be >= 1 */
|
|
3293
|
-
pc += 2;
|
|
3294
|
-
if (cptr >= cbuf_end)
|
|
3295
|
-
goto no_match;
|
|
3296
|
-
GET_CHAR(c, cptr, cbuf_end, cbuf_type);
|
|
3297
|
-
if (opcode == REOP_range32_i) {
|
|
3298
|
-
c = lre_canonicalize(c, s->is_unicode);
|
|
3299
|
-
}
|
|
3300
|
-
idx_min = 0;
|
|
3301
|
-
low = get_u32(pc + 0 * 8);
|
|
3302
|
-
if (c < low)
|
|
3303
|
-
goto no_match;
|
|
3304
|
-
idx_max = n - 1;
|
|
3305
|
-
high = get_u32(pc + idx_max * 8 + 4);
|
|
3306
|
-
if (c > high)
|
|
3307
|
-
goto no_match;
|
|
3308
|
-
while (idx_min <= idx_max) {
|
|
3309
|
-
idx = (idx_min + idx_max) / 2;
|
|
3310
|
-
low = get_u32(pc + idx * 8);
|
|
3311
|
-
high = get_u32(pc + idx * 8 + 4);
|
|
3312
|
-
if (c < low)
|
|
3313
|
-
idx_max = idx - 1;
|
|
3314
|
-
else if (c > high)
|
|
3315
|
-
idx_min = idx + 1;
|
|
3316
|
-
else
|
|
3317
|
-
goto range32_match;
|
|
3318
|
-
}
|
|
3319
|
-
goto no_match;
|
|
3320
|
-
range32_match:
|
|
3321
|
-
pc += 8 * n;
|
|
3322
|
-
}
|
|
3323
|
-
break;
|
|
3324
|
-
case REOP_prev:
|
|
3325
|
-
/* go to the previous char */
|
|
3326
|
-
if (cptr == s->cbuf)
|
|
3327
|
-
goto no_match;
|
|
3328
|
-
PREV_CHAR(cptr, s->cbuf, cbuf_type);
|
|
3329
|
-
break;
|
|
3330
|
-
default:
|
|
3331
|
-
#ifdef DUMP_EXEC
|
|
3332
|
-
printf("unknown opcode pc=%ld\n", pc - 1 - pc_start);
|
|
3333
|
-
#endif
|
|
3334
|
-
abort();
|
|
3335
|
-
}
|
|
3336
|
-
}
|
|
3337
|
-
}
|
|
3733
|
+
#define LRE_BT_FUNC lre_exec_backtrack
|
|
3734
|
+
#define LRE_CBUF_TYPE_INIT (s->cbuf_type)
|
|
3735
|
+
#include "libregexp-backtrack.c.inc"
|
|
3736
|
+
#undef LRE_BT_FUNC
|
|
3737
|
+
#undef LRE_CBUF_TYPE_INIT
|
|
3338
3738
|
|
|
3339
3739
|
/* Return 1 if match, 0 if not match or < 0 if error (see LRE_RET_x). cindex is the
|
|
3340
3740
|
starting position of the match and must be such as 0 <= cindex <=
|
|
3341
3741
|
clen. */
|
|
3342
|
-
int
|
|
3343
|
-
|
|
3344
|
-
|
|
3742
|
+
static int lre_exec_internal(uint8_t **capture, const uint8_t *bc_buf,
|
|
3743
|
+
uint32_t bytecode_offset,
|
|
3744
|
+
const uint8_t *cbuf, int cindex, int clen,
|
|
3745
|
+
int cbuf_type, void *opaque)
|
|
3345
3746
|
{
|
|
3346
3747
|
REExecContext s_s, *s = &s_s;
|
|
3347
3748
|
int re_flags, i, ret;
|
|
@@ -3372,13 +3773,42 @@ int lre_exec(uint8_t **capture,
|
|
|
3372
3773
|
}
|
|
3373
3774
|
}
|
|
3374
3775
|
|
|
3375
|
-
ret = lre_exec_backtrack(s, capture,
|
|
3776
|
+
ret = lre_exec_backtrack(s, capture,
|
|
3777
|
+
bc_buf + RE_HEADER_LEN + bytecode_offset, cptr);
|
|
3376
3778
|
|
|
3377
3779
|
if (s->stack_buf != s->static_stack_buf)
|
|
3378
3780
|
lre_realloc(s->opaque, s->stack_buf, 0);
|
|
3379
3781
|
return ret;
|
|
3380
3782
|
}
|
|
3381
3783
|
|
|
3784
|
+
int lre_exec(uint8_t **capture,
|
|
3785
|
+
const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen,
|
|
3786
|
+
int cbuf_type, void *opaque)
|
|
3787
|
+
{
|
|
3788
|
+
return lre_exec_internal(capture, bc_buf, 0, cbuf, cindex, clen,
|
|
3789
|
+
cbuf_type, opaque);
|
|
3790
|
+
}
|
|
3791
|
+
|
|
3792
|
+
/* Execute the pattern anchored at 'cindex', entering the bytecode at
|
|
3793
|
+
'bytecode_offset' (which must point at the leading REOP_save_start 0 that
|
|
3794
|
+
follows the synthetic .*? scan prologue). Used by the quickjs fast paths
|
|
3795
|
+
after they have located a candidate start position by direct string
|
|
3796
|
+
search. Returns 0 when 'bytecode_offset' is not a valid save_start entry. */
|
|
3797
|
+
int lre_exec_at(uint8_t **capture,
|
|
3798
|
+
const uint8_t *bc_buf, uint32_t bytecode_offset,
|
|
3799
|
+
const uint8_t *cbuf, int cindex, int clen,
|
|
3800
|
+
int cbuf_type, void *opaque)
|
|
3801
|
+
{
|
|
3802
|
+
uint32_t bytecode_len = get_u32(bc_buf + RE_HEADER_BYTECODE_LEN);
|
|
3803
|
+
|
|
3804
|
+
if (bytecode_len < 2 || bytecode_offset > bytecode_len - 2 ||
|
|
3805
|
+
bc_buf[RE_HEADER_LEN + bytecode_offset] != REOP_save_start ||
|
|
3806
|
+
bc_buf[RE_HEADER_LEN + bytecode_offset + 1] != 0)
|
|
3807
|
+
return 0;
|
|
3808
|
+
return lre_exec_internal(capture, bc_buf, bytecode_offset, cbuf, cindex,
|
|
3809
|
+
clen, cbuf_type, opaque);
|
|
3810
|
+
}
|
|
3811
|
+
|
|
3382
3812
|
int lre_get_alloc_count(const uint8_t *bc_buf)
|
|
3383
3813
|
{
|
|
3384
3814
|
return bc_buf[RE_HEADER_CAPTURE_COUNT] * 2 +
|
|
@@ -3388,14 +3818,25 @@ int lre_get_alloc_count(const uint8_t *bc_buf)
|
|
|
3388
3818
|
/* Structurally validate serialized regexp bytecode (e.g. from JS_ReadObject)
|
|
3389
3819
|
before it is executed: a present header and a body length that fits within
|
|
3390
3820
|
the buffer. Returns 0 on success, -1 if the bytecode is malformed. */
|
|
3391
|
-
int lre_check_bytecode(const uint8_t *bc_buf, int bc_buf_len)
|
|
3821
|
+
int lre_check_bytecode(const uint8_t *bc_buf, int bc_buf_len, void *opaque)
|
|
3392
3822
|
{
|
|
3393
3823
|
uint32_t re_bytecode_len;
|
|
3824
|
+
LREMetadata meta;
|
|
3394
3825
|
if (bc_buf_len < RE_HEADER_LEN)
|
|
3395
3826
|
return -1;
|
|
3396
3827
|
re_bytecode_len = get_u32(bc_buf + RE_HEADER_BYTECODE_LEN);
|
|
3397
3828
|
if (re_bytecode_len > (uint32_t)(bc_buf_len - RE_HEADER_LEN))
|
|
3398
3829
|
return -1;
|
|
3830
|
+
if (!re_validate_code(bc_buf + RE_HEADER_LEN, re_bytecode_len,
|
|
3831
|
+
bc_buf[RE_HEADER_CAPTURE_COUNT],
|
|
3832
|
+
bc_buf[RE_HEADER_REGISTER_COUNT], opaque))
|
|
3833
|
+
return -1;
|
|
3834
|
+
if (lre_parse_metadata(bc_buf, bc_buf_len, &meta, NULL) < 0)
|
|
3835
|
+
return -1;
|
|
3836
|
+
if (meta.kind != LRE_META_NONE &&
|
|
3837
|
+
!re_validate_entry(bc_buf + RE_HEADER_LEN, re_bytecode_len,
|
|
3838
|
+
meta.entry_offset))
|
|
3839
|
+
return -1;
|
|
3399
3840
|
return 0;
|
|
3400
3841
|
}
|
|
3401
3842
|
|
|
@@ -3411,13 +3852,20 @@ int lre_get_flags(const uint8_t *bc_buf)
|
|
|
3411
3852
|
|
|
3412
3853
|
/* Return NULL if no group names. Otherwise, return a pointer to
|
|
3413
3854
|
'capture_count - 1' zero terminated UTF-8 strings. */
|
|
3414
|
-
const char *lre_get_groupnames(const uint8_t *bc_buf)
|
|
3855
|
+
const char *lre_get_groupnames(const uint8_t *bc_buf, size_t bc_buf_len)
|
|
3415
3856
|
{
|
|
3416
|
-
|
|
3857
|
+
const uint8_t *trailer;
|
|
3858
|
+
|
|
3859
|
+
if (!bc_buf || bc_buf_len < RE_HEADER_LEN)
|
|
3860
|
+
return NULL;
|
|
3417
3861
|
if ((lre_get_flags(bc_buf) & LRE_FLAG_NAMED_GROUPS) == 0)
|
|
3418
3862
|
return NULL;
|
|
3419
|
-
|
|
3420
|
-
|
|
3863
|
+
/* Group names follow the optional optimization metadata; parse it to
|
|
3864
|
+
find the trailer. */
|
|
3865
|
+
if (lre_parse_metadata(bc_buf, bc_buf_len, NULL, &trailer) < 0 ||
|
|
3866
|
+
trailer >= bc_buf + bc_buf_len)
|
|
3867
|
+
return NULL;
|
|
3868
|
+
return (const char *)trailer;
|
|
3421
3869
|
}
|
|
3422
3870
|
|
|
3423
3871
|
#ifdef TEST
|