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.
This commit is contained in:
parent
1c120efe02
commit
01bfd1a2bf
51
re.c
51
re.c
@ -88,6 +88,9 @@ static const char casetable[] = {
|
|||||||
# error >>> "You lose. You will need a translation table for your character set." <<<
|
# error >>> "You lose. You will need a translation table for your character set." <<<
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// The process-global timeout for regexp matching
|
||||||
|
rb_hrtime_t rb_reg_match_time_limit = 0;
|
||||||
|
|
||||||
int
|
int
|
||||||
rb_memcicmp(const void *x, const void *y, long len)
|
rb_memcicmp(const void *x, const void *y, long len)
|
||||||
{
|
{
|
||||||
@ -1732,6 +1735,23 @@ reg_onig_search(regex_t *reg, VALUE str, struct re_registers *regs, void *args_p
|
|||||||
ONIG_OPTION_NONE);
|
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 */
|
/* returns byte offset */
|
||||||
static long
|
static long
|
||||||
rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_backref_str, VALUE *set_match)
|
rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_backref_str, VALUE *set_match)
|
||||||
@ -1742,22 +1762,38 @@ rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_back
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct reg_onig_search_args args = {
|
struct rb_reg_onig_match_args args = {
|
||||||
|
.re = re,
|
||||||
|
.str = str,
|
||||||
|
.args = {
|
||||||
.pos = pos,
|
.pos = pos,
|
||||||
.range = reverse ? 0 : len,
|
.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, ®s);
|
if (args.result == ONIG_MISMATCH) {
|
||||||
if (result == ONIG_MISMATCH) {
|
|
||||||
rb_backref_set(Qnil);
|
rb_backref_set(Qnil);
|
||||||
return ONIG_MISMATCH;
|
return ONIG_MISMATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE match = match_alloc(rb_cMatch);
|
VALUE match = match_alloc(rb_cMatch);
|
||||||
rb_matchext_t *rm = RMATCH_EXT(match);
|
rb_matchext_t *rm = RMATCH_EXT(match);
|
||||||
rm->regs = regs;
|
rm->regs = args.regs;
|
||||||
|
|
||||||
if (set_backref_str) {
|
if (set_backref_str) {
|
||||||
RB_OBJ_WRITE(match, &RMATCH(match)->str, rb_str_new4(str));
|
RB_OBJ_WRITE(match, &RMATCH(match)->str, rb_str_new4(str));
|
||||||
@ -1774,7 +1810,7 @@ rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_back
|
|||||||
rb_backref_set(match);
|
rb_backref_set(match);
|
||||||
if (set_match) *set_match = match;
|
if (set_match) *set_match = match;
|
||||||
|
|
||||||
return result;
|
return args.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
long
|
long
|
||||||
@ -4601,9 +4637,6 @@ re_warn(const char *s)
|
|||||||
rb_warn("%s", 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
|
// This function is periodically called during regexp matching
|
||||||
bool
|
bool
|
||||||
rb_reg_timeout_p(regex_t *reg, void *end_time_)
|
rb_reg_timeout_p(regex_t *reg, void *end_time_)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user