Line | Count | Source |
1 | | /* |
2 | | Copyright (c) 2013. The YARA Authors. All Rights Reserved. |
3 | | |
4 | | Redistribution and use in source and binary forms, with or without modification, |
5 | | are permitted provided that the following conditions are met: |
6 | | |
7 | | 1. Redistributions of source code must retain the above copyright notice, this |
8 | | list of conditions and the following disclaimer. |
9 | | |
10 | | 2. Redistributions in binary form must reproduce the above copyright notice, |
11 | | this list of conditions and the following disclaimer in the documentation and/or |
12 | | other materials provided with the distribution. |
13 | | |
14 | | 3. Neither the name of the copyright holder nor the names of its contributors |
15 | | may be used to endorse or promote products derived from this software without |
16 | | specific prior written permission. |
17 | | |
18 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
19 | | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
20 | | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
21 | | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
22 | | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
23 | | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
24 | | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
25 | | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 | | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
27 | | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | | */ |
29 | | |
30 | | /* |
31 | | |
32 | | This module implements a regular expressions engine based on Thompson's |
33 | | algorithm as described by Russ Cox in http://swtch.com/~rsc/regexp/regexp2.html. |
34 | | |
35 | | What the article names a "thread" has been named a "fiber" in this code, in |
36 | | order to avoid confusion with operating system threads. |
37 | | |
38 | | */ |
39 | | |
40 | | #include <assert.h> |
41 | | #include <string.h> |
42 | | #include <yara/arena.h> |
43 | | #include <yara/compiler.h> |
44 | | #include <yara/error.h> |
45 | | #include <yara/globals.h> |
46 | | #include <yara/hex_lexer.h> |
47 | | #include <yara/libyara.h> |
48 | | #include <yara/limits.h> |
49 | | #include <yara/mem.h> |
50 | | #include <yara/re.h> |
51 | | #include <yara/re_lexer.h> |
52 | | #include <yara/strutils.h> |
53 | | #include <yara/threading.h> |
54 | | #include <yara/unaligned.h> |
55 | | #include <yara/utils.h> |
56 | | |
57 | 0 | #define EMIT_BACKWARDS 0x01 |
58 | 0 | #define EMIT_DONT_SET_FORWARDS_CODE 0x02 |
59 | 0 | #define EMIT_DONT_SET_BACKWARDS_CODE 0x04 |
60 | | |
61 | | #ifndef INT16_MAX |
62 | | #define INT16_MAX (32767) |
63 | | #endif |
64 | | |
65 | | typedef uint8_t RE_SPLIT_ID_TYPE; |
66 | | |
67 | | // RE_REPEAT_ARGS and RE_REPEAT_ANY_ARGS are structures that are embedded in |
68 | | // the regexp's instruction stream. As such, they are not always aligned to |
69 | | // 8-byte boundaries, so they need to be "packed" structures in order to prevent |
70 | | // issues due to unaligned memory accesses. |
71 | | #pragma pack(push) |
72 | | #pragma pack(1) |
73 | | |
74 | | typedef struct _RE_REPEAT_ARGS |
75 | | { |
76 | | uint16_t min; |
77 | | uint16_t max; |
78 | | int32_t offset; |
79 | | |
80 | | } RE_REPEAT_ARGS; |
81 | | |
82 | | typedef struct _RE_REPEAT_ANY_ARGS |
83 | | { |
84 | | uint16_t min; |
85 | | uint16_t max; |
86 | | |
87 | | } RE_REPEAT_ANY_ARGS; |
88 | | |
89 | | #pragma pack(pop) |
90 | | |
91 | | typedef struct _RE_EMIT_CONTEXT |
92 | | { |
93 | | YR_ARENA* arena; |
94 | | RE_SPLIT_ID_TYPE next_split_id; |
95 | | |
96 | | } RE_EMIT_CONTEXT; |
97 | | |
98 | 0 | #define CHAR_IN_CLASS(cls, chr) ((cls)[(chr) / 8] & 1 << ((chr) % 8)) |
99 | | |
100 | | static bool _yr_re_is_char_in_class( |
101 | | RE_CLASS* re_class, |
102 | | uint8_t chr, |
103 | | int case_insensitive) |
104 | 0 | { |
105 | 0 | int result = CHAR_IN_CLASS(re_class->bitmap, chr); |
106 | |
|
107 | 0 | if (case_insensitive) |
108 | 0 | result |= CHAR_IN_CLASS(re_class->bitmap, yr_altercase[chr]); |
109 | |
|
110 | 0 | if (re_class->negated) |
111 | 0 | result = !result; |
112 | |
|
113 | 0 | return result; |
114 | 0 | } |
115 | | |
116 | | static bool _yr_re_is_word_char(const uint8_t* input, uint8_t character_size) |
117 | 0 | { |
118 | 0 | int result = ((yr_isalnum(input) || (*input) == '_')); |
119 | |
|
120 | 0 | if (character_size == 2) |
121 | 0 | result = result && (*(input + 1) == 0); |
122 | |
|
123 | 0 | return result; |
124 | 0 | } |
125 | | |
126 | | RE_NODE* yr_re_node_create(int type) |
127 | 0 | { |
128 | 0 | RE_NODE* result = (RE_NODE*) yr_malloc(sizeof(RE_NODE)); |
129 | |
|
130 | 0 | if (result != NULL) |
131 | 0 | { |
132 | 0 | result->type = type; |
133 | 0 | result->children_head = NULL; |
134 | 0 | result->children_tail = NULL; |
135 | 0 | result->prev_sibling = NULL; |
136 | 0 | result->next_sibling = NULL; |
137 | 0 | result->greedy = true; |
138 | 0 | result->forward_code_ref = YR_ARENA_NULL_REF; |
139 | 0 | result->backward_code_ref = YR_ARENA_NULL_REF; |
140 | 0 | } |
141 | |
|
142 | 0 | return result; |
143 | 0 | } |
144 | | |
145 | | void yr_re_node_destroy(RE_NODE* node) |
146 | 0 | { |
147 | 0 | RE_NODE* child = node->children_head; |
148 | 0 | RE_NODE* next_child; |
149 | |
|
150 | 0 | while (child != NULL) |
151 | 0 | { |
152 | 0 | next_child = child->next_sibling; |
153 | 0 | yr_re_node_destroy(child); |
154 | 0 | child = next_child; |
155 | 0 | } |
156 | |
|
157 | 0 | if (node->type == RE_NODE_CLASS) |
158 | 0 | yr_free(node->re_class); |
159 | |
|
160 | 0 | yr_free(node); |
161 | 0 | } |
162 | | |
163 | | //////////////////////////////////////////////////////////////////////////////// |
164 | | // Appends a node to the end of the children list. |
165 | | // |
166 | | void yr_re_node_append_child(RE_NODE* node, RE_NODE* child) |
167 | 0 | { |
168 | 0 | if (node->children_head == NULL) |
169 | 0 | node->children_head = child; |
170 | |
|
171 | 0 | if (node->children_tail != NULL) |
172 | 0 | node->children_tail->next_sibling = child; |
173 | |
|
174 | 0 | child->prev_sibling = node->children_tail; |
175 | 0 | node->children_tail = child; |
176 | 0 | } |
177 | | |
178 | | //////////////////////////////////////////////////////////////////////////////// |
179 | | // Appends a node to the beginning of the children list. |
180 | | // |
181 | | void yr_re_node_prepend_child(RE_NODE* node, RE_NODE* child) |
182 | 0 | { |
183 | 0 | child->next_sibling = node->children_head; |
184 | |
|
185 | 0 | if (node->children_head != NULL) |
186 | 0 | node->children_head->prev_sibling = child; |
187 | |
|
188 | 0 | node->children_head = child; |
189 | |
|
190 | 0 | if (node->children_tail == NULL) |
191 | 0 | node->children_tail = child; |
192 | 0 | } |
193 | | |
194 | | int yr_re_ast_create(RE_AST** re_ast) |
195 | 0 | { |
196 | 0 | *re_ast = (RE_AST*) yr_malloc(sizeof(RE_AST)); |
197 | |
|
198 | 0 | if (*re_ast == NULL) |
199 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
200 | | |
201 | 0 | (*re_ast)->flags = 0; |
202 | 0 | (*re_ast)->root_node = NULL; |
203 | |
|
204 | 0 | return ERROR_SUCCESS; |
205 | 0 | } |
206 | | |
207 | | void yr_re_ast_destroy(RE_AST* re_ast) |
208 | 0 | { |
209 | 0 | if (re_ast->root_node != NULL) |
210 | 0 | yr_re_node_destroy(re_ast->root_node); |
211 | |
|
212 | 0 | yr_free(re_ast); |
213 | 0 | } |
214 | | |
215 | | //////////////////////////////////////////////////////////////////////////////// |
216 | | // Parses a regexp but don't emit its code. A further call to |
217 | | // yr_re_ast_emit_code is required to get the code. |
218 | | // |
219 | | int yr_re_parse( |
220 | | const char* re_string, |
221 | | RE_AST** re_ast, |
222 | | RE_ERROR* error, |
223 | | int flags) |
224 | 0 | { |
225 | 0 | return yr_parse_re_string(re_string, re_ast, error, flags); |
226 | 0 | } |
227 | | |
228 | | //////////////////////////////////////////////////////////////////////////////// |
229 | | // Parses a hex string but don't emit its code. A further call to |
230 | | // yr_re_ast_emit_code is required to get the code. |
231 | | // |
232 | | int yr_re_parse_hex(const char* hex_string, RE_AST** re_ast, RE_ERROR* error) |
233 | 0 | { |
234 | 0 | return yr_parse_hex_string(hex_string, re_ast, error); |
235 | 0 | } |
236 | | |
237 | | //////////////////////////////////////////////////////////////////////////////// |
238 | | // Parses the regexp and emit its code to the provided to the |
239 | | // YR_RE_CODE_SECTION in the specified arena. |
240 | | // |
241 | | int yr_re_compile( |
242 | | const char* re_string, |
243 | | int flags, |
244 | | int parser_flags, |
245 | | YR_ARENA* arena, |
246 | | YR_ARENA_REF* ref, |
247 | | RE_ERROR* error) |
248 | 0 | { |
249 | 0 | RE_AST* re_ast; |
250 | 0 | RE _re; |
251 | 0 | int result; |
252 | |
|
253 | 0 | result = yr_re_parse(re_string, &re_ast, error, parser_flags); |
254 | 0 | if (result != ERROR_UNKNOWN_ESCAPE_SEQUENCE) |
255 | 0 | FAIL_ON_ERROR(result); |
256 | |
|
257 | 0 | _re.flags = flags; |
258 | |
|
259 | 0 | FAIL_ON_ERROR_WITH_CLEANUP( |
260 | 0 | yr_arena_write_data(arena, YR_RE_CODE_SECTION, &_re, sizeof(_re), ref), |
261 | 0 | yr_re_ast_destroy(re_ast)); |
262 | |
|
263 | 0 | FAIL_ON_ERROR_WITH_CLEANUP( |
264 | 0 | yr_re_ast_emit_code(re_ast, arena, false), yr_re_ast_destroy(re_ast)); |
265 | |
|
266 | 0 | yr_re_ast_destroy(re_ast); |
267 | |
|
268 | 0 | return result; |
269 | 0 | } |
270 | | |
271 | | //////////////////////////////////////////////////////////////////////////////// |
272 | | // Verifies if the target string matches the pattern |
273 | | // |
274 | | // Args: |
275 | | // context: Scan context |
276 | | // re: A pointer to a compiled regexp |
277 | | // target: Target string |
278 | | // |
279 | | // Returns: |
280 | | // See return codes for yr_re_exec |
281 | | // |
282 | | int yr_re_match(YR_SCAN_CONTEXT* context, RE* re, const char* target) |
283 | 0 | { |
284 | 0 | int result; |
285 | |
|
286 | 0 | yr_re_exec( |
287 | 0 | context, |
288 | 0 | re->code, |
289 | 0 | (uint8_t*) target, |
290 | 0 | strlen(target), |
291 | 0 | 0, |
292 | 0 | re->flags | RE_FLAGS_SCAN, |
293 | 0 | NULL, |
294 | 0 | NULL, |
295 | 0 | &result); |
296 | |
|
297 | 0 | return result; |
298 | 0 | } |
299 | | |
300 | | //////////////////////////////////////////////////////////////////////////////// |
301 | | // Verifies if the provided regular expression is just a literal string |
302 | | // like "abc", "12345", without any wildcard, operator, etc. In that case |
303 | | // returns the string as a SIZED_STRING, or returns NULL if otherwise. |
304 | | // |
305 | | // The caller is responsible for deallocating the returned SIZED_STRING by |
306 | | // calling yr_free. |
307 | | // |
308 | | SIZED_STRING* yr_re_ast_extract_literal(RE_AST* re_ast) |
309 | 0 | { |
310 | 0 | SIZED_STRING* string; |
311 | 0 | RE_NODE* child; |
312 | |
|
313 | 0 | int length = 0; |
314 | |
|
315 | 0 | if (re_ast->root_node->type == RE_NODE_LITERAL) |
316 | 0 | { |
317 | 0 | length = 1; |
318 | 0 | } |
319 | 0 | else if (re_ast->root_node->type == RE_NODE_CONCAT) |
320 | 0 | { |
321 | 0 | child = re_ast->root_node->children_tail; |
322 | |
|
323 | 0 | while (child != NULL && child->type == RE_NODE_LITERAL) |
324 | 0 | { |
325 | 0 | length++; |
326 | 0 | child = child->prev_sibling; |
327 | 0 | } |
328 | |
|
329 | 0 | if (child != NULL) |
330 | 0 | return NULL; |
331 | 0 | } |
332 | 0 | else |
333 | 0 | { |
334 | 0 | return NULL; |
335 | 0 | } |
336 | | |
337 | 0 | string = (SIZED_STRING*) yr_malloc(sizeof(SIZED_STRING) + length); |
338 | |
|
339 | 0 | if (string == NULL) |
340 | 0 | return NULL; |
341 | | |
342 | 0 | string->length = length; |
343 | 0 | string->flags = 0; |
344 | |
|
345 | 0 | if (re_ast->root_node->type == RE_NODE_LITERAL) |
346 | 0 | { |
347 | 0 | string->c_string[0] = re_ast->root_node->value; |
348 | 0 | } |
349 | 0 | else |
350 | 0 | { |
351 | 0 | child = re_ast->root_node->children_tail; |
352 | |
|
353 | 0 | while (child != NULL) |
354 | 0 | { |
355 | 0 | string->c_string[--length] = child->value; |
356 | 0 | child = child->prev_sibling; |
357 | 0 | } |
358 | 0 | } |
359 | |
|
360 | 0 | string->c_string[string->length] = '\0'; |
361 | |
|
362 | 0 | return string; |
363 | 0 | } |
364 | | |
365 | | int _yr_re_node_has_unbounded_quantifier_for_dot(RE_NODE* re_node) |
366 | 0 | { |
367 | 0 | RE_NODE* child; |
368 | |
|
369 | 0 | if ((re_node->type == RE_NODE_STAR || re_node->type == RE_NODE_PLUS) && |
370 | 0 | re_node->children_head->type == RE_NODE_ANY) |
371 | 0 | return true; |
372 | | |
373 | 0 | if (re_node->type == RE_NODE_RANGE_ANY && re_node->end == RE_MAX_RANGE) |
374 | 0 | return true; |
375 | | |
376 | 0 | if (re_node->type == RE_NODE_CONCAT) |
377 | 0 | { |
378 | 0 | child = re_node->children_tail; |
379 | |
|
380 | 0 | while (child != NULL) |
381 | 0 | { |
382 | 0 | if (_yr_re_node_has_unbounded_quantifier_for_dot(child)) |
383 | 0 | return true; |
384 | | |
385 | 0 | child = child->prev_sibling; |
386 | 0 | } |
387 | 0 | } |
388 | | |
389 | 0 | return false; |
390 | 0 | } |
391 | | |
392 | | //////////////////////////////////////////////////////////////////////////////// |
393 | | // Detects the use of .*, .+ or .{x,} in a regexp. The use of wildcards with |
394 | | // quantifiers that don't have a reasonably small upper bound causes a |
395 | | // performance penalty. This function detects such cases in order to warn the |
396 | | // user about this. |
397 | | // |
398 | | int yr_re_ast_has_unbounded_quantifier_for_dot(RE_AST* re_ast) |
399 | 0 | { |
400 | 0 | return _yr_re_node_has_unbounded_quantifier_for_dot(re_ast->root_node); |
401 | 0 | } |
402 | | |
403 | | //////////////////////////////////////////////////////////////////////////////// |
404 | | // In some cases splitting a regular expression (or hex string) in two parts is |
405 | | // convenient for increasing performance. This happens when the pattern contains |
406 | | // a large gap (a.k.a jump), for example: { 01 02 03 [0-999] 04 05 06 } |
407 | | // In this case the string is splitted in { 01 02 03 } and { 04 05 06 } where |
408 | | // the latter is chained to the former. This means that { 01 02 03 } and |
409 | | // { 04 05 06 } are handled as individual strings, and when both of them are |
410 | | // found, YARA verifies if the distance between the matches complies with the |
411 | | // [0-999] restriction. |
412 | | // |
413 | | // This function traverses a regexp's AST looking for nodes where it should be |
414 | | // splitted. It must be noticed that this only applies to two-level ASTs (i.e. |
415 | | // an AST consisting in a RE_NODE_CONCAT at the root where all the children are |
416 | | // leaves). |
417 | | // |
418 | | // For example, { 01 02 03 [0-1000] 04 05 06 [500-2000] 07 08 09 } has the |
419 | | // following AST: |
420 | | // |
421 | | // RE_NODE_CONCAT |
422 | | // | |
423 | | // |- RE_NODE_LITERAL (01) |
424 | | // |- RE_NODE_LITERAL (02) |
425 | | // |- RE_NODE_LITERAL (03) |
426 | | // |- RE_NODE_RANGE_ANY (start=0, end=1000) |
427 | | // |- RE_NODE_LITERAL (04) |
428 | | // |- RE_NODE_LITERAL (05) |
429 | | // |- RE_NODE_LITERAL (06) |
430 | | // |- RE_NODE_RANGE_ANY (start=500, end=2000) |
431 | | // |- RE_NODE_LITERAL (07) |
432 | | // |- RE_NODE_LITERAL (08) |
433 | | // |- RE_NODE_LITERAL (09) |
434 | | // |
435 | | // If the AST above is passed in the re_ast argument, it will be trimmed to: |
436 | | // |
437 | | // RE_NODE_CONCAT |
438 | | // | |
439 | | // |- RE_NODE_LITERAL (01) |
440 | | // |- RE_NODE_LITERAL (02) |
441 | | // |- RE_NODE_LITERAL (03) |
442 | | // |
443 | | // While remainder_re_ast will be: |
444 | | // |
445 | | // RE_NODE_CONCAT |
446 | | // | |
447 | | // |- RE_NODE_LITERAL (04) |
448 | | // |- RE_NODE_LITERAL (05) |
449 | | // |- RE_NODE_LITERAL (06) |
450 | | // |- RE_NODE_RANGE_ANY (start=500, end=2000) |
451 | | // |- RE_NODE_LITERAL (07) |
452 | | // |- RE_NODE_LITERAL (08) |
453 | | // |- RE_NODE_LITERAL (09) |
454 | | // |
455 | | // The caller is responsible for freeing the new AST in remainder_re_ast by |
456 | | // calling yr_re_ast_destroy. |
457 | | // |
458 | | // The integers pointed to by min_gap and max_gap will be filled with the |
459 | | // minimum and maximum gap size between the sub-strings represented by the |
460 | | // two ASTs. |
461 | | // |
462 | | int yr_re_ast_split_at_chaining_point( |
463 | | RE_AST* re_ast, |
464 | | RE_AST** remainder_re_ast, |
465 | | int32_t* min_gap, |
466 | | int32_t* max_gap) |
467 | 0 | { |
468 | 0 | RE_NODE* child; |
469 | 0 | RE_NODE* concat; |
470 | |
|
471 | 0 | int result; |
472 | |
|
473 | 0 | *remainder_re_ast = NULL; |
474 | 0 | *min_gap = 0; |
475 | 0 | *max_gap = 0; |
476 | |
|
477 | 0 | if (re_ast->root_node->type != RE_NODE_CONCAT) |
478 | 0 | return ERROR_SUCCESS; |
479 | | |
480 | 0 | child = re_ast->root_node->children_head; |
481 | |
|
482 | 0 | while (child != NULL) |
483 | 0 | { |
484 | 0 | if (!child->greedy && child->type == RE_NODE_RANGE_ANY && |
485 | 0 | child->prev_sibling != NULL && child->next_sibling != NULL && |
486 | 0 | (child->start > YR_STRING_CHAINING_THRESHOLD || |
487 | 0 | child->end > YR_STRING_CHAINING_THRESHOLD)) |
488 | 0 | { |
489 | 0 | result = yr_re_ast_create(remainder_re_ast); |
490 | |
|
491 | 0 | if (result != ERROR_SUCCESS) |
492 | 0 | return result; |
493 | | |
494 | 0 | concat = yr_re_node_create(RE_NODE_CONCAT); |
495 | |
|
496 | 0 | if (concat == NULL) |
497 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
498 | | |
499 | 0 | concat->children_head = child->next_sibling; |
500 | 0 | concat->children_tail = re_ast->root_node->children_tail; |
501 | |
|
502 | 0 | re_ast->root_node->children_tail = child->prev_sibling; |
503 | |
|
504 | 0 | child->prev_sibling->next_sibling = NULL; |
505 | 0 | child->next_sibling->prev_sibling = NULL; |
506 | |
|
507 | 0 | *min_gap = child->start; |
508 | 0 | *max_gap = child->end; |
509 | |
|
510 | 0 | (*remainder_re_ast)->root_node = concat; |
511 | 0 | (*remainder_re_ast)->flags = re_ast->flags; |
512 | |
|
513 | 0 | yr_re_node_destroy(child); |
514 | |
|
515 | 0 | return ERROR_SUCCESS; |
516 | 0 | } |
517 | | |
518 | 0 | child = child->next_sibling; |
519 | 0 | } |
520 | | |
521 | 0 | return ERROR_SUCCESS; |
522 | 0 | } |
523 | | |
524 | | int _yr_emit_inst( |
525 | | RE_EMIT_CONTEXT* emit_context, |
526 | | uint8_t opcode, |
527 | | YR_ARENA_REF* instruction_ref) |
528 | 0 | { |
529 | 0 | FAIL_ON_ERROR(yr_arena_write_data( |
530 | 0 | emit_context->arena, |
531 | 0 | YR_RE_CODE_SECTION, |
532 | 0 | &opcode, |
533 | 0 | sizeof(uint8_t), |
534 | 0 | instruction_ref)); |
535 | |
|
536 | 0 | return ERROR_SUCCESS; |
537 | 0 | } |
538 | | |
539 | | int _yr_emit_inst_arg_uint8( |
540 | | RE_EMIT_CONTEXT* emit_context, |
541 | | uint8_t opcode, |
542 | | uint8_t argument, |
543 | | YR_ARENA_REF* instruction_ref, |
544 | | YR_ARENA_REF* argument_ref) |
545 | 0 | { |
546 | 0 | FAIL_ON_ERROR(yr_arena_write_data( |
547 | 0 | emit_context->arena, |
548 | 0 | YR_RE_CODE_SECTION, |
549 | 0 | &opcode, |
550 | 0 | sizeof(uint8_t), |
551 | 0 | instruction_ref)); |
552 | |
|
553 | 0 | FAIL_ON_ERROR(yr_arena_write_data( |
554 | 0 | emit_context->arena, |
555 | 0 | YR_RE_CODE_SECTION, |
556 | 0 | &argument, |
557 | 0 | sizeof(uint8_t), |
558 | 0 | argument_ref)); |
559 | |
|
560 | 0 | return ERROR_SUCCESS; |
561 | 0 | } |
562 | | |
563 | | int _yr_emit_inst_arg_uint16( |
564 | | RE_EMIT_CONTEXT* emit_context, |
565 | | uint8_t opcode, |
566 | | uint16_t argument, |
567 | | YR_ARENA_REF* instruction_ref, |
568 | | YR_ARENA_REF* argument_ref) |
569 | 0 | { |
570 | 0 | FAIL_ON_ERROR(yr_arena_write_data( |
571 | 0 | emit_context->arena, |
572 | 0 | YR_RE_CODE_SECTION, |
573 | 0 | &opcode, |
574 | 0 | sizeof(uint8_t), |
575 | 0 | instruction_ref)); |
576 | |
|
577 | 0 | FAIL_ON_ERROR(yr_arena_write_data( |
578 | 0 | emit_context->arena, |
579 | 0 | YR_RE_CODE_SECTION, |
580 | 0 | &argument, |
581 | 0 | sizeof(uint16_t), |
582 | 0 | argument_ref)); |
583 | |
|
584 | 0 | return ERROR_SUCCESS; |
585 | 0 | } |
586 | | |
587 | | int _yr_emit_inst_arg_uint32( |
588 | | RE_EMIT_CONTEXT* emit_context, |
589 | | uint8_t opcode, |
590 | | uint32_t argument, |
591 | | YR_ARENA_REF* instruction_ref, |
592 | | YR_ARENA_REF* argument_ref) |
593 | 0 | { |
594 | 0 | FAIL_ON_ERROR(yr_arena_write_data( |
595 | 0 | emit_context->arena, |
596 | 0 | YR_RE_CODE_SECTION, |
597 | 0 | &opcode, |
598 | 0 | sizeof(uint8_t), |
599 | 0 | instruction_ref)); |
600 | |
|
601 | 0 | FAIL_ON_ERROR(yr_arena_write_data( |
602 | 0 | emit_context->arena, |
603 | 0 | YR_RE_CODE_SECTION, |
604 | 0 | &argument, |
605 | 0 | sizeof(uint32_t), |
606 | 0 | argument_ref)); |
607 | |
|
608 | 0 | return ERROR_SUCCESS; |
609 | 0 | } |
610 | | |
611 | | int _yr_emit_inst_arg_int16( |
612 | | RE_EMIT_CONTEXT* emit_context, |
613 | | uint8_t opcode, |
614 | | int16_t argument, |
615 | | YR_ARENA_REF* instruction_ref, |
616 | | YR_ARENA_REF* argument_ref) |
617 | 0 | { |
618 | 0 | FAIL_ON_ERROR(yr_arena_write_data( |
619 | 0 | emit_context->arena, |
620 | 0 | YR_RE_CODE_SECTION, |
621 | 0 | &opcode, |
622 | 0 | sizeof(uint8_t), |
623 | 0 | instruction_ref)); |
624 | |
|
625 | 0 | FAIL_ON_ERROR(yr_arena_write_data( |
626 | 0 | emit_context->arena, |
627 | 0 | YR_RE_CODE_SECTION, |
628 | 0 | &argument, |
629 | 0 | sizeof(int16_t), |
630 | 0 | argument_ref)); |
631 | |
|
632 | 0 | return ERROR_SUCCESS; |
633 | 0 | } |
634 | | |
635 | | int _yr_emit_inst_arg_struct( |
636 | | RE_EMIT_CONTEXT* emit_context, |
637 | | uint8_t opcode, |
638 | | void* structure, |
639 | | size_t structure_size, |
640 | | YR_ARENA_REF* instruction_ref, |
641 | | YR_ARENA_REF* argument_ref) |
642 | 0 | { |
643 | 0 | FAIL_ON_ERROR(yr_arena_write_data( |
644 | 0 | emit_context->arena, |
645 | 0 | YR_RE_CODE_SECTION, |
646 | 0 | &opcode, |
647 | 0 | sizeof(uint8_t), |
648 | 0 | instruction_ref)); |
649 | |
|
650 | 0 | FAIL_ON_ERROR(yr_arena_write_data( |
651 | 0 | emit_context->arena, |
652 | 0 | YR_RE_CODE_SECTION, |
653 | 0 | structure, |
654 | 0 | structure_size, |
655 | 0 | argument_ref)); |
656 | |
|
657 | 0 | return ERROR_SUCCESS; |
658 | 0 | } |
659 | | |
660 | | int _yr_emit_split( |
661 | | RE_EMIT_CONTEXT* emit_context, |
662 | | uint8_t opcode, |
663 | | int16_t argument, |
664 | | YR_ARENA_REF* instruction_ref, |
665 | | YR_ARENA_REF* argument_ref) |
666 | 0 | { |
667 | 0 | assert(opcode == RE_OPCODE_SPLIT_A || opcode == RE_OPCODE_SPLIT_B); |
668 | |
|
669 | 0 | if (emit_context->next_split_id == RE_MAX_SPLIT_ID) |
670 | 0 | return ERROR_REGULAR_EXPRESSION_TOO_COMPLEX; |
671 | | |
672 | 0 | FAIL_ON_ERROR(yr_arena_write_data( |
673 | 0 | emit_context->arena, |
674 | 0 | YR_RE_CODE_SECTION, |
675 | 0 | &opcode, |
676 | 0 | sizeof(uint8_t), |
677 | 0 | instruction_ref)); |
678 | |
|
679 | 0 | FAIL_ON_ERROR(yr_arena_write_data( |
680 | 0 | emit_context->arena, |
681 | 0 | YR_RE_CODE_SECTION, |
682 | 0 | &emit_context->next_split_id, |
683 | 0 | sizeof(RE_SPLIT_ID_TYPE), |
684 | 0 | NULL)); |
685 | |
|
686 | 0 | emit_context->next_split_id++; |
687 | |
|
688 | 0 | FAIL_ON_ERROR(yr_arena_write_data( |
689 | 0 | emit_context->arena, |
690 | 0 | YR_RE_CODE_SECTION, |
691 | 0 | &argument, |
692 | 0 | sizeof(int16_t), |
693 | 0 | argument_ref)); |
694 | |
|
695 | 0 | return ERROR_SUCCESS; |
696 | 0 | } |
697 | | |
698 | | static int _yr_re_emit( |
699 | | RE_EMIT_CONTEXT* emit_context, |
700 | | RE_NODE* re_node, |
701 | | int flags, |
702 | | YR_ARENA_REF* code_ref) |
703 | 0 | { |
704 | 0 | int16_t jmp_offset; |
705 | |
|
706 | 0 | yr_arena_off_t bookmark_1 = 0; |
707 | 0 | yr_arena_off_t bookmark_2 = 0; |
708 | 0 | yr_arena_off_t bookmark_3 = 0; |
709 | 0 | yr_arena_off_t bookmark_4 = 0; |
710 | |
|
711 | 0 | bool emit_split; |
712 | 0 | bool emit_repeat; |
713 | 0 | bool emit_prolog; |
714 | 0 | bool emit_epilog; |
715 | |
|
716 | 0 | RE_REPEAT_ARGS repeat_args; |
717 | 0 | RE_REPEAT_ARGS* repeat_start_args_addr; |
718 | 0 | RE_REPEAT_ANY_ARGS repeat_any_args; |
719 | |
|
720 | 0 | RE_NODE* child; |
721 | |
|
722 | 0 | void* split_offset_addr = NULL; |
723 | 0 | void* jmp_offset_addr = NULL; |
724 | |
|
725 | 0 | YR_ARENA_REF instruction_ref = YR_ARENA_NULL_REF; |
726 | 0 | YR_ARENA_REF split_offset_ref; |
727 | 0 | YR_ARENA_REF jmp_instruction_ref; |
728 | 0 | YR_ARENA_REF jmp_offset_ref; |
729 | 0 | YR_ARENA_REF repeat_start_args_ref; |
730 | |
|
731 | 0 | switch (re_node->type) |
732 | 0 | { |
733 | 0 | case RE_NODE_LITERAL: |
734 | 0 | FAIL_ON_ERROR(_yr_emit_inst_arg_uint8( |
735 | 0 | emit_context, |
736 | 0 | RE_OPCODE_LITERAL, |
737 | 0 | re_node->value, |
738 | 0 | &instruction_ref, |
739 | 0 | NULL)); |
740 | 0 | break; |
741 | | |
742 | 0 | case RE_NODE_NOT_LITERAL: |
743 | 0 | FAIL_ON_ERROR(_yr_emit_inst_arg_uint8( |
744 | 0 | emit_context, |
745 | 0 | RE_OPCODE_NOT_LITERAL, |
746 | 0 | re_node->value, |
747 | 0 | &instruction_ref, |
748 | 0 | NULL)); |
749 | 0 | break; |
750 | | |
751 | 0 | case RE_NODE_MASKED_LITERAL: |
752 | 0 | FAIL_ON_ERROR(_yr_emit_inst_arg_uint16( |
753 | 0 | emit_context, |
754 | 0 | RE_OPCODE_MASKED_LITERAL, |
755 | 0 | re_node->mask << 8 | re_node->value, |
756 | 0 | &instruction_ref, |
757 | 0 | NULL)); |
758 | 0 | break; |
759 | | |
760 | 0 | case RE_NODE_MASKED_NOT_LITERAL: |
761 | 0 | FAIL_ON_ERROR(_yr_emit_inst_arg_uint16( |
762 | 0 | emit_context, |
763 | 0 | RE_OPCODE_MASKED_NOT_LITERAL, |
764 | 0 | re_node->mask << 8 | re_node->value, |
765 | 0 | &instruction_ref, |
766 | 0 | NULL)); |
767 | 0 | break; |
768 | | |
769 | 0 | case RE_NODE_WORD_CHAR: |
770 | 0 | FAIL_ON_ERROR( |
771 | 0 | _yr_emit_inst(emit_context, RE_OPCODE_WORD_CHAR, &instruction_ref)); |
772 | 0 | break; |
773 | | |
774 | 0 | case RE_NODE_NON_WORD_CHAR: |
775 | 0 | FAIL_ON_ERROR( |
776 | 0 | _yr_emit_inst(emit_context, RE_OPCODE_NON_WORD_CHAR, &instruction_ref)); |
777 | 0 | break; |
778 | | |
779 | 0 | case RE_NODE_WORD_BOUNDARY: |
780 | 0 | FAIL_ON_ERROR( |
781 | 0 | _yr_emit_inst(emit_context, RE_OPCODE_WORD_BOUNDARY, &instruction_ref)); |
782 | 0 | break; |
783 | | |
784 | 0 | case RE_NODE_NON_WORD_BOUNDARY: |
785 | 0 | FAIL_ON_ERROR(_yr_emit_inst( |
786 | 0 | emit_context, RE_OPCODE_NON_WORD_BOUNDARY, &instruction_ref)); |
787 | 0 | break; |
788 | | |
789 | 0 | case RE_NODE_SPACE: |
790 | 0 | FAIL_ON_ERROR( |
791 | 0 | _yr_emit_inst(emit_context, RE_OPCODE_SPACE, &instruction_ref)); |
792 | 0 | break; |
793 | | |
794 | 0 | case RE_NODE_NON_SPACE: |
795 | 0 | FAIL_ON_ERROR( |
796 | 0 | _yr_emit_inst(emit_context, RE_OPCODE_NON_SPACE, &instruction_ref)); |
797 | 0 | break; |
798 | | |
799 | 0 | case RE_NODE_DIGIT: |
800 | 0 | FAIL_ON_ERROR( |
801 | 0 | _yr_emit_inst(emit_context, RE_OPCODE_DIGIT, &instruction_ref)); |
802 | 0 | break; |
803 | | |
804 | 0 | case RE_NODE_NON_DIGIT: |
805 | 0 | FAIL_ON_ERROR( |
806 | 0 | _yr_emit_inst(emit_context, RE_OPCODE_NON_DIGIT, &instruction_ref)); |
807 | 0 | break; |
808 | | |
809 | 0 | case RE_NODE_ANY: |
810 | 0 | FAIL_ON_ERROR(_yr_emit_inst(emit_context, RE_OPCODE_ANY, &instruction_ref)); |
811 | 0 | break; |
812 | | |
813 | 0 | case RE_NODE_CLASS: |
814 | 0 | FAIL_ON_ERROR( |
815 | 0 | _yr_emit_inst(emit_context, RE_OPCODE_CLASS, &instruction_ref)); |
816 | |
|
817 | 0 | FAIL_ON_ERROR(yr_arena_write_data( |
818 | 0 | emit_context->arena, |
819 | 0 | YR_RE_CODE_SECTION, |
820 | 0 | re_node->re_class, |
821 | 0 | sizeof(*re_node->re_class), |
822 | 0 | NULL)); |
823 | 0 | break; |
824 | | |
825 | 0 | case RE_NODE_ANCHOR_START: |
826 | 0 | FAIL_ON_ERROR(_yr_emit_inst( |
827 | 0 | emit_context, RE_OPCODE_MATCH_AT_START, &instruction_ref)); |
828 | 0 | break; |
829 | | |
830 | 0 | case RE_NODE_ANCHOR_END: |
831 | 0 | FAIL_ON_ERROR( |
832 | 0 | _yr_emit_inst(emit_context, RE_OPCODE_MATCH_AT_END, &instruction_ref)); |
833 | 0 | break; |
834 | | |
835 | 0 | case RE_NODE_CONCAT: |
836 | 0 | FAIL_ON_ERROR(_yr_re_emit( |
837 | 0 | emit_context, |
838 | 0 | (flags & EMIT_BACKWARDS) ? re_node->children_tail |
839 | 0 | : re_node->children_head, |
840 | 0 | flags, |
841 | 0 | &instruction_ref)); |
842 | |
|
843 | 0 | if (flags & EMIT_BACKWARDS) |
844 | 0 | child = re_node->children_tail->prev_sibling; |
845 | 0 | else |
846 | 0 | child = re_node->children_head->next_sibling; |
847 | |
|
848 | 0 | while (child != NULL) |
849 | 0 | { |
850 | 0 | FAIL_ON_ERROR(_yr_re_emit(emit_context, child, flags, NULL)); |
851 | |
|
852 | 0 | child = (flags & EMIT_BACKWARDS) ? child->prev_sibling |
853 | 0 | : child->next_sibling; |
854 | 0 | } |
855 | 0 | break; |
856 | | |
857 | 0 | case RE_NODE_PLUS: |
858 | | // Code for e+ looks like: |
859 | | // |
860 | | // L1: code for e |
861 | | // split L1, L2 |
862 | | // L2: |
863 | | // |
864 | 0 | FAIL_ON_ERROR(_yr_re_emit( |
865 | 0 | emit_context, re_node->children_head, flags, &instruction_ref)); |
866 | |
|
867 | 0 | bookmark_1 = yr_arena_get_current_offset( |
868 | 0 | emit_context->arena, YR_RE_CODE_SECTION); |
869 | |
|
870 | 0 | if (instruction_ref.offset - bookmark_1 < INT16_MIN) |
871 | 0 | return ERROR_REGULAR_EXPRESSION_TOO_LARGE; |
872 | | |
873 | 0 | jmp_offset = (int16_t) (instruction_ref.offset - bookmark_1); |
874 | |
|
875 | 0 | FAIL_ON_ERROR(_yr_emit_split( |
876 | 0 | emit_context, |
877 | 0 | re_node->greedy ? RE_OPCODE_SPLIT_B : RE_OPCODE_SPLIT_A, |
878 | 0 | jmp_offset, |
879 | 0 | NULL, |
880 | 0 | NULL)); |
881 | |
|
882 | 0 | break; |
883 | | |
884 | 0 | case RE_NODE_STAR: |
885 | | // Code for e* looks like: |
886 | | // |
887 | | // L1: split L1, L2 |
888 | | // code for e |
889 | | // jmp L1 |
890 | | // L2: |
891 | 0 | FAIL_ON_ERROR(_yr_emit_split( |
892 | 0 | emit_context, |
893 | 0 | re_node->greedy ? RE_OPCODE_SPLIT_A : RE_OPCODE_SPLIT_B, |
894 | 0 | 0, |
895 | 0 | &instruction_ref, |
896 | 0 | &split_offset_ref)); |
897 | |
|
898 | 0 | FAIL_ON_ERROR( |
899 | 0 | _yr_re_emit(emit_context, re_node->children_head, flags, NULL)); |
900 | |
|
901 | 0 | bookmark_1 = yr_arena_get_current_offset( |
902 | 0 | emit_context->arena, YR_RE_CODE_SECTION); |
903 | |
|
904 | 0 | if (instruction_ref.offset - bookmark_1 < INT16_MIN) |
905 | 0 | return ERROR_REGULAR_EXPRESSION_TOO_LARGE; |
906 | | |
907 | 0 | jmp_offset = (int16_t) (instruction_ref.offset - bookmark_1); |
908 | | |
909 | | // Emit jump with offset set to 0. |
910 | |
|
911 | 0 | FAIL_ON_ERROR(_yr_emit_inst_arg_int16( |
912 | 0 | emit_context, RE_OPCODE_JUMP, jmp_offset, NULL, NULL)); |
913 | |
|
914 | 0 | bookmark_1 = yr_arena_get_current_offset( |
915 | 0 | emit_context->arena, YR_RE_CODE_SECTION); |
916 | |
|
917 | 0 | if (bookmark_1 - instruction_ref.offset > INT16_MAX) |
918 | 0 | return ERROR_REGULAR_EXPRESSION_TOO_LARGE; |
919 | | |
920 | 0 | jmp_offset = (int16_t) (bookmark_1 - instruction_ref.offset); |
921 | | |
922 | | // Update split offset. |
923 | 0 | split_offset_addr = |
924 | 0 | yr_arena_ref_to_ptr(emit_context->arena, &split_offset_ref); |
925 | |
|
926 | 0 | memcpy(split_offset_addr, &jmp_offset, sizeof(jmp_offset)); |
927 | 0 | break; |
928 | | |
929 | 0 | case RE_NODE_ALT: |
930 | | // Code for e1|e2 looks like: |
931 | | // |
932 | | // split L1, L2 |
933 | | // L1: code for e1 |
934 | | // jmp L3 |
935 | | // L2: code for e2 |
936 | | // L3: |
937 | | |
938 | | // Emit a split instruction with offset set to 0 temporarily. Offset |
939 | | // will be updated after we know the size of the code generated for |
940 | | // the left node (e1). |
941 | |
|
942 | 0 | FAIL_ON_ERROR(_yr_emit_split( |
943 | 0 | emit_context, |
944 | 0 | RE_OPCODE_SPLIT_A, |
945 | 0 | 0, |
946 | 0 | &instruction_ref, |
947 | 0 | &split_offset_ref)); |
948 | |
|
949 | 0 | FAIL_ON_ERROR( |
950 | 0 | _yr_re_emit(emit_context, re_node->children_head, flags, NULL)); |
951 | | |
952 | | // Emit jump with offset set to 0. |
953 | |
|
954 | 0 | FAIL_ON_ERROR(_yr_emit_inst_arg_int16( |
955 | 0 | emit_context, |
956 | 0 | RE_OPCODE_JUMP, |
957 | 0 | 0, |
958 | 0 | &jmp_instruction_ref, |
959 | 0 | &jmp_offset_ref)); |
960 | |
|
961 | 0 | bookmark_1 = yr_arena_get_current_offset( |
962 | 0 | emit_context->arena, YR_RE_CODE_SECTION); |
963 | |
|
964 | 0 | if (bookmark_1 - instruction_ref.offset > INT16_MAX) |
965 | 0 | return ERROR_REGULAR_EXPRESSION_TOO_LARGE; |
966 | | |
967 | 0 | jmp_offset = (int16_t) (bookmark_1 - instruction_ref.offset); |
968 | | |
969 | | // Update split offset. |
970 | 0 | split_offset_addr = |
971 | 0 | yr_arena_ref_to_ptr(emit_context->arena, &split_offset_ref); |
972 | |
|
973 | 0 | memcpy(split_offset_addr, &jmp_offset, sizeof(jmp_offset)); |
974 | |
|
975 | 0 | FAIL_ON_ERROR( |
976 | 0 | _yr_re_emit(emit_context, re_node->children_tail, flags, NULL)); |
977 | |
|
978 | 0 | bookmark_1 = yr_arena_get_current_offset( |
979 | 0 | emit_context->arena, YR_RE_CODE_SECTION); |
980 | |
|
981 | 0 | if (bookmark_1 - jmp_instruction_ref.offset > INT16_MAX) |
982 | 0 | return ERROR_REGULAR_EXPRESSION_TOO_LARGE; |
983 | | |
984 | 0 | jmp_offset = (int16_t) (bookmark_1 - jmp_instruction_ref.offset); |
985 | | |
986 | | // Update offset for jmp instruction. |
987 | 0 | jmp_offset_addr = yr_arena_ref_to_ptr(emit_context->arena, &jmp_offset_ref); |
988 | |
|
989 | 0 | memcpy(jmp_offset_addr, &jmp_offset, sizeof(jmp_offset)); |
990 | 0 | break; |
991 | | |
992 | 0 | case RE_NODE_RANGE_ANY: |
993 | 0 | repeat_any_args.min = re_node->start; |
994 | 0 | repeat_any_args.max = re_node->end; |
995 | |
|
996 | 0 | FAIL_ON_ERROR(_yr_emit_inst_arg_struct( |
997 | 0 | emit_context, |
998 | 0 | re_node->greedy ? RE_OPCODE_REPEAT_ANY_GREEDY |
999 | 0 | : RE_OPCODE_REPEAT_ANY_UNGREEDY, |
1000 | 0 | &repeat_any_args, |
1001 | 0 | sizeof(repeat_any_args), |
1002 | 0 | &instruction_ref, |
1003 | 0 | NULL)); |
1004 | |
|
1005 | 0 | break; |
1006 | | |
1007 | 0 | case RE_NODE_RANGE: |
1008 | | // Code for e{n,m} looks like: |
1009 | | // |
1010 | | // code for e --- prolog |
1011 | | // repeat_start n, m, L1 --+ |
1012 | | // L0: code for e | repeat |
1013 | | // repeat_end n, m, L0 --+ |
1014 | | // L1: split L2, L3 --- split |
1015 | | // L2: code for e --- epilog |
1016 | | // L3: |
1017 | | // |
1018 | | // Not all sections (prolog, repeat, split and epilog) are generated in all |
1019 | | // cases, it depends on the values of n and m. The following table shows |
1020 | | // which sections are generated for the first few values of n and m. |
1021 | | // |
1022 | | // n,m prolog repeat split epilog |
1023 | | // (min,max) |
1024 | | // --------------------------------------- |
1025 | | // 0,0 - - - - |
1026 | | // 0,1 - - X X |
1027 | | // 0,2 - 0,1 X X |
1028 | | // 0,3 - 0,2 X X |
1029 | | // 0,M - 0,M-1 X X |
1030 | | // |
1031 | | // 1,1 X - - - |
1032 | | // 1,2 X - X X |
1033 | | // 1,3 X 0,1 X X |
1034 | | // 1,4 X 1,2 X X |
1035 | | // 1,M X 1,M-2 X X |
1036 | | // |
1037 | | // 2,2 X - - X |
1038 | | // 2,3 X 1,1 X X |
1039 | | // 2,4 X 1,2 X X |
1040 | | // 2,M X 1,M-2 X X |
1041 | | // |
1042 | | // 3,3 X 1,1 - X |
1043 | | // 3,4 X 2,2 X X |
1044 | | // 3,M X 2,M-2 X X |
1045 | | // |
1046 | | // 4,4 X 2,2 - X |
1047 | | // 4,5 X 3,3 X X |
1048 | | // 4,M X 3,M-2 X X |
1049 | | // |
1050 | | // The code can't consists simply in the repeat section, the prolog and |
1051 | | // epilog are required because we can't have atoms pointing to code inside |
1052 | | // the repeat loop. Atoms' forwards_code will point to code in the prolog |
1053 | | // and backwards_code will point to code in the epilog (or in prolog if |
1054 | | // epilog wasn't generated, like in n=1,m=1) |
1055 | |
|
1056 | 0 | emit_prolog = re_node->start > 0; |
1057 | 0 | emit_repeat = re_node->end > re_node->start + 1 || re_node->end > 2; |
1058 | 0 | emit_split = re_node->end > re_node->start; |
1059 | 0 | emit_epilog = re_node->end > re_node->start || re_node->end > 1; |
1060 | |
|
1061 | 0 | if (emit_prolog) |
1062 | 0 | { |
1063 | 0 | FAIL_ON_ERROR(_yr_re_emit( |
1064 | 0 | emit_context, re_node->children_head, flags, &instruction_ref)); |
1065 | 0 | } |
1066 | | |
1067 | 0 | if (emit_repeat) |
1068 | 0 | { |
1069 | 0 | repeat_args.min = re_node->start; |
1070 | 0 | repeat_args.max = re_node->end; |
1071 | |
|
1072 | 0 | if (emit_prolog) |
1073 | 0 | { |
1074 | 0 | repeat_args.max--; |
1075 | 0 | repeat_args.min--; |
1076 | 0 | } |
1077 | |
|
1078 | 0 | if (emit_split) |
1079 | 0 | { |
1080 | 0 | repeat_args.max--; |
1081 | 0 | } |
1082 | 0 | else |
1083 | 0 | { |
1084 | 0 | repeat_args.min--; |
1085 | 0 | repeat_args.max--; |
1086 | 0 | } |
1087 | |
|
1088 | 0 | repeat_args.offset = 0; |
1089 | |
|
1090 | 0 | bookmark_1 = yr_arena_get_current_offset( |
1091 | 0 | emit_context->arena, YR_RE_CODE_SECTION); |
1092 | |
|
1093 | 0 | FAIL_ON_ERROR(_yr_emit_inst_arg_struct( |
1094 | 0 | emit_context, |
1095 | 0 | re_node->greedy ? RE_OPCODE_REPEAT_START_GREEDY |
1096 | 0 | : RE_OPCODE_REPEAT_START_UNGREEDY, |
1097 | 0 | &repeat_args, |
1098 | 0 | sizeof(repeat_args), |
1099 | 0 | emit_prolog ? NULL : &instruction_ref, |
1100 | 0 | &repeat_start_args_ref)); |
1101 | |
|
1102 | 0 | bookmark_2 = yr_arena_get_current_offset( |
1103 | 0 | emit_context->arena, YR_RE_CODE_SECTION); |
1104 | |
|
1105 | 0 | FAIL_ON_ERROR(_yr_re_emit( |
1106 | 0 | emit_context, |
1107 | 0 | re_node->children_head, |
1108 | 0 | flags | EMIT_DONT_SET_FORWARDS_CODE | EMIT_DONT_SET_BACKWARDS_CODE, |
1109 | 0 | NULL)); |
1110 | |
|
1111 | 0 | bookmark_3 = yr_arena_get_current_offset( |
1112 | 0 | emit_context->arena, YR_RE_CODE_SECTION); |
1113 | |
|
1114 | 0 | if (bookmark_2 - bookmark_3 < INT32_MIN) |
1115 | 0 | return ERROR_REGULAR_EXPRESSION_TOO_LARGE; |
1116 | | |
1117 | 0 | repeat_args.offset = (int32_t) (bookmark_2 - bookmark_3); |
1118 | |
|
1119 | 0 | FAIL_ON_ERROR(_yr_emit_inst_arg_struct( |
1120 | 0 | emit_context, |
1121 | 0 | re_node->greedy ? RE_OPCODE_REPEAT_END_GREEDY |
1122 | 0 | : RE_OPCODE_REPEAT_END_UNGREEDY, |
1123 | 0 | &repeat_args, |
1124 | 0 | sizeof(repeat_args), |
1125 | 0 | NULL, |
1126 | 0 | NULL)); |
1127 | |
|
1128 | 0 | bookmark_4 = yr_arena_get_current_offset( |
1129 | 0 | emit_context->arena, YR_RE_CODE_SECTION); |
1130 | |
|
1131 | 0 | repeat_start_args_addr = (RE_REPEAT_ARGS*) yr_arena_ref_to_ptr( |
1132 | 0 | emit_context->arena, &repeat_start_args_ref); |
1133 | |
|
1134 | 0 | if (bookmark_4 - bookmark_1 > INT32_MAX) |
1135 | 0 | return ERROR_REGULAR_EXPRESSION_TOO_LARGE; |
1136 | | |
1137 | 0 | repeat_start_args_addr->offset = (int32_t) (bookmark_4 - bookmark_1); |
1138 | 0 | } |
1139 | | |
1140 | 0 | if (emit_split) |
1141 | 0 | { |
1142 | 0 | bookmark_1 = yr_arena_get_current_offset( |
1143 | 0 | emit_context->arena, YR_RE_CODE_SECTION); |
1144 | |
|
1145 | 0 | FAIL_ON_ERROR(_yr_emit_split( |
1146 | 0 | emit_context, |
1147 | 0 | re_node->greedy ? RE_OPCODE_SPLIT_A : RE_OPCODE_SPLIT_B, |
1148 | 0 | 0, |
1149 | 0 | NULL, |
1150 | 0 | &split_offset_ref)); |
1151 | 0 | } |
1152 | | |
1153 | 0 | if (emit_epilog) |
1154 | 0 | { |
1155 | 0 | FAIL_ON_ERROR(_yr_re_emit( |
1156 | 0 | emit_context, |
1157 | 0 | re_node->children_head, |
1158 | 0 | emit_prolog ? flags | EMIT_DONT_SET_FORWARDS_CODE : flags, |
1159 | 0 | emit_prolog || emit_repeat ? NULL : &instruction_ref)); |
1160 | 0 | } |
1161 | | |
1162 | 0 | if (emit_split) |
1163 | 0 | { |
1164 | 0 | bookmark_2 = yr_arena_get_current_offset( |
1165 | 0 | emit_context->arena, YR_RE_CODE_SECTION); |
1166 | |
|
1167 | 0 | if (bookmark_2 - bookmark_1 > INT16_MAX) |
1168 | 0 | return ERROR_REGULAR_EXPRESSION_TOO_LARGE; |
1169 | | |
1170 | 0 | split_offset_addr = |
1171 | 0 | yr_arena_ref_to_ptr(emit_context->arena, &split_offset_ref); |
1172 | |
|
1173 | 0 | jmp_offset = (int16_t) (bookmark_2 - bookmark_1); |
1174 | |
|
1175 | 0 | memcpy(split_offset_addr, &jmp_offset, sizeof(jmp_offset)); |
1176 | 0 | } |
1177 | | |
1178 | 0 | break; |
1179 | 0 | } |
1180 | | |
1181 | 0 | if (flags & EMIT_BACKWARDS) |
1182 | 0 | { |
1183 | 0 | if (!(flags & EMIT_DONT_SET_BACKWARDS_CODE)) |
1184 | 0 | { |
1185 | 0 | re_node->backward_code_ref.buffer_id = YR_RE_CODE_SECTION; |
1186 | 0 | re_node->backward_code_ref.offset = yr_arena_get_current_offset( |
1187 | 0 | emit_context->arena, YR_RE_CODE_SECTION); |
1188 | 0 | } |
1189 | 0 | } |
1190 | 0 | else |
1191 | 0 | { |
1192 | 0 | if (!(flags & EMIT_DONT_SET_FORWARDS_CODE)) |
1193 | 0 | { |
1194 | 0 | re_node->forward_code_ref = instruction_ref; |
1195 | 0 | } |
1196 | 0 | } |
1197 | |
|
1198 | 0 | if (code_ref != NULL) |
1199 | 0 | *code_ref = instruction_ref; |
1200 | |
|
1201 | 0 | return ERROR_SUCCESS; |
1202 | 0 | } |
1203 | | |
1204 | | int yr_re_ast_emit_code(RE_AST* re_ast, YR_ARENA* arena, int backwards_code) |
1205 | 0 | { |
1206 | 0 | RE_EMIT_CONTEXT emit_context; |
1207 | | |
1208 | | // Emit code for matching the regular expressions forwards. |
1209 | 0 | emit_context.arena = arena; |
1210 | 0 | emit_context.next_split_id = 0; |
1211 | |
|
1212 | 0 | FAIL_ON_ERROR(_yr_re_emit( |
1213 | 0 | &emit_context, |
1214 | 0 | re_ast->root_node, |
1215 | 0 | backwards_code ? EMIT_BACKWARDS : 0, |
1216 | 0 | NULL)); |
1217 | |
|
1218 | 0 | FAIL_ON_ERROR(_yr_emit_inst(&emit_context, RE_OPCODE_MATCH, NULL)); |
1219 | |
|
1220 | 0 | return ERROR_SUCCESS; |
1221 | 0 | } |
1222 | | |
1223 | | static int _yr_re_fiber_create(RE_FIBER_POOL* fiber_pool, RE_FIBER** new_fiber) |
1224 | 0 | { |
1225 | 0 | RE_FIBER* fiber; |
1226 | |
|
1227 | 0 | if (fiber_pool->fibers.head != NULL) |
1228 | 0 | { |
1229 | 0 | fiber = fiber_pool->fibers.head; |
1230 | 0 | fiber_pool->fibers.head = fiber->next; |
1231 | |
|
1232 | 0 | if (fiber_pool->fibers.tail == fiber) |
1233 | 0 | fiber_pool->fibers.tail = NULL; |
1234 | 0 | } |
1235 | 0 | else |
1236 | 0 | { |
1237 | 0 | if (fiber_pool->fiber_count == RE_MAX_FIBERS) |
1238 | 0 | return ERROR_TOO_MANY_RE_FIBERS; |
1239 | | |
1240 | 0 | fiber = (RE_FIBER*) yr_malloc(sizeof(RE_FIBER)); |
1241 | |
|
1242 | 0 | if (fiber == NULL) |
1243 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
1244 | | |
1245 | 0 | fiber_pool->fiber_count++; |
1246 | 0 | } |
1247 | | |
1248 | 0 | fiber->ip = NULL; |
1249 | 0 | fiber->sp = -1; |
1250 | 0 | fiber->rc = -1; |
1251 | 0 | fiber->next = NULL; |
1252 | 0 | fiber->prev = NULL; |
1253 | |
|
1254 | 0 | *new_fiber = fiber; |
1255 | |
|
1256 | 0 | return ERROR_SUCCESS; |
1257 | 0 | } |
1258 | | |
1259 | | //////////////////////////////////////////////////////////////////////////////// |
1260 | | // Appends 'fiber' to 'fiber_list' |
1261 | | // |
1262 | | static void _yr_re_fiber_append(RE_FIBER_LIST* fiber_list, RE_FIBER* fiber) |
1263 | 0 | { |
1264 | 0 | assert(fiber->prev == NULL); |
1265 | 0 | assert(fiber->next == NULL); |
1266 | |
|
1267 | 0 | fiber->prev = fiber_list->tail; |
1268 | |
|
1269 | 0 | if (fiber_list->tail != NULL) |
1270 | 0 | fiber_list->tail->next = fiber; |
1271 | |
|
1272 | 0 | fiber_list->tail = fiber; |
1273 | |
|
1274 | 0 | if (fiber_list->head == NULL) |
1275 | 0 | fiber_list->head = fiber; |
1276 | |
|
1277 | 0 | assert(fiber_list->tail->next == NULL); |
1278 | 0 | assert(fiber_list->head->prev == NULL); |
1279 | 0 | } |
1280 | | |
1281 | | //////////////////////////////////////////////////////////////////////////////// |
1282 | | // Verifies if a fiber with the same properties (ip, rc, sp, and stack values) |
1283 | | // than 'target_fiber' exists in 'fiber_list'. The list is iterated from |
1284 | | // the start until 'last_fiber' (inclusive). Fibers past 'last_fiber' are not |
1285 | | // taken into account. |
1286 | | // |
1287 | | static int _yr_re_fiber_exists( |
1288 | | RE_FIBER_LIST* fiber_list, |
1289 | | RE_FIBER* target_fiber, |
1290 | | RE_FIBER* last_fiber) |
1291 | 0 | { |
1292 | 0 | RE_FIBER* fiber = fiber_list->head; |
1293 | |
|
1294 | 0 | int equal_stacks; |
1295 | 0 | int i; |
1296 | |
|
1297 | 0 | if (last_fiber == NULL) |
1298 | 0 | return false; |
1299 | | |
1300 | 0 | while (fiber != last_fiber->next) |
1301 | 0 | { |
1302 | 0 | if (fiber->ip == target_fiber->ip && fiber->sp == target_fiber->sp && |
1303 | 0 | fiber->rc == target_fiber->rc) |
1304 | 0 | { |
1305 | 0 | equal_stacks = true; |
1306 | |
|
1307 | 0 | for (i = 0; i <= fiber->sp; i++) |
1308 | 0 | { |
1309 | 0 | if (fiber->stack[i] != target_fiber->stack[i]) |
1310 | 0 | { |
1311 | 0 | equal_stacks = false; |
1312 | 0 | break; |
1313 | 0 | } |
1314 | 0 | } |
1315 | |
|
1316 | 0 | if (equal_stacks) |
1317 | 0 | return true; |
1318 | 0 | } |
1319 | | |
1320 | 0 | fiber = fiber->next; |
1321 | 0 | } |
1322 | | |
1323 | 0 | return false; |
1324 | 0 | } |
1325 | | |
1326 | | //////////////////////////////////////////////////////////////////////////////// |
1327 | | // Clones a fiber in fiber_list and inserts the cloned fiber just after. |
1328 | | // the original one. If fiber_list is: |
1329 | | // |
1330 | | // f1 -> f2 -> f3 -> f4 |
1331 | | // |
1332 | | // Splitting f2 will result in: |
1333 | | // |
1334 | | // f1 -> f2 -> cloned f2 -> f3 -> f4 |
1335 | | // |
1336 | | static int _yr_re_fiber_split( |
1337 | | RE_FIBER_LIST* fiber_list, |
1338 | | RE_FIBER_POOL* fiber_pool, |
1339 | | RE_FIBER* fiber, |
1340 | | RE_FIBER** new_fiber) |
1341 | 0 | { |
1342 | 0 | int32_t i; |
1343 | |
|
1344 | 0 | FAIL_ON_ERROR(_yr_re_fiber_create(fiber_pool, new_fiber)); |
1345 | |
|
1346 | 0 | (*new_fiber)->sp = fiber->sp; |
1347 | 0 | (*new_fiber)->ip = fiber->ip; |
1348 | 0 | (*new_fiber)->rc = fiber->rc; |
1349 | |
|
1350 | 0 | for (i = 0; i <= fiber->sp; i++) (*new_fiber)->stack[i] = fiber->stack[i]; |
1351 | |
|
1352 | 0 | (*new_fiber)->next = fiber->next; |
1353 | 0 | (*new_fiber)->prev = fiber; |
1354 | |
|
1355 | 0 | if (fiber->next != NULL) |
1356 | 0 | fiber->next->prev = *new_fiber; |
1357 | |
|
1358 | 0 | fiber->next = *new_fiber; |
1359 | |
|
1360 | 0 | if (fiber_list->tail == fiber) |
1361 | 0 | fiber_list->tail = *new_fiber; |
1362 | |
|
1363 | 0 | assert(fiber_list->tail->next == NULL); |
1364 | 0 | assert(fiber_list->head->prev == NULL); |
1365 | |
|
1366 | 0 | return ERROR_SUCCESS; |
1367 | 0 | } |
1368 | | |
1369 | | //////////////////////////////////////////////////////////////////////////////// |
1370 | | // Kills a given fiber by removing it from the fiber list and putting it in the |
1371 | | // fiber pool. |
1372 | | // |
1373 | | static RE_FIBER* _yr_re_fiber_kill( |
1374 | | RE_FIBER_LIST* fiber_list, |
1375 | | RE_FIBER_POOL* fiber_pool, |
1376 | | RE_FIBER* fiber) |
1377 | 0 | { |
1378 | 0 | RE_FIBER* next_fiber = fiber->next; |
1379 | |
|
1380 | 0 | if (fiber->prev != NULL) |
1381 | 0 | fiber->prev->next = next_fiber; |
1382 | |
|
1383 | 0 | if (next_fiber != NULL) |
1384 | 0 | next_fiber->prev = fiber->prev; |
1385 | |
|
1386 | 0 | if (fiber_pool->fibers.tail != NULL) |
1387 | 0 | fiber_pool->fibers.tail->next = fiber; |
1388 | |
|
1389 | 0 | if (fiber_list->tail == fiber) |
1390 | 0 | fiber_list->tail = fiber->prev; |
1391 | |
|
1392 | 0 | if (fiber_list->head == fiber) |
1393 | 0 | fiber_list->head = next_fiber; |
1394 | |
|
1395 | 0 | fiber->next = NULL; |
1396 | 0 | fiber->prev = fiber_pool->fibers.tail; |
1397 | 0 | fiber_pool->fibers.tail = fiber; |
1398 | |
|
1399 | 0 | if (fiber_pool->fibers.head == NULL) |
1400 | 0 | fiber_pool->fibers.head = fiber; |
1401 | |
|
1402 | 0 | return next_fiber; |
1403 | 0 | } |
1404 | | |
1405 | | //////////////////////////////////////////////////////////////////////////////// |
1406 | | // Kills all fibers from the given one up to the end of the fiber list. |
1407 | | // |
1408 | | static void _yr_re_fiber_kill_tail( |
1409 | | RE_FIBER_LIST* fiber_list, |
1410 | | RE_FIBER_POOL* fiber_pool, |
1411 | | RE_FIBER* fiber) |
1412 | 0 | { |
1413 | 0 | RE_FIBER* prev_fiber = fiber->prev; |
1414 | |
|
1415 | 0 | if (prev_fiber != NULL) |
1416 | 0 | prev_fiber->next = NULL; |
1417 | |
|
1418 | 0 | fiber->prev = fiber_pool->fibers.tail; |
1419 | |
|
1420 | 0 | if (fiber_pool->fibers.tail != NULL) |
1421 | 0 | fiber_pool->fibers.tail->next = fiber; |
1422 | |
|
1423 | 0 | fiber_pool->fibers.tail = fiber_list->tail; |
1424 | 0 | fiber_list->tail = prev_fiber; |
1425 | |
|
1426 | 0 | if (fiber_list->head == fiber) |
1427 | 0 | fiber_list->head = NULL; |
1428 | |
|
1429 | 0 | if (fiber_pool->fibers.head == NULL) |
1430 | 0 | fiber_pool->fibers.head = fiber; |
1431 | 0 | } |
1432 | | |
1433 | | //////////////////////////////////////////////////////////////////////////////// |
1434 | | // Kills all fibers in the fiber list. |
1435 | | // |
1436 | | static void _yr_re_fiber_kill_all( |
1437 | | RE_FIBER_LIST* fiber_list, |
1438 | | RE_FIBER_POOL* fiber_pool) |
1439 | 0 | { |
1440 | 0 | if (fiber_list->head != NULL) |
1441 | 0 | _yr_re_fiber_kill_tail(fiber_list, fiber_pool, fiber_list->head); |
1442 | 0 | } |
1443 | | |
1444 | | //////////////////////////////////////////////////////////////////////////////// |
1445 | | // Executes a fiber until reaching an "matching" instruction. A "matching" |
1446 | | // instruction is one that actually reads a byte from the input and performs |
1447 | | // some matching. If the fiber reaches a split instruction, the new fiber is |
1448 | | // also synced. |
1449 | | // |
1450 | | static int _yr_re_fiber_sync( |
1451 | | RE_FIBER_LIST* fiber_list, |
1452 | | RE_FIBER_POOL* fiber_pool, |
1453 | | RE_FIBER* fiber_to_sync) |
1454 | 0 | { |
1455 | | // A array for keeping track of which split instructions has been already |
1456 | | // executed. Each split instruction within a regexp has an associated ID |
1457 | | // between 0 and RE_MAX_SPLIT_ID-1. Keeping track of executed splits is |
1458 | | // required to avoid infinite loops in regexps like (a*)* or (a|)* |
1459 | |
|
1460 | 0 | RE_SPLIT_ID_TYPE splits_executed[RE_MAX_SPLIT_ID]; |
1461 | 0 | RE_SPLIT_ID_TYPE splits_executed_count = 0; |
1462 | 0 | RE_SPLIT_ID_TYPE split_id, splits_executed_idx; |
1463 | |
|
1464 | 0 | int split_already_executed; |
1465 | |
|
1466 | 0 | RE_REPEAT_ARGS* repeat_args; |
1467 | 0 | RE_REPEAT_ANY_ARGS* repeat_any_args; |
1468 | |
|
1469 | 0 | RE_FIBER* fiber; |
1470 | 0 | RE_FIBER* last; |
1471 | 0 | RE_FIBER* next; |
1472 | 0 | RE_FIBER* branch_a; |
1473 | 0 | RE_FIBER* branch_b; |
1474 | |
|
1475 | 0 | fiber = fiber_to_sync; |
1476 | 0 | last = fiber_to_sync->next; |
1477 | |
|
1478 | 0 | while (fiber != last) |
1479 | 0 | { |
1480 | 0 | int16_t jmp_len; |
1481 | 0 | uint8_t opcode = *fiber->ip; |
1482 | |
|
1483 | 0 | switch (opcode) |
1484 | 0 | { |
1485 | 0 | case RE_OPCODE_SPLIT_A: |
1486 | 0 | case RE_OPCODE_SPLIT_B: |
1487 | |
|
1488 | 0 | split_id = *(RE_SPLIT_ID_TYPE*) (fiber->ip + 1); |
1489 | 0 | split_already_executed = false; |
1490 | |
|
1491 | 0 | for (splits_executed_idx = 0; splits_executed_idx < splits_executed_count; |
1492 | 0 | splits_executed_idx++) |
1493 | 0 | { |
1494 | 0 | if (split_id == splits_executed[splits_executed_idx]) |
1495 | 0 | { |
1496 | 0 | split_already_executed = true; |
1497 | 0 | break; |
1498 | 0 | } |
1499 | 0 | } |
1500 | |
|
1501 | 0 | if (split_already_executed) |
1502 | 0 | { |
1503 | 0 | fiber = _yr_re_fiber_kill(fiber_list, fiber_pool, fiber); |
1504 | 0 | } |
1505 | 0 | else |
1506 | 0 | { |
1507 | 0 | branch_a = fiber; |
1508 | |
|
1509 | 0 | FAIL_ON_ERROR( |
1510 | 0 | _yr_re_fiber_split(fiber_list, fiber_pool, branch_a, &branch_b)); |
1511 | | |
1512 | | // With RE_OPCODE_SPLIT_A the current fiber continues at the next |
1513 | | // instruction in the stream (branch A), while the newly created |
1514 | | // fiber starts at the address indicated by the instruction (branch B) |
1515 | | // RE_OPCODE_SPLIT_B has the opposite behavior. |
1516 | |
|
1517 | 0 | if (opcode == RE_OPCODE_SPLIT_B) |
1518 | 0 | yr_swap(branch_a, branch_b, RE_FIBER*); |
1519 | | |
1520 | | // Branch A continues at the next instruction |
1521 | 0 | branch_a->ip += (sizeof(RE_SPLIT_ID_TYPE) + 3); |
1522 | | |
1523 | | // Branch B adds the offset indicated by the split instruction. |
1524 | 0 | jmp_len = yr_unaligned_i16(branch_b->ip + 1 + sizeof(RE_SPLIT_ID_TYPE)); |
1525 | |
|
1526 | 0 | branch_b->ip += jmp_len; |
1527 | |
|
1528 | 0 | #if YR_PARANOID_EXEC |
1529 | | // In normal conditions this should never happen. But with compiled |
1530 | | // rules that has been hand-crafted by a malicious actor this could |
1531 | | // happen. |
1532 | 0 | if (splits_executed_count >= RE_MAX_SPLIT_ID) |
1533 | 0 | return ERROR_INTERNAL_FATAL_ERROR; |
1534 | 0 | #endif |
1535 | | |
1536 | 0 | splits_executed[splits_executed_count] = split_id; |
1537 | 0 | splits_executed_count++; |
1538 | 0 | } |
1539 | | |
1540 | 0 | break; |
1541 | | |
1542 | 0 | case RE_OPCODE_REPEAT_START_GREEDY: |
1543 | 0 | case RE_OPCODE_REPEAT_START_UNGREEDY: |
1544 | |
|
1545 | 0 | repeat_args = (RE_REPEAT_ARGS*) (fiber->ip + 1); |
1546 | 0 | assert(repeat_args->max > 0); |
1547 | 0 | branch_a = fiber; |
1548 | |
|
1549 | 0 | if (repeat_args->min == 0) |
1550 | 0 | { |
1551 | 0 | FAIL_ON_ERROR( |
1552 | 0 | _yr_re_fiber_split(fiber_list, fiber_pool, branch_a, &branch_b)); |
1553 | |
|
1554 | 0 | if (opcode == RE_OPCODE_REPEAT_START_UNGREEDY) |
1555 | 0 | yr_swap(branch_a, branch_b, RE_FIBER*); |
1556 | |
|
1557 | 0 | branch_b->ip += repeat_args->offset; |
1558 | 0 | } |
1559 | | |
1560 | 0 | branch_a->stack[++branch_a->sp] = 0; |
1561 | 0 | branch_a->ip += (1 + sizeof(RE_REPEAT_ARGS)); |
1562 | 0 | break; |
1563 | | |
1564 | 0 | case RE_OPCODE_REPEAT_END_GREEDY: |
1565 | 0 | case RE_OPCODE_REPEAT_END_UNGREEDY: |
1566 | |
|
1567 | 0 | repeat_args = (RE_REPEAT_ARGS*) (fiber->ip + 1); |
1568 | 0 | fiber->stack[fiber->sp]++; |
1569 | |
|
1570 | 0 | if (fiber->stack[fiber->sp] < repeat_args->min) |
1571 | 0 | { |
1572 | 0 | fiber->ip += repeat_args->offset; |
1573 | 0 | break; |
1574 | 0 | } |
1575 | | |
1576 | 0 | branch_a = fiber; |
1577 | |
|
1578 | 0 | if (fiber->stack[fiber->sp] < repeat_args->max) |
1579 | 0 | { |
1580 | 0 | FAIL_ON_ERROR( |
1581 | 0 | _yr_re_fiber_split(fiber_list, fiber_pool, branch_a, &branch_b)); |
1582 | |
|
1583 | 0 | if (opcode == RE_OPCODE_REPEAT_END_GREEDY) |
1584 | 0 | yr_swap(branch_a, branch_b, RE_FIBER*); |
1585 | |
|
1586 | 0 | branch_b->ip += repeat_args->offset; |
1587 | 0 | } |
1588 | | |
1589 | 0 | branch_a->sp--; |
1590 | 0 | branch_a->ip += (1 + sizeof(RE_REPEAT_ARGS)); |
1591 | 0 | break; |
1592 | | |
1593 | 0 | case RE_OPCODE_REPEAT_ANY_GREEDY: |
1594 | 0 | case RE_OPCODE_REPEAT_ANY_UNGREEDY: |
1595 | |
|
1596 | 0 | repeat_any_args = (RE_REPEAT_ANY_ARGS*) (fiber->ip + 1); |
1597 | | |
1598 | | // If repetition counter (rc) is -1 it means that we are reaching this |
1599 | | // instruction from the previous one in the instructions stream. In |
1600 | | // this case let's initialize the counter to 0 and start looping. |
1601 | |
|
1602 | 0 | if (fiber->rc == -1) |
1603 | 0 | fiber->rc = 0; |
1604 | |
|
1605 | 0 | if (fiber->rc < repeat_any_args->min) |
1606 | 0 | { |
1607 | | // Increase repetition counter and continue with next fiber. The |
1608 | | // instruction pointer for this fiber is not incremented yet, this |
1609 | | // fiber spins in this same instruction until reaching the minimum |
1610 | | // number of repetitions. |
1611 | |
|
1612 | 0 | fiber->rc++; |
1613 | 0 | fiber = fiber->next; |
1614 | 0 | } |
1615 | 0 | else if (fiber->rc < repeat_any_args->max) |
1616 | 0 | { |
1617 | | // Once the minimum number of repetitions are matched one fiber |
1618 | | // remains spinning in this instruction until reaching the maximum |
1619 | | // number of repetitions while new fibers are created. New fibers |
1620 | | // start executing at the next instruction. |
1621 | |
|
1622 | 0 | next = fiber->next; |
1623 | 0 | branch_a = fiber; |
1624 | |
|
1625 | 0 | FAIL_ON_ERROR( |
1626 | 0 | _yr_re_fiber_split(fiber_list, fiber_pool, branch_a, &branch_b)); |
1627 | |
|
1628 | 0 | if (opcode == RE_OPCODE_REPEAT_ANY_UNGREEDY) |
1629 | 0 | yr_swap(branch_a, branch_b, RE_FIBER*); |
1630 | |
|
1631 | 0 | branch_a->rc++; |
1632 | 0 | branch_b->ip += (1 + sizeof(RE_REPEAT_ANY_ARGS)); |
1633 | 0 | branch_b->rc = -1; |
1634 | |
|
1635 | 0 | FAIL_ON_ERROR(_yr_re_fiber_sync(fiber_list, fiber_pool, branch_b)); |
1636 | |
|
1637 | 0 | fiber = next; |
1638 | 0 | } |
1639 | 0 | else |
1640 | 0 | { |
1641 | | // When the maximum number of repetitions is reached the fiber keeps |
1642 | | // executing at the next instruction. The repetition counter is set |
1643 | | // to -1 indicating that we are not spinning in a repeat instruction |
1644 | | // anymore. |
1645 | |
|
1646 | 0 | fiber->ip += (1 + sizeof(RE_REPEAT_ANY_ARGS)); |
1647 | 0 | fiber->rc = -1; |
1648 | 0 | } |
1649 | | |
1650 | 0 | break; |
1651 | | |
1652 | 0 | case RE_OPCODE_JUMP: |
1653 | 0 | jmp_len = yr_unaligned_i16(fiber->ip + 1); |
1654 | 0 | fiber->ip += jmp_len; |
1655 | 0 | break; |
1656 | | |
1657 | 0 | default: |
1658 | 0 | fiber = fiber->next; |
1659 | 0 | } |
1660 | 0 | } |
1661 | | |
1662 | 0 | return ERROR_SUCCESS; |
1663 | 0 | } |
1664 | | |
1665 | | //////////////////////////////////////////////////////////////////////////////// |
1666 | | // Executes a regular expression. The specified regular expression will try to |
1667 | | // match the data starting at the address specified by "input". The "input" |
1668 | | // pointer can point to any address inside a memory buffer. Arguments |
1669 | | // "input_forwards_size" and "input_backwards_size" indicate how many bytes |
1670 | | // can be accessible starting at "input" and going forwards and backwards |
1671 | | // respectively. |
1672 | | // |
1673 | | // <--- input_backwards_size -->|<----------- input_forwards_size --------> |
1674 | | // |-------- memory buffer -----------------------------------------------| |
1675 | | // ^ |
1676 | | // input |
1677 | | // |
1678 | | // Args: |
1679 | | // YR_SCAN_CONTEXT *context - Scan context. |
1680 | | // const uint8_t* code - Regexp code be executed |
1681 | | // const uint8_t* input - Pointer to input data |
1682 | | // size_t input_forwards_size - Number of accessible bytes starting at |
1683 | | // "input" and going forwards. |
1684 | | // size_t input_backwards_size - Number of accessible bytes starting at |
1685 | | // "input" and going backwards |
1686 | | // int flags - Flags: |
1687 | | // RE_FLAGS_SCAN |
1688 | | // RE_FLAGS_BACKWARDS |
1689 | | // RE_FLAGS_EXHAUSTIVE |
1690 | | // RE_FLAGS_WIDE |
1691 | | // RE_FLAGS_NO_CASE |
1692 | | // RE_FLAGS_DOT_ALL |
1693 | | // RE_MATCH_CALLBACK_FUNC callback - Callback function |
1694 | | // void* callback_args - Callback argument |
1695 | | // int* matches - Pointer to an integer receiving the |
1696 | | // number of matching bytes. Notice that |
1697 | | // 0 means a zero-length match, while no |
1698 | | // matches is -1. |
1699 | | // Returns: |
1700 | | // ERROR_SUCCESS or any other error code. |
1701 | | |
1702 | | int yr_re_exec( |
1703 | | YR_SCAN_CONTEXT* context, |
1704 | | const uint8_t* code, |
1705 | | const uint8_t* input_data, |
1706 | | size_t input_forwards_size, |
1707 | | size_t input_backwards_size, |
1708 | | int flags, |
1709 | | RE_MATCH_CALLBACK_FUNC callback, |
1710 | | void* callback_args, |
1711 | | int* matches) |
1712 | 0 | { |
1713 | 0 | const uint8_t* input; |
1714 | 0 | const uint8_t* ip; |
1715 | |
|
1716 | 0 | uint16_t opcode_args; |
1717 | 0 | uint8_t mask; |
1718 | 0 | uint8_t value; |
1719 | 0 | uint8_t character_size; |
1720 | |
|
1721 | 0 | RE_FIBER_LIST fibers; |
1722 | 0 | RE_FIBER* fiber; |
1723 | 0 | RE_FIBER* next_fiber; |
1724 | |
|
1725 | 0 | int bytes_matched; |
1726 | 0 | int max_bytes_matched; |
1727 | |
|
1728 | 0 | int match; |
1729 | 0 | int input_incr; |
1730 | 0 | int kill; |
1731 | 0 | int action; |
1732 | |
|
1733 | 0 | bool prev_is_word_char = false; |
1734 | 0 | bool input_is_word_char = false; |
1735 | |
|
1736 | 0 | #define ACTION_NONE 0 |
1737 | 0 | #define ACTION_CONTINUE 1 |
1738 | 0 | #define ACTION_KILL 2 |
1739 | 0 | #define ACTION_KILL_TAIL 3 |
1740 | |
|
1741 | 0 | #define prolog \ |
1742 | 0 | { \ |
1743 | 0 | if ((bytes_matched >= max_bytes_matched) || \ |
1744 | 0 | (character_size == 2 && *(input + 1) != 0)) \ |
1745 | 0 | { \ |
1746 | 0 | action = ACTION_KILL; \ |
1747 | 0 | break; \ |
1748 | 0 | } \ |
1749 | 0 | } |
1750 | |
|
1751 | 0 | if (matches != NULL) |
1752 | 0 | *matches = -1; |
1753 | |
|
1754 | 0 | if (flags & RE_FLAGS_WIDE) |
1755 | 0 | character_size = 2; |
1756 | 0 | else |
1757 | 0 | character_size = 1; |
1758 | |
|
1759 | 0 | input = input_data; |
1760 | 0 | input_incr = character_size; |
1761 | |
|
1762 | 0 | if (flags & RE_FLAGS_BACKWARDS) |
1763 | 0 | { |
1764 | | // Signedness conversion is sound as long as YR_RE_SCAN_LIMIT <= INT_MAX |
1765 | 0 | max_bytes_matched = (int) yr_min(input_backwards_size, YR_RE_SCAN_LIMIT); |
1766 | 0 | input -= character_size; |
1767 | 0 | input_incr = -input_incr; |
1768 | 0 | } |
1769 | 0 | else |
1770 | 0 | { |
1771 | | // Signedness conversion is sound as long as YR_RE_SCAN_LIMIT <= INT_MAX |
1772 | 0 | max_bytes_matched = (int) yr_min(input_forwards_size, YR_RE_SCAN_LIMIT); |
1773 | 0 | } |
1774 | | |
1775 | | // Round down max_bytes_matched to a multiple of character_size, this way if |
1776 | | // character_size is 2 and max_bytes_matched is odd we are ignoring the |
1777 | | // extra byte which can't match anyways. |
1778 | |
|
1779 | 0 | max_bytes_matched = max_bytes_matched - max_bytes_matched % character_size; |
1780 | 0 | bytes_matched = 0; |
1781 | |
|
1782 | 0 | FAIL_ON_ERROR(_yr_re_fiber_create(&context->re_fiber_pool, &fiber)); |
1783 | |
|
1784 | 0 | fiber->ip = code; |
1785 | 0 | fibers.head = fiber; |
1786 | 0 | fibers.tail = fiber; |
1787 | |
|
1788 | 0 | FAIL_ON_ERROR_WITH_CLEANUP( |
1789 | 0 | _yr_re_fiber_sync(&fibers, &context->re_fiber_pool, fiber), |
1790 | 0 | _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); |
1791 | |
|
1792 | 0 | while (fibers.head != NULL) |
1793 | 0 | { |
1794 | 0 | fiber = fibers.head; |
1795 | |
|
1796 | 0 | while (fiber != NULL) |
1797 | 0 | { |
1798 | 0 | next_fiber = fiber->next; |
1799 | |
|
1800 | 0 | if (_yr_re_fiber_exists(&fibers, fiber, fiber->prev)) |
1801 | 0 | _yr_re_fiber_kill(&fibers, &context->re_fiber_pool, fiber); |
1802 | |
|
1803 | 0 | fiber = next_fiber; |
1804 | 0 | } |
1805 | |
|
1806 | 0 | fiber = fibers.head; |
1807 | |
|
1808 | 0 | while (fiber != NULL) |
1809 | 0 | { |
1810 | 0 | ip = fiber->ip; |
1811 | 0 | action = ACTION_NONE; |
1812 | |
|
1813 | 0 | switch (*ip) |
1814 | 0 | { |
1815 | 0 | case RE_OPCODE_ANY: |
1816 | 0 | prolog; |
1817 | 0 | match = (flags & RE_FLAGS_DOT_ALL) || (*input != 0x0A); |
1818 | 0 | action = match ? ACTION_NONE : ACTION_KILL; |
1819 | 0 | fiber->ip += 1; |
1820 | 0 | break; |
1821 | | |
1822 | 0 | case RE_OPCODE_REPEAT_ANY_GREEDY: |
1823 | 0 | case RE_OPCODE_REPEAT_ANY_UNGREEDY: |
1824 | 0 | prolog; |
1825 | 0 | match = (flags & RE_FLAGS_DOT_ALL) || (*input != 0x0A); |
1826 | 0 | action = match ? ACTION_NONE : ACTION_KILL; |
1827 | | |
1828 | | // The instruction pointer is not incremented here. The current fiber |
1829 | | // spins in this instruction until reaching the required number of |
1830 | | // repetitions. The code controlling the number of repetitions is in |
1831 | | // _yr_re_fiber_sync. |
1832 | |
|
1833 | 0 | break; |
1834 | | |
1835 | 0 | case RE_OPCODE_LITERAL: |
1836 | 0 | prolog; |
1837 | 0 | if (flags & RE_FLAGS_NO_CASE) |
1838 | 0 | match = yr_lowercase[*input] == yr_lowercase[*(ip + 1)]; |
1839 | 0 | else |
1840 | 0 | match = (*input == *(ip + 1)); |
1841 | 0 | action = match ? ACTION_NONE : ACTION_KILL; |
1842 | 0 | fiber->ip += 2; |
1843 | 0 | break; |
1844 | | |
1845 | 0 | case RE_OPCODE_NOT_LITERAL: |
1846 | 0 | prolog; |
1847 | | |
1848 | | // We don't need to take into account the case-insensitive |
1849 | | // case because this opcode is only used with hex strings, |
1850 | | // which can't be case-insensitive. |
1851 | |
|
1852 | 0 | match = (*input != *(ip + 1)); |
1853 | 0 | action = match ? ACTION_NONE : ACTION_KILL; |
1854 | 0 | fiber->ip += 2; |
1855 | 0 | break; |
1856 | | |
1857 | 0 | case RE_OPCODE_MASKED_LITERAL: |
1858 | 0 | prolog; |
1859 | 0 | opcode_args = yr_unaligned_u16(ip + 1); |
1860 | 0 | mask = opcode_args >> 8; |
1861 | 0 | value = opcode_args & 0xFF; |
1862 | | |
1863 | | // We don't need to take into account the case-insensitive |
1864 | | // case because this opcode is only used with hex strings, |
1865 | | // which can't be case-insensitive. |
1866 | |
|
1867 | 0 | match = ((*input & mask) == value); |
1868 | 0 | action = match ? ACTION_NONE : ACTION_KILL; |
1869 | 0 | fiber->ip += 3; |
1870 | 0 | break; |
1871 | | |
1872 | 0 | case RE_OPCODE_MASKED_NOT_LITERAL: |
1873 | 0 | prolog; |
1874 | 0 | opcode_args = yr_unaligned_u16(ip + 1); |
1875 | 0 | mask = opcode_args >> 8; |
1876 | 0 | value = opcode_args & 0xFF; |
1877 | | |
1878 | | // We don't need to take into account the case-insensitive |
1879 | | // case because this opcode is only used with hex strings, |
1880 | | // which can't be case-insensitive. |
1881 | |
|
1882 | 0 | match = ((*input & mask) != value); |
1883 | 0 | action = match ? ACTION_NONE : ACTION_KILL; |
1884 | 0 | fiber->ip += 3; |
1885 | 0 | break; |
1886 | | |
1887 | 0 | case RE_OPCODE_CLASS: |
1888 | 0 | prolog; |
1889 | 0 | match = _yr_re_is_char_in_class( |
1890 | 0 | (RE_CLASS*) (ip + 1), *input, flags & RE_FLAGS_NO_CASE); |
1891 | 0 | action = match ? ACTION_NONE : ACTION_KILL; |
1892 | 0 | fiber->ip += (sizeof(RE_CLASS) + 1); |
1893 | 0 | break; |
1894 | | |
1895 | 0 | case RE_OPCODE_WORD_CHAR: |
1896 | 0 | prolog; |
1897 | 0 | match = _yr_re_is_word_char(input, character_size); |
1898 | 0 | action = match ? ACTION_NONE : ACTION_KILL; |
1899 | 0 | fiber->ip += 1; |
1900 | 0 | break; |
1901 | | |
1902 | 0 | case RE_OPCODE_NON_WORD_CHAR: |
1903 | 0 | prolog; |
1904 | 0 | match = !_yr_re_is_word_char(input, character_size); |
1905 | 0 | action = match ? ACTION_NONE : ACTION_KILL; |
1906 | 0 | fiber->ip += 1; |
1907 | 0 | break; |
1908 | | |
1909 | 0 | case RE_OPCODE_SPACE: |
1910 | 0 | case RE_OPCODE_NON_SPACE: |
1911 | |
|
1912 | 0 | prolog; |
1913 | |
|
1914 | 0 | switch (*input) |
1915 | 0 | { |
1916 | 0 | case ' ': |
1917 | 0 | case '\t': |
1918 | 0 | case '\r': |
1919 | 0 | case '\n': |
1920 | 0 | case '\v': |
1921 | 0 | case '\f': |
1922 | 0 | match = true; |
1923 | 0 | break; |
1924 | 0 | default: |
1925 | 0 | match = false; |
1926 | 0 | } |
1927 | | |
1928 | 0 | if (*ip == RE_OPCODE_NON_SPACE) |
1929 | 0 | match = !match; |
1930 | |
|
1931 | 0 | action = match ? ACTION_NONE : ACTION_KILL; |
1932 | 0 | fiber->ip += 1; |
1933 | 0 | break; |
1934 | | |
1935 | 0 | case RE_OPCODE_DIGIT: |
1936 | 0 | prolog; |
1937 | 0 | match = isdigit(*input); |
1938 | 0 | action = match ? ACTION_NONE : ACTION_KILL; |
1939 | 0 | fiber->ip += 1; |
1940 | 0 | break; |
1941 | | |
1942 | 0 | case RE_OPCODE_NON_DIGIT: |
1943 | 0 | prolog; |
1944 | 0 | match = !isdigit(*input); |
1945 | 0 | action = match ? ACTION_NONE : ACTION_KILL; |
1946 | 0 | fiber->ip += 1; |
1947 | 0 | break; |
1948 | | |
1949 | 0 | case RE_OPCODE_WORD_BOUNDARY: |
1950 | 0 | case RE_OPCODE_NON_WORD_BOUNDARY: |
1951 | 0 | if (input - input_incr + character_size <= |
1952 | 0 | input_data + input_forwards_size && |
1953 | 0 | input - input_incr >= input_data - input_backwards_size) |
1954 | 0 | { |
1955 | 0 | prev_is_word_char = _yr_re_is_word_char( |
1956 | 0 | input - input_incr, character_size); |
1957 | 0 | } |
1958 | 0 | else |
1959 | 0 | { |
1960 | 0 | prev_is_word_char = false; |
1961 | 0 | } |
1962 | |
|
1963 | 0 | if (input + character_size <= input_data + input_forwards_size && |
1964 | 0 | input >= input_data - input_backwards_size) |
1965 | 0 | { |
1966 | 0 | input_is_word_char = _yr_re_is_word_char(input, character_size); |
1967 | 0 | } |
1968 | 0 | else |
1969 | 0 | { |
1970 | 0 | input_is_word_char = false; |
1971 | 0 | } |
1972 | |
|
1973 | 0 | match = (prev_is_word_char && !input_is_word_char) || |
1974 | 0 | (!prev_is_word_char && input_is_word_char); |
1975 | |
|
1976 | 0 | if (*ip == RE_OPCODE_NON_WORD_BOUNDARY) |
1977 | 0 | match = !match; |
1978 | |
|
1979 | 0 | action = match ? ACTION_CONTINUE : ACTION_KILL; |
1980 | 0 | fiber->ip += 1; |
1981 | 0 | break; |
1982 | | |
1983 | 0 | case RE_OPCODE_MATCH_AT_START: |
1984 | 0 | if (flags & RE_FLAGS_BACKWARDS) |
1985 | 0 | kill = input_backwards_size > (size_t) bytes_matched; |
1986 | 0 | else |
1987 | 0 | kill = input_backwards_size > 0 || (bytes_matched != 0); |
1988 | 0 | action = kill ? ACTION_KILL : ACTION_CONTINUE; |
1989 | 0 | fiber->ip += 1; |
1990 | 0 | break; |
1991 | | |
1992 | 0 | case RE_OPCODE_MATCH_AT_END: |
1993 | 0 | kill = flags & RE_FLAGS_BACKWARDS || |
1994 | 0 | input_forwards_size > (size_t) bytes_matched; |
1995 | 0 | action = kill ? ACTION_KILL : ACTION_CONTINUE; |
1996 | 0 | fiber->ip += 1; |
1997 | 0 | break; |
1998 | | |
1999 | 0 | case RE_OPCODE_MATCH: |
2000 | |
|
2001 | 0 | if (matches != NULL) |
2002 | 0 | *matches = bytes_matched; |
2003 | |
|
2004 | 0 | if (flags & RE_FLAGS_EXHAUSTIVE) |
2005 | 0 | { |
2006 | 0 | if (callback != NULL) |
2007 | 0 | { |
2008 | 0 | if (flags & RE_FLAGS_BACKWARDS) |
2009 | 0 | { |
2010 | 0 | FAIL_ON_ERROR_WITH_CLEANUP( |
2011 | 0 | callback( |
2012 | 0 | input + character_size, |
2013 | 0 | bytes_matched, |
2014 | 0 | flags, |
2015 | 0 | callback_args), |
2016 | 0 | _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); |
2017 | 0 | } |
2018 | 0 | else |
2019 | 0 | { |
2020 | 0 | FAIL_ON_ERROR_WITH_CLEANUP( |
2021 | 0 | callback(input_data, bytes_matched, flags, callback_args), |
2022 | 0 | _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); |
2023 | 0 | } |
2024 | 0 | } |
2025 | | |
2026 | 0 | action = ACTION_KILL; |
2027 | 0 | } |
2028 | 0 | else |
2029 | 0 | { |
2030 | 0 | action = ACTION_KILL_TAIL; |
2031 | 0 | } |
2032 | | |
2033 | 0 | break; |
2034 | | |
2035 | 0 | default: |
2036 | 0 | assert(false); |
2037 | 0 | } |
2038 | | |
2039 | 0 | switch (action) |
2040 | 0 | { |
2041 | 0 | case ACTION_KILL: |
2042 | 0 | fiber = _yr_re_fiber_kill(&fibers, &context->re_fiber_pool, fiber); |
2043 | 0 | break; |
2044 | | |
2045 | 0 | case ACTION_KILL_TAIL: |
2046 | 0 | _yr_re_fiber_kill_tail(&fibers, &context->re_fiber_pool, fiber); |
2047 | 0 | fiber = NULL; |
2048 | 0 | break; |
2049 | | |
2050 | 0 | case ACTION_CONTINUE: |
2051 | 0 | FAIL_ON_ERROR_WITH_CLEANUP( |
2052 | 0 | _yr_re_fiber_sync(&fibers, &context->re_fiber_pool, fiber), |
2053 | 0 | _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); |
2054 | 0 | break; |
2055 | | |
2056 | 0 | default: |
2057 | 0 | next_fiber = fiber->next; |
2058 | 0 | FAIL_ON_ERROR_WITH_CLEANUP( |
2059 | 0 | _yr_re_fiber_sync(&fibers, &context->re_fiber_pool, fiber), |
2060 | 0 | _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); |
2061 | 0 | fiber = next_fiber; |
2062 | 0 | } |
2063 | 0 | } |
2064 | | |
2065 | 0 | input += input_incr; |
2066 | 0 | bytes_matched += character_size; |
2067 | |
|
2068 | 0 | if (flags & RE_FLAGS_SCAN && bytes_matched < max_bytes_matched) |
2069 | 0 | { |
2070 | 0 | FAIL_ON_ERROR_WITH_CLEANUP( |
2071 | 0 | _yr_re_fiber_create(&context->re_fiber_pool, &fiber), |
2072 | 0 | _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); |
2073 | |
|
2074 | 0 | fiber->ip = code; |
2075 | 0 | _yr_re_fiber_append(&fibers, fiber); |
2076 | |
|
2077 | 0 | FAIL_ON_ERROR_WITH_CLEANUP( |
2078 | 0 | _yr_re_fiber_sync(&fibers, &context->re_fiber_pool, fiber), |
2079 | 0 | _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); |
2080 | 0 | } |
2081 | 0 | } |
2082 | | |
2083 | 0 | return ERROR_SUCCESS; |
2084 | 0 | } |
2085 | | |
2086 | | //////////////////////////////////////////////////////////////////////////////// |
2087 | | // Helper function that creates a RE_FAST_EXEC_POSITION by either allocating it |
2088 | | // or reusing a previously allocated one from a pool. |
2089 | | // |
2090 | | static int _yr_re_fast_exec_position_create( |
2091 | | RE_FAST_EXEC_POSITION_POOL* pool, |
2092 | | RE_FAST_EXEC_POSITION** new_position) |
2093 | 0 | { |
2094 | 0 | RE_FAST_EXEC_POSITION* position; |
2095 | |
|
2096 | 0 | if (pool->head != NULL) |
2097 | 0 | { |
2098 | 0 | position = pool->head; |
2099 | 0 | pool->head = position->next; |
2100 | 0 | } |
2101 | 0 | else |
2102 | 0 | { |
2103 | 0 | position = (RE_FAST_EXEC_POSITION*) yr_malloc( |
2104 | 0 | sizeof(RE_FAST_EXEC_POSITION)); |
2105 | |
|
2106 | 0 | if (position == NULL) |
2107 | 0 | return ERROR_INSUFFICIENT_MEMORY; |
2108 | 0 | } |
2109 | | |
2110 | 0 | position->input = NULL; |
2111 | 0 | position->round = 0; |
2112 | 0 | position->next = NULL; |
2113 | 0 | position->prev = NULL; |
2114 | |
|
2115 | 0 | *new_position = position; |
2116 | |
|
2117 | 0 | return ERROR_SUCCESS; |
2118 | 0 | } |
2119 | | |
2120 | | //////////////////////////////////////////////////////////////////////////////// |
2121 | | // Helper function that moves a list of RE_FAST_EXEC_POSITION structures to a |
2122 | | // pool represented by a RE_FAST_EXEC_POSITION_POOL. Receives pointers to the |
2123 | | // pool, the first item, and last item in the list. |
2124 | | // |
2125 | | static void _yr_re_fast_exec_destroy_position_list( |
2126 | | RE_FAST_EXEC_POSITION_POOL* pool, |
2127 | | RE_FAST_EXEC_POSITION* first, |
2128 | | RE_FAST_EXEC_POSITION* last) |
2129 | 0 | { |
2130 | 0 | last->next = pool->head; |
2131 | |
|
2132 | 0 | if (pool->head != NULL) |
2133 | 0 | pool->head->prev = last; |
2134 | |
|
2135 | 0 | pool->head = first; |
2136 | 0 | } |
2137 | | |
2138 | | //////////////////////////////////////////////////////////////////////////////// |
2139 | | // This function replaces yr_re_exec for regular expressions marked with flag |
2140 | | // RE_FLAGS_FAST_REGEXP. These regular expressions are derived from hex strings |
2141 | | // that don't contain alternatives, like for example: |
2142 | | // |
2143 | | // { 01 02 03 04 [0-2] 04 05 06 07 } |
2144 | | // |
2145 | | // The regexp's code produced by such strings can be matched by a faster, less |
2146 | | // general algorithm, and it contains only the following opcodes: |
2147 | | // |
2148 | | // * RE_OPCODE_LITERAL |
2149 | | // * RE_OPCODE_MASKED_LITERAL, |
2150 | | // * RE_OPCODE_NOT_LITERAL |
2151 | | // * RE_OPCODE_MASKED_NOT_LITERAL |
2152 | | // * RE_OPCODE_ANY |
2153 | | // * RE_OPCODE_REPEAT_ANY_UNGREEDY |
2154 | | // * RE_OPCODE_MATCH. |
2155 | | // |
2156 | | // The regexp's code is executed one instruction at time, and the function |
2157 | | // maintains a list of positions within the input for tracking different |
2158 | | // matching alternatives, these positions are described by an instance of |
2159 | | // RE_FAST_EXEC_POSITION. With each instruction the list of positions is |
2160 | | // updated, removing those where the input data doesn't match the current |
2161 | | // instruction, or adding new positions if the instruction is |
2162 | | // RE_OPCODE_REPEAT_ANY_UNGREEDY. The list of positions is maintained sorted |
2163 | | // by the value of the pointer they hold to the input, and it doesn't contain |
2164 | | // duplicated pointer values. |
2165 | | // |
2166 | | int yr_re_fast_exec( |
2167 | | YR_SCAN_CONTEXT* context, |
2168 | | const uint8_t* code, |
2169 | | const uint8_t* input_data, |
2170 | | size_t input_forwards_size, |
2171 | | size_t input_backwards_size, |
2172 | | int flags, |
2173 | | RE_MATCH_CALLBACK_FUNC callback, |
2174 | | void* callback_args, |
2175 | | int* matches) |
2176 | 0 | { |
2177 | 0 | RE_REPEAT_ANY_ARGS* repeat_any_args; |
2178 | | |
2179 | | // Pointers to the first and last position in the list. |
2180 | 0 | RE_FAST_EXEC_POSITION* first; |
2181 | 0 | RE_FAST_EXEC_POSITION* last; |
2182 | |
|
2183 | 0 | int input_incr = flags & RE_FLAGS_BACKWARDS ? -1 : 1; |
2184 | 0 | int bytes_matched; |
2185 | 0 | int max_bytes_matched; |
2186 | |
|
2187 | 0 | if (flags & RE_FLAGS_BACKWARDS) |
2188 | 0 | max_bytes_matched = (int) yr_min(input_backwards_size, YR_RE_SCAN_LIMIT); |
2189 | 0 | else |
2190 | 0 | max_bytes_matched = (int) yr_min(input_forwards_size, YR_RE_SCAN_LIMIT); |
2191 | |
|
2192 | 0 | const uint8_t* ip = code; |
2193 | | |
2194 | | // Create the first position in the list, which points to the start of the |
2195 | | // input data. Intially this is the only position, more positions will be |
2196 | | // created every time RE_OPCODE_REPEAT_ANY_UNGREEDY is executed. |
2197 | 0 | FAIL_ON_ERROR(_yr_re_fast_exec_position_create( |
2198 | 0 | &context->re_fast_exec_position_pool, &first)); |
2199 | |
|
2200 | 0 | first->round = 0; |
2201 | 0 | first->input = input_data; |
2202 | 0 | first->prev = NULL; |
2203 | 0 | first->next = NULL; |
2204 | |
|
2205 | 0 | if (flags & RE_FLAGS_BACKWARDS) |
2206 | 0 | first->input--; |
2207 | | |
2208 | | // As we are starting with a single position, the last one and the first one |
2209 | | // are the same. |
2210 | 0 | last = first; |
2211 | | |
2212 | | // Round is incremented with every regxp instruction. |
2213 | 0 | int round = 0; |
2214 | | |
2215 | | // Keep in the loop until the list of positions gets empty. Positions are |
2216 | | // removed from the list when they don't match the current instruction in |
2217 | | // the code. |
2218 | 0 | while (first != NULL) |
2219 | 0 | { |
2220 | 0 | RE_FAST_EXEC_POSITION* current = first; |
2221 | | |
2222 | | // Iterate over all the positions, executing the current instruction at |
2223 | | // all of them. |
2224 | 0 | while (current != NULL) |
2225 | 0 | { |
2226 | 0 | RE_FAST_EXEC_POSITION* next = current->next; |
2227 | | |
2228 | | // Ignore any position in the list whose round number is different from |
2229 | | // the current round. This prevents new positions added to the list in |
2230 | | // this round from being taken into account in this same round. |
2231 | 0 | if (current->round != round) |
2232 | 0 | { |
2233 | 0 | current = next; |
2234 | 0 | continue; |
2235 | 0 | } |
2236 | | |
2237 | 0 | bytes_matched = flags & RE_FLAGS_BACKWARDS |
2238 | 0 | ? (int) (input_data - current->input - 1) |
2239 | 0 | : (int) (current->input - input_data); |
2240 | |
|
2241 | 0 | uint16_t opcode_args; |
2242 | 0 | uint8_t mask; |
2243 | 0 | uint8_t value; |
2244 | |
|
2245 | 0 | bool match = false; |
2246 | |
|
2247 | 0 | switch (*ip) |
2248 | 0 | { |
2249 | 0 | case RE_OPCODE_ANY: |
2250 | 0 | if (bytes_matched >= max_bytes_matched) |
2251 | 0 | break; |
2252 | | |
2253 | 0 | match = true; |
2254 | 0 | current->input += input_incr; |
2255 | 0 | break; |
2256 | | |
2257 | 0 | case RE_OPCODE_LITERAL: |
2258 | 0 | if (bytes_matched >= max_bytes_matched) |
2259 | 0 | break; |
2260 | | |
2261 | 0 | if (*current->input == *(ip + 1)) |
2262 | 0 | { |
2263 | 0 | match = true; |
2264 | 0 | current->input += input_incr; |
2265 | 0 | } |
2266 | 0 | break; |
2267 | | |
2268 | 0 | case RE_OPCODE_NOT_LITERAL: |
2269 | 0 | if (bytes_matched >= max_bytes_matched) |
2270 | 0 | break; |
2271 | | |
2272 | 0 | if (*current->input != *(ip + 1)) |
2273 | 0 | { |
2274 | 0 | match = true; |
2275 | 0 | current->input += input_incr; |
2276 | 0 | } |
2277 | 0 | break; |
2278 | | |
2279 | 0 | case RE_OPCODE_MASKED_LITERAL: |
2280 | 0 | if (bytes_matched >= max_bytes_matched) |
2281 | 0 | break; |
2282 | | |
2283 | 0 | opcode_args = yr_unaligned_u16(ip + 1); |
2284 | 0 | mask = opcode_args >> 8; |
2285 | 0 | value = opcode_args & 0xFF; |
2286 | |
|
2287 | 0 | if ((*current->input & mask) == value) |
2288 | 0 | { |
2289 | 0 | match = true; |
2290 | 0 | current->input += input_incr; |
2291 | 0 | } |
2292 | 0 | break; |
2293 | | |
2294 | 0 | case RE_OPCODE_MASKED_NOT_LITERAL: |
2295 | 0 | if (bytes_matched >= max_bytes_matched) |
2296 | 0 | break; |
2297 | | |
2298 | 0 | opcode_args = yr_unaligned_u16(ip + 1); |
2299 | 0 | mask = opcode_args >> 8; |
2300 | 0 | value = opcode_args & 0xFF; |
2301 | |
|
2302 | 0 | if ((*current->input & mask) != value) |
2303 | 0 | { |
2304 | 0 | match = true; |
2305 | 0 | current->input += input_incr; |
2306 | 0 | } |
2307 | 0 | break; |
2308 | | |
2309 | 0 | case RE_OPCODE_REPEAT_ANY_UNGREEDY: |
2310 | 0 | repeat_any_args = (RE_REPEAT_ANY_ARGS*) (ip + 1); |
2311 | |
|
2312 | 0 | if (bytes_matched + repeat_any_args->min >= max_bytes_matched) |
2313 | 0 | break; |
2314 | | |
2315 | 0 | match = true; |
2316 | |
|
2317 | 0 | const uint8_t* next_opcode = ip + 1 + sizeof(RE_REPEAT_ANY_ARGS); |
2318 | | |
2319 | | // insertion_point indicates the item in the list of inputs after which |
2320 | | // the newly created inputs will be inserted. |
2321 | 0 | RE_FAST_EXEC_POSITION* insertion_point = current; |
2322 | |
|
2323 | 0 | for (int j = repeat_any_args->min + 1; j <= repeat_any_args->max; j++) |
2324 | 0 | { |
2325 | | // bytes_matched is the number of bytes matched so far, and j is the |
2326 | | // minimum number of bytes that are still pending to match. If these |
2327 | | // two numbers sum more than the maximum number of bytes that can be |
2328 | | // matched the loop can be aborted. The position that we were about |
2329 | | // to create can't lead to a match without exceeding |
2330 | | // max_bytes_matched. |
2331 | 0 | if (bytes_matched + j >= max_bytes_matched) |
2332 | 0 | break; |
2333 | | |
2334 | 0 | const uint8_t* next_input = current->input + j * input_incr; |
2335 | | |
2336 | | // Find the point where next_input should be inserted. The list is |
2337 | | // kept sorted by pointer in increasing order, the insertion point is |
2338 | | // an item that has a pointer lower or equal than next_input, but |
2339 | | // whose next item have a pointer that is larger. |
2340 | 0 | while (insertion_point->next != NULL && |
2341 | 0 | insertion_point->next->input <= next_input) |
2342 | 0 | { |
2343 | 0 | insertion_point = insertion_point->next; |
2344 | 0 | } |
2345 | | |
2346 | | // If the input already exists for the next round, we don't need to |
2347 | | // insert it. |
2348 | 0 | if (insertion_point->round == round + 1 && |
2349 | 0 | insertion_point->input == next_input) |
2350 | 0 | continue; |
2351 | | |
2352 | | // The next opcode is RE_OPCODE_LITERAL, but the literal doesn't |
2353 | | // match with the byte at next_input, we don't need to add this |
2354 | | // input to the list as we already know that it won't match in the |
2355 | | // next round and will be deleted from the list anyways. |
2356 | 0 | if (*(next_opcode) == RE_OPCODE_LITERAL && |
2357 | 0 | *(next_opcode + 1) != *next_input) |
2358 | 0 | continue; |
2359 | | |
2360 | 0 | RE_FAST_EXEC_POSITION* new_input; |
2361 | |
|
2362 | 0 | FAIL_ON_ERROR_WITH_CLEANUP( |
2363 | 0 | _yr_re_fast_exec_position_create( |
2364 | 0 | &context->re_fast_exec_position_pool, &new_input), |
2365 | | // Cleanup |
2366 | 0 | _yr_re_fast_exec_destroy_position_list( |
2367 | 0 | &context->re_fast_exec_position_pool, first, last)); |
2368 | |
|
2369 | 0 | new_input->input = next_input; |
2370 | 0 | new_input->round = round + 1; |
2371 | 0 | new_input->prev = insertion_point; |
2372 | 0 | new_input->next = insertion_point->next; |
2373 | 0 | insertion_point->next = new_input; |
2374 | |
|
2375 | 0 | if (new_input->next != NULL) |
2376 | 0 | new_input->next->prev = new_input; |
2377 | |
|
2378 | 0 | if (insertion_point == last) |
2379 | 0 | last = new_input; |
2380 | 0 | } |
2381 | | |
2382 | 0 | current->input += input_incr * repeat_any_args->min; |
2383 | 0 | break; |
2384 | | |
2385 | 0 | case RE_OPCODE_MATCH: |
2386 | |
|
2387 | 0 | if (flags & RE_FLAGS_EXHAUSTIVE) |
2388 | 0 | { |
2389 | 0 | FAIL_ON_ERROR_WITH_CLEANUP( |
2390 | 0 | callback( |
2391 | | // When matching forwards the matching data always starts at |
2392 | | // input_data, when matching backwards it starts at input + 1 |
2393 | | // or input_data - input_backwards_size if input + 1 is |
2394 | | // outside the buffer. |
2395 | 0 | flags & RE_FLAGS_BACKWARDS |
2396 | 0 | ? yr_max( |
2397 | 0 | current->input + 1, |
2398 | 0 | input_data - input_backwards_size) |
2399 | 0 | : input_data, |
2400 | | // The number of matched bytes should not be larger than |
2401 | | // max_bytes_matched. |
2402 | 0 | yr_min(bytes_matched, max_bytes_matched), |
2403 | 0 | flags, |
2404 | 0 | callback_args), |
2405 | | // Cleanup |
2406 | 0 | _yr_re_fast_exec_destroy_position_list( |
2407 | 0 | &context->re_fast_exec_position_pool, first, last)); |
2408 | 0 | } |
2409 | 0 | else |
2410 | 0 | { |
2411 | 0 | if (matches != NULL) |
2412 | 0 | *matches = bytes_matched; |
2413 | |
|
2414 | 0 | _yr_re_fast_exec_destroy_position_list( |
2415 | 0 | &context->re_fast_exec_position_pool, first, last); |
2416 | |
|
2417 | 0 | return ERROR_SUCCESS; |
2418 | 0 | } |
2419 | 0 | break; |
2420 | | |
2421 | 0 | default: |
2422 | 0 | printf("non-supported opcode: %d\n", *ip); |
2423 | 0 | assert(false); |
2424 | 0 | } |
2425 | | |
2426 | 0 | if (match) |
2427 | 0 | { |
2428 | 0 | current->round = round + 1; |
2429 | 0 | } |
2430 | 0 | else |
2431 | 0 | { |
2432 | | // Remove current from the list. If the item being removed is the first |
2433 | | // one or the last one, the first and last pointers should be updated. |
2434 | | // The removed item is put into the pool for later reuse. |
2435 | |
|
2436 | 0 | if (current == first) |
2437 | 0 | first = current->next; |
2438 | |
|
2439 | 0 | if (current == last) |
2440 | 0 | last = current->prev; |
2441 | |
|
2442 | 0 | if (current->prev != NULL) |
2443 | 0 | current->prev->next = current->next; |
2444 | |
|
2445 | 0 | if (current->next != NULL) |
2446 | 0 | current->next->prev = current->prev; |
2447 | |
|
2448 | 0 | current->prev = NULL; |
2449 | 0 | current->next = context->re_fast_exec_position_pool.head; |
2450 | |
|
2451 | 0 | if (current->next != NULL) |
2452 | 0 | current->next->prev = current; |
2453 | |
|
2454 | 0 | context->re_fast_exec_position_pool.head = current; |
2455 | 0 | } |
2456 | |
|
2457 | 0 | current = next; |
2458 | |
|
2459 | 0 | } // while (current != NULL) |
2460 | | |
2461 | | // Move instruction pointer (ip) to next instruction. Each opcode has |
2462 | | // a different size. |
2463 | 0 | switch (*ip) |
2464 | 0 | { |
2465 | 0 | case RE_OPCODE_ANY: |
2466 | 0 | ip += 1; |
2467 | 0 | break; |
2468 | 0 | case RE_OPCODE_LITERAL: |
2469 | 0 | case RE_OPCODE_NOT_LITERAL: |
2470 | 0 | ip += 2; |
2471 | 0 | break; |
2472 | 0 | case RE_OPCODE_MASKED_LITERAL: |
2473 | 0 | case RE_OPCODE_MASKED_NOT_LITERAL: |
2474 | 0 | ip += 3; |
2475 | 0 | break; |
2476 | 0 | case RE_OPCODE_REPEAT_ANY_UNGREEDY: |
2477 | 0 | ip += 1 + sizeof(RE_REPEAT_ANY_ARGS); |
2478 | 0 | break; |
2479 | 0 | case RE_OPCODE_MATCH: |
2480 | 0 | break; |
2481 | 0 | default: |
2482 | 0 | assert(false); |
2483 | 0 | } |
2484 | | |
2485 | 0 | round++; |
2486 | 0 | } |
2487 | | |
2488 | | // If this point is reached no matches were found. |
2489 | | |
2490 | 0 | if (matches != NULL) |
2491 | 0 | *matches = -1; |
2492 | |
|
2493 | 0 | return ERROR_SUCCESS; |
2494 | 0 | } |
2495 | | |
2496 | | static void _yr_re_print_node(RE_NODE* re_node, uint32_t indent) |
2497 | 0 | { |
2498 | 0 | RE_NODE* child; |
2499 | 0 | int i; |
2500 | |
|
2501 | 0 | if (re_node == NULL) |
2502 | 0 | return; |
2503 | | |
2504 | 0 | if (indent > 0) |
2505 | 0 | printf("\n%*s", indent, " "); |
2506 | 0 | switch (re_node->type) |
2507 | 0 | { |
2508 | 0 | case RE_NODE_ALT: |
2509 | 0 | printf("Alt("); |
2510 | 0 | _yr_re_print_node(re_node->children_head, indent + 4); |
2511 | 0 | printf(","); |
2512 | 0 | _yr_re_print_node(re_node->children_tail, indent + 4); |
2513 | 0 | printf("\n%*s%s", indent, " ", ")"); |
2514 | 0 | break; |
2515 | | |
2516 | 0 | case RE_NODE_CONCAT: |
2517 | 0 | printf("Cat("); |
2518 | 0 | child = re_node->children_head; |
2519 | 0 | while (child != NULL) |
2520 | 0 | { |
2521 | 0 | _yr_re_print_node(child, indent + 4); |
2522 | 0 | printf(","); |
2523 | 0 | child = child->next_sibling; |
2524 | 0 | } |
2525 | 0 | printf("\n%*s%s", indent, " ", ")"); |
2526 | 0 | break; |
2527 | | |
2528 | 0 | case RE_NODE_STAR: |
2529 | 0 | printf("Star("); |
2530 | 0 | _yr_re_print_node(re_node->children_head, indent + 4); |
2531 | 0 | printf(")"); |
2532 | 0 | break; |
2533 | | |
2534 | 0 | case RE_NODE_PLUS: |
2535 | 0 | printf("Plus("); |
2536 | 0 | _yr_re_print_node(re_node->children_head, indent + 4); |
2537 | 0 | printf(")"); |
2538 | 0 | break; |
2539 | | |
2540 | 0 | case RE_NODE_LITERAL: |
2541 | 0 | printf("Lit(%c)", re_node->value); |
2542 | 0 | break; |
2543 | | |
2544 | 0 | case RE_NODE_NOT_LITERAL: |
2545 | 0 | printf("NotLit(%c)", re_node->value); |
2546 | 0 | break; |
2547 | | |
2548 | 0 | case RE_NODE_MASKED_LITERAL: |
2549 | 0 | printf("MaskedLit(%02X,%02X)", re_node->value, re_node->mask); |
2550 | 0 | break; |
2551 | | |
2552 | 0 | case RE_NODE_WORD_CHAR: |
2553 | 0 | printf("WordChar"); |
2554 | 0 | break; |
2555 | | |
2556 | 0 | case RE_NODE_NON_WORD_CHAR: |
2557 | 0 | printf("NonWordChar"); |
2558 | 0 | break; |
2559 | | |
2560 | 0 | case RE_NODE_SPACE: |
2561 | 0 | printf("Space"); |
2562 | 0 | break; |
2563 | | |
2564 | 0 | case RE_NODE_NON_SPACE: |
2565 | 0 | printf("NonSpace"); |
2566 | 0 | break; |
2567 | | |
2568 | 0 | case RE_NODE_DIGIT: |
2569 | 0 | printf("Digit"); |
2570 | 0 | break; |
2571 | | |
2572 | 0 | case RE_NODE_NON_DIGIT: |
2573 | 0 | printf("NonDigit"); |
2574 | 0 | break; |
2575 | | |
2576 | 0 | case RE_NODE_ANY: |
2577 | 0 | printf("Any"); |
2578 | 0 | break; |
2579 | | |
2580 | 0 | case RE_NODE_RANGE: |
2581 | 0 | printf("Range(%d-%d, ", re_node->start, re_node->end); |
2582 | 0 | _yr_re_print_node(re_node->children_head, indent + 4); |
2583 | 0 | printf("\n%*s%s", indent, " ", ")"); |
2584 | 0 | break; |
2585 | | |
2586 | 0 | case RE_NODE_CLASS: |
2587 | 0 | printf("Class("); |
2588 | 0 | for (i = 0; i < 256; i++) |
2589 | 0 | if (_yr_re_is_char_in_class(re_node->re_class, i, false)) |
2590 | 0 | printf("%02X,", i); |
2591 | 0 | printf(")"); |
2592 | 0 | break; |
2593 | | |
2594 | 0 | case RE_NODE_EMPTY: |
2595 | 0 | printf("Empty"); |
2596 | 0 | break; |
2597 | | |
2598 | 0 | case RE_NODE_ANCHOR_START: |
2599 | 0 | printf("AnchorStart"); |
2600 | 0 | break; |
2601 | | |
2602 | 0 | case RE_NODE_ANCHOR_END: |
2603 | 0 | printf("AnchorEnd"); |
2604 | 0 | break; |
2605 | | |
2606 | 0 | case RE_NODE_WORD_BOUNDARY: |
2607 | 0 | printf("WordBoundary"); |
2608 | 0 | break; |
2609 | | |
2610 | 0 | case RE_NODE_NON_WORD_BOUNDARY: |
2611 | 0 | printf("NonWordBoundary"); |
2612 | 0 | break; |
2613 | | |
2614 | 0 | case RE_NODE_RANGE_ANY: |
2615 | 0 | printf("RangeAny"); |
2616 | 0 | break; |
2617 | | |
2618 | 0 | default: |
2619 | 0 | printf("???"); |
2620 | 0 | break; |
2621 | 0 | } |
2622 | 0 | } |
2623 | | |
2624 | | void yr_re_print(RE_AST* re_ast) |
2625 | 0 | { |
2626 | 0 | _yr_re_print_node(re_ast->root_node, 0); |
2627 | 0 | } |