summaryrefslogtreecommitdiff
path: root/string.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2004-10-27 00:18:08 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2004-10-27 00:18:08 +0000
commitffcc841ffef2bc1a29cd8a59b862bfe45298bfd7 (patch)
treec7e0e4647df9c413b548d972867e2eaa2588bedd /string.c
parentf608d9eadf79461670f533ee297545233e0d42da (diff)
* string.c (str_gsub): use a string object for exception safeness.
[ruby-dev:24601] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@7117 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'string.c')
-rw-r--r--string.c58
1 files changed, 30 insertions, 28 deletions
diff --git a/string.c b/string.c
index 39069c9..5177e63 100644
--- a/string.c
+++ b/string.c
@@ -36,6 +36,17 @@ VALUE rb_cString;
VALUE rb_fs;
+static inline void
+str_mod_check(s, p, len)
+ VALUE s;
+ char *p;
+ long len;
+{
+ if (RSTRING(s)->ptr != p || RSTRING(s)->len != len) {
+ rb_raise(rb_eRuntimeError, "string modified");
+ }
+}
+
static VALUE str_alloc _((VALUE));
static VALUE
str_alloc(klass)
@@ -1997,7 +2008,7 @@ str_gsub(argc, argv, str, bang)
VALUE str;
int bang;
{
- VALUE pat, val, repl, match;
+ VALUE pat, val, repl, match, dest;
struct re_registers *regs;
long beg, n;
long offset, blen, len;
@@ -2026,7 +2037,8 @@ str_gsub(argc, argv, str, bang)
}
blen = RSTRING(str)->len + 30; /* len + margin */
- buf = ALLOC_N(char, blen);
+ dest = rb_str_new5(str, 0, blen);
+ buf = RSTRING(dest)->ptr;
bp = buf;
cp = RSTRING(str)->ptr;
@@ -2037,9 +2049,7 @@ str_gsub(argc, argv, str, bang)
if (iter) {
rb_match_busy(match);
val = rb_obj_as_string(rb_yield(rb_reg_nth_match(0, match)));
- if (RSTRING(str)->ptr == buf) {
- rb_raise(rb_eRuntimeError, "gsub reentered");
- }
+ str_mod_check(dest, buf, blen);
rb_backref_set(match);
}
else {
@@ -2050,7 +2060,9 @@ str_gsub(argc, argv, str, bang)
if (blen < len) {
while (blen < len) blen *= 2;
len = bp - buf;
- REALLOC_N(buf, char, blen);
+ RESIZE_CAPA(dest, blen);
+ RSTRING(dest)->len = blen;
+ buf = RSTRING(dest)->ptr;
bp = buf + len;
}
len = beg - offset; /* copy pre-match substr */
@@ -2076,30 +2088,32 @@ str_gsub(argc, argv, str, bang)
}
if (RSTRING(str)->len > offset) {
len = bp - buf;
- if (blen - len < RSTRING(str)->len - offset + 1) {
- REALLOC_N(buf, char, len + RSTRING(str)->len - offset + 1);
+ if (blen - len < RSTRING(str)->len - offset) {
+ blen = len + RSTRING(str)->len - offset;
+ RESIZE_CAPA(dest, blen);
+ buf = RSTRING(dest)->ptr;
bp = buf + len;
}
memcpy(bp, cp, RSTRING(str)->len - offset);
bp += RSTRING(str)->len - offset;
}
rb_backref_set(match);
+ *bp = '\0';
if (bang) {
if (str_independent(str)) {
free(RSTRING(str)->ptr);
}
FL_UNSET(str, ELTS_SHARED|STR_ASSOC);
+ RSTRING(str)->ptr = buf;
+ RSTRING(str)->aux.capa = blen;
+ RSTRING(dest)->ptr = 0;
+ RSTRING(dest)->len = 0;
}
else {
- VALUE dup = str_alloc(rb_obj_class(str));
-
- OBJ_INFECT(dup, str);
- str = dup;
+ OBJ_INFECT(dest, str);
+ str = dest;
}
- RSTRING(str)->ptr = buf;
- RSTRING(str)->len = len = bp - buf;
- RSTRING(str)->ptr[len] = '\0';
- RSTRING(str)->aux.capa = len;
+ RSTRING(str)->len = bp - buf;
if (tainted) OBJ_TAINT(str);
return str;
@@ -3556,18 +3570,6 @@ rb_f_split(argc, argv)
return rb_str_split_m(argc, argv, uscore_get());
}
-
-static inline void
-str_mod_check(s, p, len)
- VALUE s;
- char *p;
- long len;
-{
- if (RSTRING(s)->ptr != p || RSTRING(s)->len != len) {
- rb_raise(rb_eRuntimeError, "string modified");
- }
-}
-
/*
* call-seq:
* str.each(separator=$/) {|substr| block } => str