From 04739ba61744046ac145b384aa9053429c80142f Mon Sep 17 00:00:00 2001 From: akr Date: Fri, 20 Jun 2008 02:46:17 +0000 Subject: * string.c (rb_memhash): randomize hash to avoid algorithmic complexity attacks. (rb_str_hash): use rb_memhash. * include/ruby/intern.h (rb_reset_random_seed): declared. * thread.c (rb_thread_atfork): call rb_reset_random_seed. * inits.c (rb_call_inits): call Init_RandomSeed at first. * random.c (seed_initialized): defined. (fill_random_seed): extracted from random_seed. (make_seed_value): extracted from random_seed. (rb_f_rand): initialize random seed at first. (initial_seed): defined. (Init_RandomSeed): defined. (Init_RandomSeed2): defined. (rb_reset_random_seed): defined. (Init_Random): call Init_RandomSeed2. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17465 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 22 ++++++++++++++ include/ruby/intern.h | 1 + inits.c | 2 ++ random.c | 76 ++++++++++++++++++++++++++++++++++++++---------- string.c | 12 ++++++-- test/ruby/test_string.rb | 11 +++++++ thread.c | 1 + 7 files changed, 107 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6a2d69eb2b..643f035cc3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +Fri Jun 20 11:07:56 2008 Tanaka Akira + + * string.c (rb_memhash): randomize hash to avoid algorithmic + complexity attacks. + (rb_str_hash): use rb_memhash. + + * include/ruby/intern.h (rb_reset_random_seed): declared. + + * thread.c (rb_thread_atfork): call rb_reset_random_seed. + + * inits.c (rb_call_inits): call Init_RandomSeed at first. + + * random.c (seed_initialized): defined. + (fill_random_seed): extracted from random_seed. + (make_seed_value): extracted from random_seed. + (rb_f_rand): initialize random seed at first. + (initial_seed): defined. + (Init_RandomSeed): defined. + (Init_RandomSeed2): defined. + (rb_reset_random_seed): defined. + (Init_Random): call Init_RandomSeed2. + Wed Jun 18 21:52:38 2008 URABE Shyouhei * array.c (ary_new, rb_ary_initialize, rb_ary_store, diff --git a/include/ruby/intern.h b/include/ruby/intern.h index a6f85482e9..36ae8442bb 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -475,6 +475,7 @@ VALUE rb_range_beg_len(VALUE, long*, long*, long, int); /* random.c */ unsigned long rb_genrand_int32(void); double rb_genrand_real(void); +void rb_reset_random_seed(void); /* re.c */ #define rb_memcmp memcmp int rb_memcicmp(const void*,const void*,long); diff --git a/inits.c b/inits.c index d031fcf08f..5e55d7f69d 100644 --- a/inits.c +++ b/inits.c @@ -38,6 +38,7 @@ void Init_Precision(void); void Init_sym(void); void Init_id(void); void Init_process(void); +void Init_RandomSeed(void); void Init_Random(void); void Init_Range(void); void Init_Rational(void); @@ -58,6 +59,7 @@ void Init_Encoding(void); void rb_call_inits() { + Init_RandomSeed(); Init_sym(); Init_id(); Init_var_tables(); diff --git a/random.c b/random.c index d0849ebc93..83fb16bd94 100644 --- a/random.c +++ b/random.c @@ -199,6 +199,7 @@ rb_genrand_real(void) return genrand_real(); } +static int seed_initialized = 0; static VALUE saved_seed = INT2FIX(0); static VALUE @@ -259,27 +260,21 @@ rand_init(VALUE vseed) return old; } -static VALUE -random_seed(void) +#define DEFAULT_SEED_LEN (4 * sizeof(long)) + +static void +fill_random_seed(char *ptr) { static int n = 0; + unsigned long *seed; struct timeval tv; int fd; struct stat statbuf; + char *buf = (char*)ptr; - int seed_len; - BDIGIT *digits; - unsigned long *seed; - NEWOBJ(big, struct RBignum); - OBJSETUP(big, rb_cBignum, T_BIGNUM); + seed = (unsigned long *)buf; - seed_len = 4 * sizeof(long); - RBIGNUM_SET_SIGN(big, 1); - rb_big_resize((VALUE)big, seed_len / SIZEOF_BDIGITS + 1); - digits = RBIGNUM_DIGITS(big); - seed = (unsigned long *)RBIGNUM_DIGITS(big); - - memset(digits, 0, RBIGNUM_LEN(big) * SIZEOF_BDIGITS); + memset(buf, 0, DEFAULT_SEED_LEN); #ifdef S_ISCHR if ((fd = open("/dev/urandom", O_RDONLY @@ -294,7 +289,7 @@ random_seed(void) #endif )) >= 0) { if (fstat(fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) { - read(fd, seed, seed_len); + read(fd, seed, DEFAULT_SEED_LEN); } close(fd); } @@ -305,6 +300,20 @@ random_seed(void) seed[1] ^= tv.tv_sec; seed[2] ^= getpid() ^ (n++ << 16); seed[3] ^= (unsigned long)&seed; +} + +static VALUE +make_seed_value(char *ptr) +{ + BDIGIT *digits; + NEWOBJ(big, struct RBignum); + OBJSETUP(big, rb_cBignum, T_BIGNUM); + + RBIGNUM_SET_SIGN(big, 1); + rb_big_resize((VALUE)big, DEFAULT_SEED_LEN / SIZEOF_BDIGITS + 1); + digits = RBIGNUM_DIGITS(big); + + MEMCPY((char *)RBIGNUM_DIGITS(big), ptr, char, DEFAULT_SEED_LEN); /* set leading-zero-guard if need. */ digits[RBIGNUM_LEN(big)-1] = digits[RBIGNUM_LEN(big)-2] <= 1 ? 1 : 0; @@ -312,6 +321,14 @@ random_seed(void) return rb_big_norm((VALUE)big); } +static VALUE +random_seed(void) +{ + char buf[DEFAULT_SEED_LEN]; + fill_random_seed(buf); + return make_seed_value(buf); +} + /* * call-seq: * srand(number=0) => old_seed @@ -453,6 +470,9 @@ rb_f_rand(int argc, VALUE *argv, VALUE obj) long val, max; rb_scan_args(argc, argv, "01", &vmax); + if (!seed_initialized) { + rand_init(random_seed()); + } switch (TYPE(vmax)) { case T_FLOAT: if (RFLOAT_VALUE(vmax) <= LONG_MAX && RFLOAT_VALUE(vmax) >= LONG_MIN) { @@ -499,10 +519,34 @@ rb_f_rand(int argc, VALUE *argv, VALUE obj) return LONG2NUM(val); } +static char initial_seed[DEFAULT_SEED_LEN]; + +void +Init_RandomSeed(void) +{ + fill_random_seed(initial_seed); + init_by_array((unsigned long*)initial_seed, DEFAULT_SEED_LEN/sizeof(unsigned long)); + seed_initialized = 1; +} + +static VALUE +Init_RandomSeed2(void) +{ + saved_seed = make_seed_value(initial_seed); + memset(initial_seed, 0, DEFAULT_SEED_LEN); +} + +void +rb_reset_random_seed(void) +{ + seed_initialized = 0; + saved_seed = INT2FIX(0); +} + void Init_Random(void) { - rand_init(random_seed()); + Init_RandomSeed2(); rb_define_global_function("srand", rb_f_srand, -1); rb_define_global_function("rand", rb_f_rand, -1); rb_global_variable(&saved_seed); diff --git a/string.c b/string.c index c19544deac..5c46d61605 100644 --- a/string.c +++ b/string.c @@ -1820,13 +1820,21 @@ hash(const unsigned char * data, int len, unsigned int h) int rb_memhash(const void *ptr, long len) { - return hash(ptr, len, 0); + static int hashseed_init = 0; + static unsigned int hashseed; + + if (!hashseed_init) { + hashseed = rb_genrand_int32(); + hashseed_init = 1; + } + + return hash(ptr, len, hashseed); } int rb_str_hash(VALUE str) { - return hash((const void *)RSTRING_PTR(str), RSTRING_LEN(str), 0); + return rb_memhash((const void *)RSTRING_PTR(str), RSTRING_LEN(str)); } int diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb index 55cef9001e..869e31b641 100644 --- a/test/ruby/test_string.rb +++ b/test/ruby/test_string.rb @@ -683,6 +683,17 @@ class TestString < Test::Unit::TestCase assert(S("hello").hash != S("helLO").hash) end + def test_hash_random + str = 'abc' + a = [str.hash.to_s] + 3.times { + EnvUtil.rubyexec("-e", "print #{str.dump}.hash") {|i,o,e| + a << o.read + } + } + assert_not_equal([str.hash.to_s], a.uniq) + end + def test_hex assert_equal(255, S("0xff").hex) assert_equal(-255, S("-0xff").hex) diff --git a/thread.c b/thread.c index 92f5104dba..13630b6b02 100644 --- a/thread.c +++ b/thread.c @@ -2124,6 +2124,7 @@ rb_thread_atfork(void) st_clear(vm->living_threads); st_insert(vm->living_threads, thval, (st_data_t) th->thread_id); vm->sleeper = 0; + rb_reset_random_seed(); } static int -- cgit v1.2.3 From 6b33d77c4be3d5471be60f95ec65f94aaab2dd4f Mon Sep 17 00:00:00 2001 From: matz Date: Fri, 20 Jun 2008 03:14:23 +0000 Subject: * string.c (rb_str_sub_bang): should preserve replacement points since they may be altered in the yielded block. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17466 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 5 +++++ string.c | 20 +++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 643f035cc3..501d439e29 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Fri Jun 20 11:57:46 2008 Yukihiro Matsumoto + + * string.c (rb_str_sub_bang): should preserve replacement points + since they may be altered in the yielded block. + Fri Jun 20 11:07:56 2008 Tanaka Akira * string.c (rb_memhash): randomize hash to avoid algorithmic diff --git a/string.c b/string.c index 5c46d61605..c683fa1b86 100644 --- a/string.c +++ b/string.c @@ -3121,6 +3121,8 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str) int cr = ENC_CODERANGE(str); VALUE match = rb_backref_get(); struct re_registers *regs = RMATCH_REGS(match); + long beg0 = BEG(0); + long end0 = END(0); if (iter || !NIL_P(hash)) { char *p = RSTRING_PTR(str); long len = RSTRING_LEN(str); @@ -3129,7 +3131,7 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str) repl = rb_obj_as_string(rb_yield(rb_reg_nth_match(0, match))); } else { - repl = rb_hash_aref(hash, rb_str_subseq(str, BEG(0), END(0) - BEG(0))); + repl = rb_hash_aref(hash, rb_str_subseq(str, beg0, end0 - beg0)); repl = rb_obj_as_string(repl); } str_mod_check(str, p, len); @@ -3141,9 +3143,9 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str) enc = rb_enc_compatible(str, repl); if (!enc) { rb_encoding *str_enc = STR_ENC_GET(str); - if (coderange_scan(RSTRING_PTR(str), BEG(0), str_enc) != ENC_CODERANGE_7BIT || - coderange_scan(RSTRING_PTR(str)+END(0), - RSTRING_LEN(str)-END(0), str_enc) != ENC_CODERANGE_7BIT) { + if (coderange_scan(RSTRING_PTR(str), beg0, str_enc) != ENC_CODERANGE_7BIT || + coderange_scan(RSTRING_PTR(str)+end0, + RSTRING_LEN(str)-end0, str_enc) != ENC_CODERANGE_7BIT) { rb_raise(rb_eArgError, "character encodings differ: %s and %s", rb_enc_name(str_enc), rb_enc_name(STR_ENC_GET(repl))); @@ -3157,16 +3159,16 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str) int cr2 = ENC_CODERANGE(repl); if (cr2 == ENC_CODERANGE_UNKNOWN || cr2 > cr) cr = cr2; } - plen = END(0) - BEG(0); + plen = end0 - beg0; if (RSTRING_LEN(repl) > plen) { RESIZE_CAPA(str, RSTRING_LEN(str) + RSTRING_LEN(repl) - plen); } if (RSTRING_LEN(repl) != plen) { - memmove(RSTRING_PTR(str) + BEG(0) + RSTRING_LEN(repl), - RSTRING_PTR(str) + BEG(0) + plen, - RSTRING_LEN(str) - BEG(0) - plen); + memmove(RSTRING_PTR(str) + beg0 + RSTRING_LEN(repl), + RSTRING_PTR(str) + beg0 + plen, + RSTRING_LEN(str) - beg0 - plen); } - memcpy(RSTRING_PTR(str) + BEG(0), + memcpy(RSTRING_PTR(str) + beg0, RSTRING_PTR(repl), RSTRING_LEN(repl)); STR_SET_LEN(str, RSTRING_LEN(str) + RSTRING_LEN(repl) - plen); RSTRING_PTR(str)[RSTRING_LEN(str)] = '\0'; -- cgit v1.2.3 From feb400081b5411213e7fe6f653c9be92891edfef Mon Sep 17 00:00:00 2001 From: nobu Date: Fri, 20 Jun 2008 03:19:38 +0000 Subject: * tool/make-snapshot: fixed typo. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17467 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- tool/make-snapshot | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tool/make-snapshot b/tool/make-snapshot index 71c83956b4..92a30323fe 100755 --- a/tool/make-snapshot +++ b/tool/make-snapshot @@ -34,9 +34,10 @@ for rev; do tag= case "$rev" in trunk | branches/* | tags/*) - url=$SVNURL/rev;; + url=$SVNURL/$rev;; stable) - url=$SVNURL/brances/$(svn ls $SVNURL/branches | grep '^ruby_[0-9]_[0-9]/' | tail -1);; + url=$SVNURL/branches + url=/$(svn ls $url | grep '^ruby_[0-9]_[0-9]/' | tail -1);; *.*.*-p* | *.*.*-*) tag=${rev##*-}; url=${rev/-p/_}; url=${url/-/_}; url=$SVNURL/tags/v${url//./_};; *.*) -- cgit v1.2.3 From 79bb49b61ba9a614a401e22b4563a5ee7e2a5725 Mon Sep 17 00:00:00 2001 From: nobu Date: Fri, 20 Jun 2008 03:29:19 +0000 Subject: * random.c (Init_RandomSeed2): should be void. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- random.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/random.c b/random.c index 83fb16bd94..921ec7c52d 100644 --- a/random.c +++ b/random.c @@ -529,7 +529,7 @@ Init_RandomSeed(void) seed_initialized = 1; } -static VALUE +static void Init_RandomSeed2(void) { saved_seed = make_seed_value(initial_seed); -- cgit v1.2.3 From a54cbe65a9e35fdea4f9989017dcd87ebb2e68a7 Mon Sep 17 00:00:00 2001 From: nobu Date: Fri, 20 Jun 2008 03:40:02 +0000 Subject: * process.c (rb_detach_process): store detached process ID in the thread local storage. moved from lib/open3.rb. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17469 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 5 +++++ lib/open3.rb | 1 - process.c | 19 ++++++++++++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 501d439e29..48e976557a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Fri Jun 20 12:39:55 2008 Nobuyoshi Nakada + + * process.c (rb_detach_process): store detached process ID in the + thread local storage. moved from lib/open3.rb. + Fri Jun 20 11:57:46 2008 Yukihiro Matsumoto * string.c (rb_str_sub_bang): should preserve replacement points diff --git a/lib/open3.rb b/lib/open3.rb index f707f55409..d776de7445 100644 --- a/lib/open3.rb +++ b/lib/open3.rb @@ -66,7 +66,6 @@ module Open3 pid = spawn(*cmd, STDIN=>pw[0], STDOUT=>pr[1], STDERR=>pe[1]) wait_thr = Process.detach(pid) - wait_thr[:pid] = pid pw[0].close pr[1].close pe[1].close diff --git a/process.c b/process.c index ee0bbaf4d5..94dc712c8f 100644 --- a/process.c +++ b/process.c @@ -885,6 +885,20 @@ proc_waitall(void) return result; } +static inline ID +id_pid(void) +{ + ID pid; + CONST_ID(pid, "pid"); + return pid; +} + +static VALUE +detach_process_pid(VALUE thread) +{ + return rb_thread_local_aref(thread, id_pid()); +} + static VALUE detach_process_watcher(void *arg) { @@ -900,7 +914,10 @@ detach_process_watcher(void *arg) VALUE rb_detach_process(rb_pid_t pid) { - return rb_thread_create(detach_process_watcher, (void*)(VALUE)pid); + VALUE watcher = rb_thread_create(detach_process_watcher, (void*)(VALUE)pid); + rb_thread_local_aset(watcher, id_pid(), PIDT2NUM(pid)); + rb_define_singleton_method(watcher, "pid", detach_process_pid, 0); + return watcher; } -- cgit v1.2.3 From 72dd5fdc47e1ec78055cd4028b032ea62d50d8c9 Mon Sep 17 00:00:00 2001 From: nobu Date: Fri, 20 Jun 2008 06:40:10 +0000 Subject: * array.c (rb_ary_store, rb_ary_splice): not depend on unspecified behavior at integer overflow. * string.c (str_buf_cat): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17471 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ChangeLog b/ChangeLog index 48e976557a..33d73196f8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Fri Jun 20 15:40:02 2008 Nobuyoshi Nakada + + * array.c (rb_ary_store, rb_ary_splice): not depend on unspecified + behavior at integer overflow. + + * string.c (str_buf_cat): ditto. + Fri Jun 20 12:39:55 2008 Nobuyoshi Nakada * process.c (rb_detach_process): store detached process ID in the -- cgit v1.2.3 From e1a45b10b6165c8fec505180a52c4ce58fb21e91 Mon Sep 17 00:00:00 2001 From: nobu Date: Fri, 20 Jun 2008 06:42:07 +0000 Subject: * array.c (rb_ary_store, rb_ary_splice): not depend on unspecified behavior at integer overflow. * string.c (str_buf_cat): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@17472 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- array.c | 6 +++--- string.c | 70 +++++++++++++++++++++++++--------------------------------------- 2 files changed, 30 insertions(+), 46 deletions(-) diff --git a/array.c b/array.c index 46fd050669..783e5a5e39 100644 --- a/array.c +++ b/array.c @@ -383,7 +383,7 @@ rb_ary_store(VALUE ary, long idx, VALUE val) if (new_capa < ARY_DEFAULT_SIZE) { new_capa = ARY_DEFAULT_SIZE; } - else if (new_capa >= ARY_MAX_SIZE - idx) { + if (new_capa >= ARY_MAX_SIZE - idx) { new_capa = (ARY_MAX_SIZE - idx) / 2; } new_capa += idx; @@ -986,10 +986,10 @@ rb_ary_splice(VALUE ary, long beg, long len, VALUE rpl) } rb_ary_modify(ary); if (beg >= RARRAY_LEN(ary)) { - len = beg + rlen; - if (len < 0 || len > ARY_MAX_SIZE) { + if (beg > ARY_MAX_SIZE - rlen) { rb_raise(rb_eIndexError, "index %ld too big", beg); } + len = beg + rlen; if (len >= ARY_CAPA(ary)) { RESIZE_CAPA(ary, len); } diff --git a/string.c b/string.c index c683fa1b86..30143593bf 100644 --- a/string.c +++ b/string.c @@ -1394,16 +1394,16 @@ rb_str_resize(VALUE str, long len) return str; } -VALUE -rb_str_buf_cat(VALUE str, const char *ptr, long len) +static long +str_buf_cat(VALUE str, const char *ptr, long len) { - long capa, total; + long capa, total, off = -1; - if (len == 0) return str; - if (len < 0) { - rb_raise(rb_eArgError, "negative string size (or size too big)"); + if (ptr >= RSTRING_PTR(str) && ptr <= RSTRING_END(str)) { + off = ptr - RSTRING_PTR(str); } rb_str_modify(str); + if (len == 0) return 0; if (STR_ASSOC_P(str)) { FL_UNSET(str, STR_ASSOC); capa = RSTRING(str)->as.heap.aux.capa = RSTRING_LEN(str); @@ -1414,13 +1414,23 @@ rb_str_buf_cat(VALUE str, const char *ptr, long len) else { capa = RSTRING(str)->as.heap.aux.capa; } + if (RSTRING_LEN(str) >= LONG_MAX - len) { + rb_raise(rb_eArgError, "string sizes too big"); + } total = RSTRING_LEN(str)+len; if (capa <= total) { while (total > capa) { + if (capa + 1 >= LONG_MAX / 2) { + capa = (total + 4095) / 4096; + break; + } capa = (capa + 1) * 2; } RESIZE_CAPA(str, capa); } + if (off != -1) { + ptr = RSTRING_PTR(str) + off; + } memcpy(RSTRING_PTR(str) + RSTRING_LEN(str), ptr, len); STR_SET_LEN(str, total); RSTRING_PTR(str)[total] = '\0'; /* sentinel */ @@ -1428,6 +1438,16 @@ rb_str_buf_cat(VALUE str, const char *ptr, long len) return str; } +VALUE +rb_str_buf_cat(VALUE str, const char *ptr, long len) +{ + if (len == 0) return str; + if (len < 0) { + rb_raise(rb_eArgError, "negative string size (or size too big)"); + } + return str_buf_cat(str, ptr, len); +} + VALUE rb_str_buf_cat2(VALUE str, const char *ptr) { @@ -1463,8 +1483,6 @@ static VALUE rb_enc_cr_str_buf_cat(VALUE str, const char *ptr, long len, int ptr_encindex, int ptr_cr, int *ptr_cr_ret) { - long capa, total, off = -1; - int str_encindex = ENCODING_GET(str); int res_encindex; int str_cr, res_cr; @@ -1543,41 +1561,7 @@ rb_enc_cr_str_buf_cat(VALUE str, const char *ptr, long len, if (len < 0) { rb_raise(rb_eArgError, "negative string size (or size too big)"); } - if (ptr >= RSTRING_PTR(str) && ptr <= RSTRING_END(str)) { - off = ptr - RSTRING_PTR(str); - } - rb_str_modify(str); - if (len == 0) { - ENCODING_CODERANGE_SET(str, res_encindex, res_cr); - return str; - } - if (STR_ASSOC_P(str)) { - FL_UNSET(str, STR_ASSOC); - capa = RSTRING(str)->as.heap.aux.capa = RSTRING_LEN(str); - } - else if (STR_EMBED_P(str)) { - capa = RSTRING_EMBED_LEN_MAX; - } - else { - capa = RSTRING(str)->as.heap.aux.capa; - } - total = RSTRING_LEN(str)+len; - if (total < 0 || capa + 1 > LONG_MAX / 2) { - rb_raise(rb_eArgError, "string sizes too big"); - } - if (capa <= total) { - while (total > capa) { - capa = (capa + 1) * 2; - } - RESIZE_CAPA(str, capa); - } - if (off != -1) { - ptr = RSTRING_PTR(str) + off; - } - memcpy(RSTRING_PTR(str) + RSTRING_LEN(str), ptr, len); - STR_SET_LEN(str, total); - RSTRING_PTR(str)[total] = '\0'; /* sentinel */ - + str_buf_cat(str, ptr, len); ENCODING_CODERANGE_SET(str, res_encindex, res_cr); return str; } -- cgit v1.2.3