summaryrefslogtreecommitdiff
path: root/string.c
diff options
context:
space:
mode:
authornagachika <nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-07-01 19:09:29 +0000
committernagachika <nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-07-01 19:09:29 +0000
commit840a4573af4477f699714030d7f5191796d591d7 (patch)
treeb2c1133e49685ebac42d95bae0da382aef0f52f7 /string.c
parent62586a95d39a92d7c96b711919955b72c8ac5ecf (diff)
merge revision(s) 55427: [Backport #12503]
* string.c (tr_trans): consider terminator length and fix heap overflow. reported by Guido Vranken <guido AT guidovranken.nl>. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_3@55561 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'string.c')
-rw-r--r--string.c18
1 files changed, 10 insertions, 8 deletions
diff --git a/string.c b/string.c
index bc27b8cfdd..318acf38ff 100644
--- a/string.c
+++ b/string.c
@@ -5981,6 +5981,7 @@ tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
char *s, *send;
VALUE hash = 0;
int singlebyte = single_byte_optimizable(str);
+ int termlen;
int cr;
#define CHECK_IF_ASCII(c) \
@@ -6062,11 +6063,12 @@ tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
cr = ENC_CODERANGE_7BIT;
str_modify_keep_cr(str);
s = RSTRING_PTR(str); send = RSTRING_END(str);
+ termlen = rb_enc_mbminlen(enc);
if (sflag) {
int clen, tlen;
long offset, max = RSTRING_LEN(str);
unsigned int save = -1;
- char *buf = ALLOC_N(char, max), *t = buf;
+ char *buf = ALLOC_N(char, max + termlen), *t = buf;
while (s < send) {
int may_modify = 0;
@@ -6107,7 +6109,7 @@ tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
while (t - buf + tlen >= max) {
offset = t - buf;
max *= 2;
- REALLOC_N(buf, char, max);
+ REALLOC_N(buf, char, max + termlen);
t = buf + offset;
}
rb_enc_mbcput(c, t, enc);
@@ -6120,7 +6122,7 @@ tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
if (!STR_EMBED_P(str)) {
ruby_sized_xfree(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
}
- TERM_FILL(t, rb_enc_mbminlen(enc));
+ TERM_FILL(t, termlen);
RSTRING(str)->as.heap.ptr = buf;
RSTRING(str)->as.heap.len = t - buf;
STR_SET_NOEMBED(str);
@@ -6145,9 +6147,9 @@ tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
}
}
else {
- int clen, tlen, max = (int)(RSTRING_LEN(str) * 1.2);
- long offset;
- char *buf = ALLOC_N(char, max), *t = buf;
+ int clen, tlen;
+ long offset, max = (long)((send - s) * 1.2);
+ char *buf = ALLOC_N(char, max + termlen), *t = buf;
while (s < send) {
int may_modify = 0;
@@ -6180,7 +6182,7 @@ tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
while (t - buf + tlen >= max) {
offset = t - buf;
max *= 2;
- REALLOC_N(buf, char, max);
+ REALLOC_N(buf, char, max + termlen);
t = buf + offset;
}
if (s != t) {
@@ -6196,7 +6198,7 @@ tr_trans(VALUE str, VALUE src, VALUE repl, int sflag)
if (!STR_EMBED_P(str)) {
ruby_sized_xfree(STR_HEAP_PTR(str), STR_HEAP_SIZE(str));
}
- TERM_FILL(t, rb_enc_mbminlen(enc));
+ TERM_FILL(t, termlen);
RSTRING(str)->as.heap.ptr = buf;
RSTRING(str)->as.heap.len = t - buf;
STR_SET_NOEMBED(str);