summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--ext/strscan/strscan.c5
-rw-r--r--include/ruby/re.h1
-rw-r--r--re.c23
4 files changed, 26 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index 7378c95cae..8eb6ba7481 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Tue Dec 2 06:30:55 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * re.c (rb_reg_region_copy): new function to try with GC if copy
+ failed and return the error.
+
Tue Dec 2 04:43:08 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
* re.c (CHECK_REGION_COPIED): onig_region_copy() can fail when
diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c
index eb36cecc47..55d13d413b 100644
--- a/ext/strscan/strscan.c
+++ b/ext/strscan/strscan.c
@@ -251,8 +251,9 @@ strscan_init_copy(VALUE vself, VALUE vorig)
self->str = orig->str;
self->prev = orig->prev;
self->curr = orig->curr;
- onig_region_copy(&self->regs, &orig->regs);
- if (!self->regs.allocated) rb_memerror();
+ if (rb_reg_region_copy(&self->regs, &orig->regs))
+ rb_memerror();
+ RB_GC_GUARD(vorig);
}
return vself;
diff --git a/include/ruby/re.h b/include/ruby/re.h
index 41b3e492f8..166f254aa5 100644
--- a/include/ruby/re.h
+++ b/include/ruby/re.h
@@ -58,6 +58,7 @@ long rb_reg_adjust_startpos(VALUE, VALUE, long, int);
void rb_match_busy(VALUE);
VALUE rb_reg_quote(VALUE);
regex_t *rb_reg_prepare_re(VALUE re, VALUE str);
+int rb_reg_region_copy(struct re_registers *, const struct re_registers *);
RUBY_SYMBOL_EXPORT_END
diff --git a/re.c b/re.c
index 39db793b30..1a0f0b182b 100644
--- a/re.c
+++ b/re.c
@@ -20,8 +20,6 @@ VALUE rb_eRegexpError;
typedef char onig_errmsg_buffer[ONIG_MAX_ERROR_MESSAGE_LEN];
#define errcpy(err, msg) strlcpy((err), (msg), ONIG_MAX_ERROR_MESSAGE_LEN)
-#define CHECK_REGION_COPIED(regs) \
- do {if (!(regs)->allocated) rb_memerror();} while (0)
#define BEG(no) (regs->beg[(no)])
#define END(no) (regs->end[(no)])
@@ -877,6 +875,17 @@ match_alloc(VALUE klass)
return (VALUE)match;
}
+int
+rb_reg_region_copy(struct re_registers *to, const struct re_registers *from)
+{
+ onig_region_copy(to, (OnigRegion *)from);
+ if (to->allocated) return 0;
+ rb_gc();
+ onig_region_copy(to, (OnigRegion *)from);
+ if (to->allocated) return 0;
+ return ONIGERR_MEMORY;
+}
+
typedef struct {
long byte_pos;
long char_pos;
@@ -984,8 +993,8 @@ match_init_copy(VALUE obj, VALUE orig)
RMATCH(obj)->regexp = RMATCH(orig)->regexp;
rm = RMATCH(obj)->rmatch;
- onig_region_copy(&rm->regs, RMATCH_REGS(orig));
- CHECK_REGION_COPIED(&rm->regs);
+ if (rb_reg_region_copy(&rm->regs, RMATCH_REGS(orig)))
+ rb_memerror();
if (!RMATCH(orig)->rmatch->char_offset_updated) {
rm->char_offset_updated = 0;
@@ -998,6 +1007,7 @@ match_init_copy(VALUE obj, VALUE orig)
MEMCPY(rm->char_offset, RMATCH(orig)->rmatch->char_offset,
struct rmatch_offset, rm->regs.num_regs);
rm->char_offset_updated = 1;
+ RB_GC_GUARD(orig);
}
return obj;
@@ -1472,10 +1482,11 @@ rb_reg_search0(VALUE re, VALUE str, long pos, int reverse, int set_backref_str)
}
if (NIL_P(match)) {
+ int err;
match = match_alloc(rb_cMatch);
- onig_region_copy(RMATCH_REGS(match), regs);
+ err = rb_reg_region_copy(RMATCH_REGS(match), regs);
onig_region_free(regs, 0);
- CHECK_REGION_COPIED(RMATCH_REGS(match));
+ if (err) rb_memerror();
}
else {
if (rb_safe_level() >= 3)