diff --git a/ChangeLog b/ChangeLog index 7479d1507e..77153b1eab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -66,6 +66,26 @@ Wed Sep 11 00:41:10 2002 Nobuyoshi Nakada * eval.c (rb_mod_define_method): initialize orig_func too. (ruby-bugs-ja:PR#330) +Wed Sep 11 00:01:32 2002 Yukihiro Matsumoto + + * dir.c (glob_helper): prevent memory leak using rb_protect(). + + * string.c (rb_str_associate): no need to check freeze flag. + + * string.c (rb_str_resize): should honor STR_ASSOC flag on + resize. + + * string.c (rb_str_resize): proper STR_ASSOC handling. pointed + out by Michal Rokos. + + * string.c (rb_str_buf_cat): ditto. + + * string.c (rb_str_cat): ditto. + + * string.c (rb_str_buf_append): ditto. + + * string.c (rb_str_append): ditto. + Tue Sep 10 23:35:46 2002 Nobuyoshi Nakada * parse.y (nextc): restore line number after here documents. diff --git a/dir.c b/dir.c index 5f6e707a81..72ce949b24 100644 --- a/dir.c +++ b/dir.c @@ -653,7 +653,38 @@ remove_backslashes(p) # define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) #endif -static void +struct glob_args { + void (*func) _((const char*, VALUE)); + const char *c; + VALUE v; +}; + +static VALUE +glob_func_caller(args) + struct glob_args *args; +{ + (*args->func)(args->c, args->v); + return Qnil; +} + +static int +glob_call_func(func, path, arg) + void (*func) _((const char*, VALUE)); + const char *path; + VALUE arg; +{ + int status; + struct glob_args args; + + args.func = func; + args.c = path; + args.v = arg; + + rb_protect(glob_func_caller, (VALUE)&args, &status); + return status; +} + +static int glob_helper(path, sub, flags, func, arg) char *path; char *sub; @@ -663,6 +694,7 @@ glob_helper(path, sub, flags, func, arg) { struct stat st; char *p, *m; + int status = 0; p = sub ? sub : path; if (!has_magic(p, 0, flags)) { @@ -672,17 +704,18 @@ glob_helper(path, sub, flags, func, arg) if (!(flags & FNM_NOESCAPE)) remove_backslashes(p); #endif if (lstat(path, &st) == 0) { - (*func)(path, arg); + status = glob_call_func(func, path, arg); + if (status) return status; } else if (errno != ENOENT) { /* In case stat error is other than ENOENT and we may want to know what is wrong. */ rb_sys_warning(path); } - return; + return 0; } - while (p) { + while (p && !status) { if (*p == '/') p++; m = strchr(p, '/'); if (has_magic(p, m, flags)) { @@ -704,6 +737,7 @@ glob_helper(path, sub, flags, func, arg) if (stat(dir, &st) < 0) { if (errno != ENOENT) rb_sys_warning(dir); free(base); + free(magic); break; } if (S_ISDIR(st.st_mode)) { @@ -712,18 +746,21 @@ glob_helper(path, sub, flags, func, arg) recursive = 1; buf = ALLOC_N(char, n+strlen(m)+3); sprintf(buf, "%s%s", base, *base ? m : m+1); - glob_helper(buf, buf+n, flags, func, arg); + status = glob_helper(buf, buf+n, flags, func, arg); free(buf); + if (status) goto finalize; } dirp = opendir(dir); if (dirp == NULL) { rb_sys_warning(dir); free(base); + free(magic); break; } } else { free(base); + free(magic); break; } @@ -747,7 +784,9 @@ glob_helper(path, sub, flags, func, arg) char *t = buf+strlen(buf); strcpy(t, "/**"); strcpy(t+3, m); - glob_helper(buf, t, flags, func, arg); + status = glob_helper(buf, t, flags, func, arg); + free(buf); + if (status) goto finalize; } free(buf); continue; @@ -756,8 +795,8 @@ glob_helper(path, sub, flags, func, arg) buf = ALLOC_N(char, strlen(base)+NAMLEN(dp)+2); sprintf(buf, "%s%s%s", base, (BASE) ? "/" : "", dp->d_name); if (!m) { - (*func)(buf, arg); - free(buf); + status = glob_call_func(func, path, arg); + if (status) goto finalize; continue; } tmp = ALLOC(struct d_link); @@ -766,24 +805,27 @@ glob_helper(path, sub, flags, func, arg) link = tmp; } } + finalize: closedir(dirp); free(base); free(magic); if (link) { while (link) { - if (stat(link->path, &st) == 0) { - if (S_ISDIR(st.st_mode)) { - int len = strlen(link->path); - int mlen = strlen(m); - char *t = ALLOC_N(char, len+mlen+1); + if (status == 0) { + if (stat(link->path, &st) == 0) { + if (S_ISDIR(st.st_mode)) { + int len = strlen(link->path); + int mlen = strlen(m); + char *t = ALLOC_N(char, len+mlen+1); - sprintf(t, "%s%s", link->path, m); - glob_helper(t, t+len, flags, func, arg); - free(t); + sprintf(t, "%s%s", link->path, m); + status = glob_helper(t, t+len, flags, func, arg); + free(t); + } + } + else { + rb_sys_warning(link->path); } - } - else { - rb_sys_warning(link->path); } tmp = link; link = link->next; @@ -795,6 +837,7 @@ glob_helper(path, sub, flags, func, arg) } p = m; } + return status; } static void @@ -804,7 +847,8 @@ rb_glob2(path, flags, func, arg) void (*func) _((const char*, VALUE)); VALUE arg; { - glob_helper(path, 0, flags, func, arg); + int status = glob_helper(path, 0, flags, func, arg); + if (status) rb_jump_tag(status); } void diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb index bc9cb0676f..736a12fd26 100644 --- a/ext/tk/lib/tk.rb +++ b/ext/tk/lib/tk.rb @@ -2841,6 +2841,7 @@ class TkWindowptr = 0; /* abandon str2 */ RSTRING(str2)->len = 0; RSTRING(str2)->aux.capa = 0; - FL_UNSET(str, ELTS_SHARED|STR_ASSOC); + FL_UNSET(str2, ELTS_SHARED|STR_ASSOC); if (OBJ_TAINTED(str2)) OBJ_TAINT(str); } -void -rb_str_associate(str, add) - VALUE str, add; -{ - if (FL_TEST(str, STR_ASSOC)) { - /* already associated */ - rb_ary_concat(RSTRING(str)->aux.shared, add); - } - else { - if (FL_TEST(str, ELTS_SHARED)) { - rb_str_modify(str); - } - else if (RSTRING(str)->aux.shared) { - /* str_buf */ - 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); - } -} - -VALUE -rb_str_associated(str) - VALUE str; -{ - if (FL_TEST(str, STR_ASSOC)) { - return RSTRING(str)->aux.shared; - } - return Qfalse; -} - static ID id_to_s; VALUE @@ -433,6 +399,36 @@ rb_str_modify(str) str_make_independent(str); } +void +rb_str_associate(str, add) + VALUE str, add; +{ + if (FL_TEST(str, STR_ASSOC)) { + /* already associated */ + rb_ary_concat(RSTRING(str)->aux.shared, add); + } + else { + if (FL_TEST(str, ELTS_SHARED)) { + str_make_independent(str); + } + else if (RSTRING(str)->aux.capa != RSTRING(str)->len) { + RESIZE_CAPA(str, RSTRING(str)->len); + } + RSTRING(str)->aux.shared = add; + FL_SET(str, STR_ASSOC); + } +} + +VALUE +rb_str_associated(str) + VALUE str; +{ + if (FL_TEST(str, STR_ASSOC)) { + return RSTRING(str)->aux.shared; + } + return Qfalse; +} + VALUE rb_string_value(ptr) volatile VALUE *ptr; @@ -514,9 +510,11 @@ rb_str_resize(str, len) if (len != RSTRING(str)->len) { rb_str_modify(str); - if (RSTRING(str)->len < len || RSTRING(str)->len - len > 1024) { - RESIZE_CAPA(str, len); + REALLOC_N(RSTRING(str)->ptr, char, len+1); + if (!FL_TEST(str, STR_ASSOC)) { + RSTRING(str)->aux.capa = len; + } } RSTRING(str)->len = len; RSTRING(str)->ptr[len] = '\0'; /* sentinel */ @@ -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) return str; + if (len < 0) { + rb_raise(rb_eArgError, "negative string size (or size too big)"); + } + rb_str_modify(str); + if (FL_TEST(str, STR_ASSOC)) { + FL_UNSET(str, STR_ASSOC); + capa = RSTRING(str)->aux.capa = RSTRING(str)->len; + } + else { + capa = RSTRING(str)->aux.capa; } - capa = RSTRING(str)->aux.capa; total = RSTRING(str)->len+len; if (capa <= total) { while (total > capa) { @@ -564,12 +570,12 @@ 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 (len < 0) { + rb_raise(rb_eArgError, "negative string size (or size too big)"); + } + if (FL_TEST(str, STR_ASSOC)) { + rb_str_modify(str); + REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len+len); if (ptr) { memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len); } @@ -578,9 +584,10 @@ rb_str_cat(str, ptr, len) } RSTRING(str)->len += len; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */ + return str; } - return str; + return rb_str_buf_cat(str, ptr, len); } VALUE @@ -597,11 +604,14 @@ 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)->aux.capa = RSTRING(str)->len; + } + else { + capa = RSTRING(str)->aux.capa; } - capa = RSTRING(str)->aux.capa; - len = RSTRING(str)->len+RSTRING(str2)->len; if (capa <= len) { while (len > capa) { @@ -613,6 +623,7 @@ rb_str_buf_append(str, str2) RSTRING(str2)->ptr, RSTRING(str2)->len); RSTRING(str)->len += RSTRING(str2)->len; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */ + OBJ_INFECT(str, str2); return str; } @@ -626,20 +637,19 @@ rb_str_append(str, str2) 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; + if (FL_TEST(str, STR_ASSOC)) { + len = RSTRING(str)->len+RSTRING(str2)->len; + REALLOC_N(RSTRING(str)->ptr, char, len+1); + memcpy(RSTRING(str)->ptr + RSTRING(str)->len, + RSTRING(str2)->ptr, RSTRING(str2)->len); + RSTRING(str)->ptr[len] = '\0'; /* sentinel */ + RSTRING(str)->len = len; + } + else { + return rb_str_buf_append(str, str2); } - 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); - return str; }