8000 [Bug #20228] Fix memory leak in Regexp timeout by peterzhu2118 · Pull Request #9765 · ruby/ruby · GitHub
[go: up one dir, main page]

Skip to content

[Bug #20228] Fix memory leak in Regexp timeout #9765

8000
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 2, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix memory leak in OnigRegion when match raises
[Bug #20228]

rb_reg_onig_match can raise a Regexp::TimeoutError, which would cause
the OnigRegion to leak.
  • Loading branch information
peterzhu2118 committed Jan 31, 2024
commit 062e000d9a8269f30d5421a68507975e60aa782e
55 changes: 44 additions & 11 deletions re.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ static const char casetable[] = {
# error >>> "You lose. You will need a translation table for your character set." <<<
#endif

// The process-global timeout for regexp matching
rb_hrtime_t rb_reg_match_time_limit = 0;

int
rb_memcicmp(const void *x, const void *y, long len)
{
Expand Down Expand Up @@ -1732,6 +1735,23 @@ reg_onig_search(regex_t *reg, VALUE str, struct re_registers *regs, void *args_p
ONIG_OPTION_NONE);
}

struct rb_reg_onig_match_args {
VALUE re;
VALUE str;
struct reg_onig_search_args args;
struct re_registers regs;

OnigPosition result;
};

static VALUE
rb_reg_onig_match_try(VALUE value_args)
{
struct rb_reg_onig_match_args *args = (struct rb_reg_onig_match_args *)value_args;
args->result = rb_reg_onig_match(args->re, args->str, reg_onig_search, &args->args, &args->regs);
return Qnil;
}

/* returns byte offset */
static long
rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_backref_str, VALUE *set_match)
Expand All @@ -1742,22 +1762,38 @@ rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_back
return -1;
}

struct reg_onig_search_args args = {
.pos = pos,
.range = reverse ? 0 : len,
struct rb_reg_onig_match_args args = {
.re = re,
.str = str,
.args = {
.pos = pos,
.range = reverse ? 0 : len,
},
.regs = {0}
};

struct re_registers regs = {0};
/* If there is a timeout set, then rb_reg_onig_match could raise a
* Regexp::TimeoutError so we want to protect it from leaking memory. */
if (rb_reg_match_time_limit) {
int state;
rb_protect(rb_reg_onig_match_try, (VALUE)&args, &state);
if (state) {
onig_region_free(&args.regs, false);
rb_jump_tag(state);
}
}
else {
rb_reg_onig_match_try((VALUE)&args);
}

OnigPosition result = rb_reg_onig_match(re, str, reg_onig_search, &args, &regs);
if (result == ONIG_MISMATCH) {
if (args.result == ONIG_MISMATCH) {
rb_backref_set(Qnil);
return ONIG_MISMATCH;
}

VALUE match = match_alloc(rb_cMatch);
rb_matchext_t *rm = RMATCH_EXT(match);
rm->regs = regs;
rm->regs = args.regs;

if (set_backref_str) {
RB_OBJ_WRITE(match, &RMATCH(match)->str, rb_str_new4(str));
Expand All @@ -1774,7 +1810,7 @@ rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_back
rb_backref_set(match);
if (set_match) *set_match = match;

return result;
return args.result;
}

long
Expand Down Expand Up @@ -4601,9 +4637,6 @@ re_warn(const char *s)
rb_warn("%s", s);
}

// The process-global timeout for regexp matching
rb_hrtime_t rb_reg_match_time_limit = 0;

// This function is periodically called during regexp matching
bool
rb_reg_timeout_p(regex_t *reg, void *end_time_)
Expand Down
0