aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zhu <peter@peterzhu.ca>2024-01-30 14:15:56 -0500
committerPeter Zhu <peter@peterzhu.ca>2024-02-02 10:39:42 -0500
commit1c120efe02d079b0a1dea573cf0fd7978d9cc857 (patch)
tree137c02f71f262d8368098dc47f0b87fb024eab7a
parenta4e4e3b1f1bd66ce9121c0ba2a1926e2459106dc (diff)
downloadruby-1c120efe02d079b0a1dea573cf0fd7978d9cc857.tar.gz
Fix memory leak in stk_base when Regexp timeout
[Bug #20228] If rb_reg_check_timeout raises a Regexp::TimeoutError, then the stk_base will leak.
-rw-r--r--re.c16
-rw-r--r--regexec.c7
-rw-r--r--regint.h20
3 files changed, 31 insertions, 12 deletions
diff --git a/re.c b/re.c
index 2f515779c7..2256a0655d 100644
--- a/re.c
+++ b/re.c
@@ -4605,8 +4605,8 @@ re_warn(const char *s)
rb_hrtime_t rb_reg_match_time_limit = 0;
// This function is periodically called during regexp matching
-void
-rb_reg_check_timeout(regex_t *reg, void *end_time_)
+bool
+rb_reg_timeout_p(regex_t *reg, void *end_time_)
{
rb_hrtime_t *end_time = (rb_hrtime_t *)end_time_;
@@ -4631,10 +4631,18 @@ rb_reg_check_timeout(regex_t *reg, void *end_time_)
}
else {
if (*end_time < rb_hrtime_now()) {
- // timeout is exceeded
- rb_raise(rb_eRegexpTimeoutError, "regexp match timeout");
+ // Timeout has exceeded
+ return true;
}
}
+
+ return false;
+}
+
+void
+rb_reg_raise_timeout(void)
+{
+ rb_raise(rb_eRegexpTimeoutError, "regexp match timeout");
}
/*
diff --git a/regexec.c b/regexec.c
index 150d36ccc8..81d0ea6a6b 100644
--- a/regexec.c
+++ b/regexec.c
@@ -2293,7 +2293,7 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
UChar *pkeep;
char *alloca_base;
char *xmalloc_base = NULL;
- OnigStackType *stk_alloc, *stk_base, *stk, *stk_end;
+ OnigStackType *stk_alloc, *stk_base = NULL, *stk, *stk_end;
OnigStackType *stkp; /* used as any purpose. */
OnigStackIndex si;
OnigStackIndex *repeat_stk;
@@ -4202,6 +4202,11 @@ match_at(regex_t* reg, const UChar* str, const UChar* end,
STACK_SAVE;
xfree(xmalloc_base);
return ONIGERR_UNEXPECTED_BYTECODE;
+
+ timeout:
+ xfree(xmalloc_base);
+ xfree(stk_base);
+ HANDLE_REG_TIMEOUT_IN_MATCH_AT;
}
diff --git a/regint.h b/regint.h
index 034a31426c..57cbb81654 100644
--- a/regint.h
+++ b/regint.h
@@ -154,13 +154,18 @@
#ifdef RUBY
# define CHECK_INTERRUPT_IN_MATCH_AT do { \
- msa->counter++; \
- if (msa->counter >= 128) { \
- msa->counter = 0; \
- rb_reg_check_timeout(reg, &msa->end_time); \
- rb_thread_check_ints(); \
- } \
+ msa->counter++; \
+ if (msa->counter >= 128) { \
+ msa->counter = 0; \
+ if (rb_reg_timeout_p(reg, &msa->end_time)) { \
+ goto timeout; \
+ } \
+ rb_thread_check_ints(); \
+ } \
} while(0)
+# define HANDLE_REG_TIMEOUT_IN_MATCH_AT do { \
+ rb_reg_raise_timeout(); \
+} while (0)
# define onig_st_init_table st_init_table
# define onig_st_init_table_with_size st_init_table_with_size
# define onig_st_init_numtable st_init_numtable
@@ -996,7 +1001,8 @@ extern int onig_st_insert_strend(hash_table_type* table, const UChar* str_key, c
#ifdef RUBY
extern size_t onig_memsize(const regex_t *reg);
extern size_t onig_region_memsize(const struct re_registers *regs);
-void rb_reg_check_timeout(regex_t *reg, void *end_time);
+bool rb_reg_timeout_p(regex_t *reg, void *end_time);
+NORETURN(void rb_reg_raise_timeout(void));
#endif
RUBY_SYMBOL_EXPORT_END