Hi, based on matz's recomendations I made new version. (Massive deletes are because matz said "discard".) Michal PS: Personally I think that to have more checks is not as bad. (I'm not so much OK with, "It is assured, so don't check it." I'm little worried about future...) Index: string.c =================================================================== RCS file: /src/ruby/string.c,v retrieving revision 1.117 diff -u -p -r1.117 string.c --- string.c 2002/09/03 05:20:06 1.117 +++ string.c 2002/09/09 11:54:41 @@ -61,18 +61,18 @@ str_new(klass, ptr, len) if (len < 0) { rb_raise(rb_eArgError, "negative string size (or size too big)"); } - str = rb_obj_alloc(klass); RSTRING(str)->len = len; RSTRING(str)->aux.capa = len; RSTRING(str)->ptr = ALLOC_N(char,len+1); + if (ptr) { memcpy(RSTRING(str)->ptr, ptr, len); + RSTRING(str)->ptr[len] = '\0'; } else { - MEMZERO(RSTRING(str)->ptr, char, len); + MEMZERO(RSTRING(str)->ptr, char, len+1); } - RSTRING(str)->ptr[len] = '\0'; return str; } @@ -218,28 +218,18 @@ rb_str_shared_replace(str, str2) { if (str == str2) return; if (!FL_TEST(str, ELTS_SHARED)) free(RSTRING(str)->ptr); - if (NIL_P(str2)) { - RSTRING(str)->ptr = 0; - RSTRING(str)->len = 0; - RSTRING(str)->aux.capa = 0; - return; - } + RSTRING(str)->ptr = RSTRING(str2)->ptr; RSTRING(str)->len = RSTRING(str2)->len; - if (FL_TEST(str2, ELTS_SHARED|STR_ASSOC)) { - FL_SET(str, RBASIC(str2)->flags & (ELTS_SHARED|STR_ASSOC)); - RSTRING(str)->aux.shared = RSTRING(str2)->aux.shared; - } - else { - RSTRING(str)->aux.capa = RSTRING(str2)->aux.capa; - } + RSTRING(str)->aux.capa = RSTRING(str2)->aux.capa; RSTRING(str2)->ptr = 0; /* abandon str2 */ RSTRING(str2)->len = 0; RSTRING(str2)->aux.capa = 0; - FL_UNSET(str, ELTS_SHARED|STR_ASSOC); if (OBJ_TAINTED(str2)) OBJ_TAINT(str); } +void str_make_independent _((VALUE)); + void rb_str_associate(str, add) VALUE str, add; @@ -250,16 +240,12 @@ rb_str_associate(str, add) } else { if (FL_TEST(str, ELTS_SHARED)) { - rb_str_modify(str); + str_make_independent(str); } - else if (RSTRING(str)->aux.shared) { - /* str_buf */ - if (RSTRING(str)->aux.capa != RSTRING(str)->len) { - RESIZE_CAPA(str, RSTRING(str)->len); - } + if (RSTRING(str)->aux.capa != RSTRING(str)->len) { + RESIZE_CAPA(str, RSTRING(str)->len); } RSTRING(str)->aux.shared = add; - FL_UNSET(str, ELTS_SHARED); FL_SET(str, STR_ASSOC); } } @@ -398,30 +384,42 @@ rb_str_format(str, arg) return rb_f_sprintf(2, argv); } -static int -str_independent(str) +void +rb_str_modify_check(str) VALUE str; { if (OBJ_FROZEN(str)) rb_error_frozen("string"); - if (!OBJ_TAINTED(str) && rb_safe_level() >= 4) + if (!OBJ_TAINTED(str) && rb_safe_level() >= 4) { rb_raise(rb_eSecurityError, "Insecure: can't modify string"); + } +} + +int +str_independent(str) + VALUE str; +{ + rb_str_modify_check(str); if (!FL_TEST(str, ELTS_SHARED)) return 1; return 0; } -static void +void str_make_independent(str) VALUE str; { char *ptr; + long len = RSTRING(str)->len; - ptr = ALLOC_N(char, RSTRING(str)->len+1); + ptr = ALLOC_N(char, len+1); if (RSTRING(str)->ptr) { - memcpy(ptr, RSTRING(str)->ptr, RSTRING(str)->len); + memcpy(ptr, RSTRING(str)->ptr, len); + ptr[len] = '\0'; + } + else { + MEMZERO(ptr, char, len+1); } - ptr[RSTRING(str)->len] = 0; RSTRING(str)->ptr = ptr; - RSTRING(str)->aux.capa = RSTRING(str)->len; + RSTRING(str)->aux.capa = len; FL_UNSET(str, ELTS_SHARED|STR_ASSOC); } @@ -532,10 +530,18 @@ rb_str_buf_cat(str, ptr, len) { long capa, total; - if (FL_TEST(str, ELTS_SHARED)) { - rb_str_modify(str); + if (len < 0) { + rb_raise(rb_eArgError, "negative string size (or size too big)"); + } + if (len == 0) return str; + rb_str_modify(str); + if (FL_TEST(str, STR_ASSOC)) { + FL_UNSET(str, STR_ASSOC); + capa = RSTRING(str)->len; } - capa = RSTRING(str)->aux.capa; + else { + capa = RSTRING(str)->aux.capa; + } total = RSTRING(str)->len+len; if (capa <= total) { while (total > capa) { @@ -564,23 +570,7 @@ rb_str_cat(str, ptr, len) const char *ptr; long len; { - rb_str_modify(str); - if (len > 0) { - if (!FL_TEST(str, ELTS_SHARED) && !FL_TEST(str, STR_ASSOC)) { - return rb_str_buf_cat(str, ptr, len); - } - RESIZE_CAPA(str, RSTRING(str)->len + len); - if (ptr) { - memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len); - } - else { - MEMZERO(RSTRING(str)->ptr + RSTRING(str)->len, char, len); - } - RSTRING(str)->len += len; - RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */ - } - - return str; + return rb_str_buf_cat(str, ptr, len); } VALUE @@ -597,12 +587,16 @@ rb_str_buf_append(str, str2) { long capa, len; - if (FL_TEST(str, ELTS_SHARED)) { - rb_str_modify(str); + rb_str_modify(str); + if (FL_TEST(str, STR_ASSOC)) { + FL_UNSET(str, STR_ASSOC); + capa = RSTRING(str)->len; } - capa = RSTRING(str)->aux.capa; - + else { + capa = RSTRING(str)->aux.capa; + } len = RSTRING(str)->len+RSTRING(str2)->len; + if (capa <= len) { while (len > capa) { capa = (capa + 1) * 2; @@ -621,25 +615,11 @@ VALUE rb_str_append(str, str2) VALUE str, str2; { - long len; - StringValue(str2); - rb_str_modify(str); - if (RSTRING(str2)->len > 0) { - len = RSTRING(str)->len+RSTRING(str2)->len; - if (!FL_TEST(str, ELTS_SHARED) && !FL_TEST(str, STR_ASSOC)) { - rb_str_buf_append(str, str2); - OBJ_INFECT(str, str2); - return str; - } - RESIZE_CAPA(str, len); - memcpy(RSTRING(str)->ptr + RSTRING(str)->len, - RSTRING(str2)->ptr, RSTRING(str2)->len); - RSTRING(str)->len += RSTRING(str2)->len; - RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */ - } - OBJ_INFECT(str, str2); + rb_str_buf_append(str, str2); + + OBJ_INFECT(str, str2); return str; } @@ -1599,6 +1579,7 @@ rb_str_gsub_bang(argc, argv, str) VALUE *argv; VALUE str; { + rb_str_modify_check(str); return str_gsub(argc, argv, str, 1); } @@ -1617,23 +1598,27 @@ rb_str_replace(str, str2) { if (str == str2) return str; + rb_str_modify_check(str); StringValue(str2); + if (FL_TEST(str2, ELTS_SHARED)) { - if (str_independent(str)) { + if (!FL_TEST(str, ELTS_SHARED)) { free(RSTRING(str)->ptr); } RSTRING(str)->len = RSTRING(str2)->len; RSTRING(str)->ptr = RSTRING(str2)->ptr; - FL_SET(str, RBASIC(str2)->flags & (ELTS_SHARED|STR_ASSOC)); RSTRING(str)->aux.shared = RSTRING(str2)->aux.shared; + FL_SET(str, ELTS_SHARED); } else { - rb_str_modify(str); + if (FL_TEST(str, ELTS_SHARED)) { + str_make_independent(str); + } rb_str_resize(str, RSTRING(str2)->len); memcpy(RSTRING(str)->ptr, RSTRING(str2)->ptr, RSTRING(str2)->len); if (FL_TEST(str2, STR_ASSOC)) { - FL_SET(str, RBASIC(str2)->flags & (ELTS_SHARED|STR_ASSOC)); RSTRING(str)->aux.shared = RSTRING(str2)->aux.shared; + FL_SET(str, STR_ASSOC); } } @@ -2293,6 +2278,7 @@ rb_str_delete_bang(argc, argv, str) if (argc < 1) { rb_raise(rb_eArgError, "wrong number of arguments"); } + rb_str_modify(str); for (i=0; i<argc; i++) { VALUE s = argv[i]; @@ -2300,8 +2286,6 @@ rb_str_delete_bang(argc, argv, str) tr_setup_table(s, squeez, init); init = 0; } - - rb_str_modify(str); s = t = RSTRING(str)->ptr; if (!s || RSTRING(str)->len == 0) return Qnil; send = s + RSTRING(str)->len; @@ -2342,6 +2326,7 @@ rb_str_squeeze_bang(argc, argv, str) int init = 1; int i; + rb_str_modify(str); if (argc == 0) { for (i=0; i<256; i++) { squeez[i] = 1; @@ -2356,8 +2341,6 @@ rb_str_squeeze_bang(argc, argv, str) init = 0; } } - - rb_str_modify(str); s = t = RSTRING(str)->ptr; if (!s || RSTRING(str)->len == 0) return Qnil; send = s + RSTRING(str)->len; -- -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Michal Rokos Czech Technical University, Prague E-mail:m.rokos / sh.cvut.cz ICQ:36118339 Jabber:majkl / jabber.cz -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-