@@ -53,6 +53,9 @@ typedef enum {
53
53
54
54
#define CAPTURE_COUNT_MAX 255
55
55
#define STACK_SIZE_MAX 255
56
+ /* must be large enough to have a negligible runtime cost and small
57
+ enough to call the interrupt callback often. */
58
+ #define INTERRUPT_COUNTER_INIT 10000
56
59
57
60
/* unicode code points */
58
61
#define CP_LS 0x2028
@@ -1992,6 +1995,7 @@ typedef struct {
1992
1995
bool multi_line ;
1993
1996
bool ignore_case ;
1994
1997
bool is_unicode ;
1998
+ int interrupt_counter ;
1995
1999
void * opaque ; /* used for stack overflow check */
1996
2000
1997
2001
size_t state_size ;
@@ -2038,7 +2042,17 @@ static int push_state(REExecContext *s,
2038
2042
return 0 ;
2039
2043
}
2040
2044
2041
- /* return 1 if match, 0 if not match or -1 if error. */
2045
+ static int lre_poll_timeout (REExecContext * s )
2046
+ {
2047
+ if (unlikely (-- s -> interrupt_counter <= 0 )) {
2048
+ s -> interrupt_counter = INTERRUPT_COUNTER_INIT ;
2049
+ if (lre_check_timeout (s -> opaque ))
2050
+ return LRE_RET_TIMEOUT ;
2051
+ }
2052
+ return 0 ;
2053
+ }
2054
+
2055
+ /* return 1 if match, 0 if not match or < 0 if error. */
2042
2056
static intptr_t lre_exec_backtrack (REExecContext * s , uint8_t * * capture ,
2043
2057
StackInt * stack , int stack_len ,
2044
2058
const uint8_t * pc , const uint8_t * cptr ,
@@ -2069,6 +2083,8 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
2069
2083
ret = 0 ;
2070
2084
recurse :
2071
2085
for (;;) {
2086
+ if (lre_poll_timeout (s ))
2087
+ return LRE_RET_TIMEOUT ;
2072
2088
if (s -> state_stack_len == 0 )
2073
2089
return ret ;
2074
2090
rs = (REExecState * )(s -> state_stack +
@@ -2162,7 +2178,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
2162
2178
ret = push_state (s , capture , stack , stack_len ,
2163
2179
pc1 , cptr , RE_EXEC_STATE_SPLIT , 0 );
2164
2180
if (ret < 0 )
2165
- return -1 ;
2181
+ return LRE_RET_MEMORY_ERROR ;
2166
2182
break ;
2167
2183
}
2168
2184
case REOP_lookahead :
@@ -2174,12 +2190,14 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
2174
2190
RE_EXEC_STATE_LOOKAHEAD + opcode - REOP_lookahead ,
2175
2191
0 );
2176
2192
if (ret < 0 )
2177
- return -1 ;
2193
+ return LRE_RET_MEMORY_ERROR ;
2178
2194
break ;
2179
2195
2180
2196
case REOP_goto :
2181
2197
val = get_u32 (pc );
2182
2198
pc += 4 + (int )val ;
2199
+ if (lre_poll_timeout (s ))
2200
+ return LRE_RET_TIMEOUT ;
2183
2201
break ;
2184
2202
case REOP_line_start :
2185
2203
if (cptr == s -> cbuf )
@@ -2244,6 +2262,8 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
2244
2262
pc += 4 ;
2245
2263
if (-- stack [stack_len - 1 ] != 0 ) {
2246
2264
pc += (int )val ;
2265
+ if (lre_poll_timeout (s ))
2266
+ return LRE_RET_TIMEOUT ;
2247
2267
}
2248
2268
break ;
2249
2269
case REOP_push_char_pos :
@@ -2418,9 +2438,12 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
2418
2438
2419
2439
q = 0 ;
2420
2440
for (;;) {
2441
+ if (lre_poll_timeout (s ))
2442
+ return LRE_RET_TIMEOUT ;
2421
2443
res = lre_exec_backtrack (s , capture , stack , stack_len ,
2422
2444
pc1 , cptr , true);
2423
- if (res == -1 )
2445
+ if (res == LRE_RET_MEMORY_ERROR ||
2446
+ res == LRE_RET_TIMEOUT )
2424
2447
return res ;
2425
2448
if (!res )
2426
2449
break ;
@@ -2438,7 +2461,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
2438
2461
RE_EXEC_STATE_GREEDY_QUANT ,
2439
2462
q - quant_min );
2440
2463
if (ret < 0 )
2441
- return -1 ;
2464
+ return LRE_RET_MEMORY_ERROR ;
2442
2465
}
2443
2466
}
2444
2467
break ;
@@ -2448,7 +2471,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
2448
2471
}
2449
2472
}
2450
2473
2451
- /* Return 1 if match, 0 if not match or -1 if error. cindex is the
2474
+ /* Return 1 if match, 0 if not match or < 0 if error (see LRE_RET_x) . cindex is the
2452
2475
starting position of the match and must be such as 0 <= cindex <=
2453
2476
clen. */
2454
2477
int lre_exec (uint8_t * * capture ,
@@ -2470,6 +2493,7 @@ int lre_exec(uint8_t **capture,
2470
2493
s -> cbuf_type = cbuf_type ;
2471
2494
if (s -> cbuf_type == 1 && s -> is_unicode )
2472
2495
s -> cbuf_type = 2 ;
2496
+ s -> interrupt_counter = INTERRUPT_COUNTER_INIT ;
2473
2497
s -> opaque = opaque ;
2474
2498
2475
2499
s -> state_size = sizeof (REExecState ) +
0 commit comments