diff --git a/ChangeLog b/ChangeLog index 6eaf9a22af..d4f2a68d30 100644 --- a/ChangeLog +++ b/ChangeLog @@ -25,6 +25,19 @@ Tue Nov 9 00:50:06 2004 Dave Thomas * lib/rdoc/rdoc.rb: Change version numbering of RDoc and ri +Tue Nov 9 01:05:04 2004 Yukihiro Matsumoto + + * dir.c (rb_glob2): do not allocate buffer from heap to avoid + memory leaks. use string object for buffering instead. + [ruby-dev:24738] + + * dir.c (join_path): ditto. + + * io.c (io_read): external input buffer may be modified even after + rb_str_locktmp(). [ruby-dev:24735] + + * dir.c (fnmatch): p or s may be NULL. [ruby-dev:24749] + Tue Nov 9 00:36:26 2004 Masatoshi SEKI * lib/drb/extservm.rb: add DRb::ExtServManager#uri=. @@ -67,6 +80,11 @@ Sat Nov 6 11:18:59 2004 Tadayoshi Funaba * lib/date.rb (_parse): checks whether zone was given. +Sat Nov 6 00:46:27 2004 Yukihiro Matsumoto + + * string.c (rb_str_locktmp): check STR_TMPLOCK flag before + locking. [ruby-dev:24727] + Fri Nov 5 19:07:16 2004 NARUSE, Yui * ext/nkf: follow CVS Head of original nkf. @@ -93,6 +111,10 @@ Fri Nov 5 13:17:54 2004 Hidetoshi NAGAI * ext/tk/lib/tk/text.rb: bug fix +Fri Nov 5 08:52:48 2004 Yukihiro Matsumoto + + * gc.c (gc_mark): stricter GC stack check. + Fri Nov 5 08:34:43 2004 Yukihiro Matsumoto * string.c (str_gsub): should have removed rb_str_unlocktmp(str). diff --git a/dir.c b/dir.c index 4e3eb256fe..0c22522370 100644 --- a/dir.c +++ b/dir.c @@ -303,6 +303,8 @@ fnmatch(p, s, flags) const char *ptmp = 0; const char *stmp = 0; + if (!p) p = ""; + if (!s) s = ""; if (pathname) { while (1) { if (p[0] == '*' && p[1] == '*' && p[2] == '/') { @@ -1120,22 +1122,21 @@ glob_free_pattern(list) } } -static char * +static VALUE join_path(path, dirsep, name) - const char *path; + VALUE path; int dirsep; const char *name; { - const int len = strlen(path); - char *buf = ALLOC_N(char, len+1+strlen(name)+1); - strcpy(buf, path); + long len = RSTRING(path)->len; + VALUE buf = rb_str_new(0, RSTRING(path)->len+strlen(name)+(dirsep?1:0)); + + memcpy(RSTRING(buf)->ptr, RSTRING(path)->ptr, len); if (dirsep) { - strcpy(buf+len, "/"); - strcpy(buf+len+1, name); - } - else { - strcpy(buf+len, name); + strcpy(RSTRING(buf)->ptr+len, "/"); + len++; } + strcpy(RSTRING(buf)->ptr+len, name); return buf; } @@ -1154,8 +1155,8 @@ enum answer { YES, NO, UNKNOWN }; #endif struct glob_args { - void (*func) _((const char*, VALUE)); - const char *c; + void (*func) _((VALUE, VALUE)); + VALUE c; VALUE v; }; @@ -1166,14 +1167,17 @@ glob_func_caller(val) VALUE val; { struct glob_args *args = (struct glob_args *)val; - (*args->func)(args->c, args->v); + VALUE path = args->c; + + OBJ_TAINT(path); + (*args->func)(path, args->v); return Qnil; } static int glob_call_func(func, path, arg) - void (*func) _((const char*, VALUE)); - const char *path; + void (*func) _((VALUE, VALUE)); + VALUE path; VALUE arg; { int status; @@ -1189,14 +1193,14 @@ glob_call_func(func, path, arg) static int glob_helper(path, dirsep, exist, isdir, beg, end, flags, func, arg) - const char *path; + VALUE path; int dirsep; /* '/' should be placed before appending child entry's name to 'path'. */ enum answer exist; /* Does 'path' indicate an existing entry? */ enum answer isdir; /* Does 'path' indicate a directory or a symlink to a directory? */ struct glob_pattern **beg; struct glob_pattern **end; int flags; - void (*func) _((const char*, VALUE)); + void (*func) _((VALUE, VALUE)); VALUE arg; { struct stat st; @@ -1227,7 +1231,7 @@ glob_helper(path, dirsep, exist, isdir, beg, end, flags, func, arg) } } - if (*path) { + if (RSTRING(path)->len > 0) { if (match_all && exist == UNKNOWN) { if (do_lstat(path, &st) == 0) { exist = YES; @@ -1256,9 +1260,7 @@ glob_helper(path, dirsep, exist, isdir, beg, end, flags, func, arg) } if (match_dir && isdir == YES) { - char *buf = join_path(path, dirsep, ""); - status = glob_call_func(func, buf, arg); - free(buf); + status = glob_call_func(func, join_path(path, dirsep, ""), arg); if (status) return status; } } @@ -1267,17 +1269,17 @@ glob_helper(path, dirsep, exist, isdir, beg, end, flags, func, arg) if (magical || recursive) { struct dirent *dp; - DIR *dirp = do_opendir(*path ? path : "."); + DIR *dirp = do_opendir(RSTRING(path)->len > 0 ? RSTRING(path)->ptr : "."); if (dirp == NULL) return 0; for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { - char *buf = join_path(path, dirsep, dp->d_name); + VALUE buf = join_path(path, dirsep, dp->d_name); enum answer new_isdir = UNKNOWN; if (recursive && strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0 && fnmatch("*", dp->d_name, flags) == 0) { #ifndef _WIN32 - if (do_lstat(buf, &st) == 0) + if (do_lstat(RSTRING(buf)->ptr, &st) == 0) new_isdir = S_ISDIR(st.st_mode) ? YES : S_ISLNK(st.st_mode) ? UNKNOWN : NO; else new_isdir = NO; @@ -1303,7 +1305,6 @@ glob_helper(path, dirsep, exist, isdir, beg, end, flags, func, arg) status = glob_helper(buf, 1, YES, new_isdir, new_beg, new_end, flags, func, arg); free(new_beg); - free(buf); if (status) break; } @@ -1318,7 +1319,8 @@ glob_helper(path, dirsep, exist, isdir, beg, end, flags, func, arg) for (cur = copy_beg; cur < copy_end; ++cur) { if (*cur) { - char *name, *buf; + VALUE buf; + char *name; name = ALLOC_N(char, strlen((*cur)->str) + 1); strcpy(name, (*cur)->str); if (escape) remove_backslashes(name); @@ -1333,10 +1335,9 @@ glob_helper(path, dirsep, exist, isdir, beg, end, flags, func, arg) } buf = join_path(path, dirsep, name); - status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg, new_end, flags, func, arg); - free(buf); - free(new_beg); free(name); + status = glob_helper(buf, 1, UNKNOWN, UNKNOWN, new_beg, new_end, flags, func, arg); + free(new_beg); if (status) break; } } @@ -1349,14 +1350,14 @@ glob_helper(path, dirsep, exist, isdir, beg, end, flags, func, arg) static int rb_glob2(path, flags, func, arg) - const char *path; + VALUE path; int flags; - void (*func) _((const char*, VALUE)); + void (*func) _((VALUE, VALUE)); VALUE arg; { struct glob_pattern *list; - const char *root = path; - char *buf; + const char *root; + VALUE buf; int n; int status; @@ -1366,55 +1367,75 @@ rb_glob2(path, flags, func, arg) #if defined DOSISH flags |= FNM_CASEFOLD; - root = rb_path_skip_prefix(root); + root = rb_path_skip_prefix(RSTRING(path)->ptr); #else + root = StringValuePtr(path); flags &= ~FNM_CASEFOLD; #endif - if (*root == '/') root++; + if (root && *root == '/') root++; - n = root - path; - buf = ALLOC_N(char, n+1); - memcpy(buf, path, n); - buf[n] = '\0'; + n = root - RSTRING(path)->ptr; + buf = rb_str_new(RSTRING(path)->ptr, n); list = glob_make_pattern(root, flags); status = glob_helper(buf, 0, UNKNOWN, UNKNOWN, &list, &list + 1, flags, func, arg); glob_free_pattern(list); - free(buf); - return status; } +struct rb_glob_args { + void (*func) _((const char*, VALUE)); + VALUE arg; +}; + +static VALUE +rb_glob_caller(path, a) + VALUE path, a; +{ + struct rb_glob_args *args = (struct rb_glob_args *)a; + (*args->func)(RSTRING(path)->ptr, args->arg); + return Qnil; +} + void rb_glob(path, func, arg) const char *path; void (*func) _((const char*, VALUE)); VALUE arg; { - int status = rb_glob2(path, 0, func, arg); + struct rb_glob_args args; + int status; + + args.func = func; + args.arg = arg; + status = rb_glob2(rb_str_new2(path), 0, func, &args); if (status) rb_jump_tag(status); } static void push_pattern(path, ary) - const char *path; - VALUE ary; + VALUE path, ary; { - rb_ary_push(ary, rb_tainted_str_new2(path)); + rb_ary_push(ary, path); } static int -push_glob(ary, s, flags) +push_glob(VALUE ary, VALUE s, long offset, int flags); + +static int +push_glob(ary, str, offset, flags) VALUE ary; - const char *s; + VALUE str; + long offset; int flags; { const int escape = !(flags & FNM_NOESCAPE); - const char *p = s; + const char *p = RSTRING(str)->ptr + offset; + const char *s = RSTRING(str)->ptr + offset; const char *lbrace = 0, *rbrace = 0; int nest = 0, status = 0; @@ -1433,10 +1454,13 @@ push_glob(ary, s, flags) } if (lbrace && rbrace) { - char *buf, *b; - buf = xmalloc(strlen(s) + 1); + VALUE buffer = rb_str_new(0, strlen(s)); + char *buf; + long offset; + + buf = RSTRING(buffer)->ptr; memcpy(buf, s, lbrace-s); - b = buf + (lbrace-s); + offset = (lbrace-s); p = lbrace; while (p < rbrace) { const char *t = ++p; @@ -1449,15 +1473,14 @@ push_glob(ary, s, flags) } Inc(p); } - memcpy(b, t, p-t); - strcpy(b+(p-t), rbrace+1); - status = push_glob(ary, buf, flags); + memcpy(buf+offset, t, p-t); + strcpy(buf+offset+(p-t), rbrace+1); + status = push_glob(ary, buffer, offset, flags); if (status) break; } - free(buf); } else if (!lbrace && !rbrace) { - status = rb_glob2(s, flags, push_pattern, ary); + status = rb_glob2(str, flags, push_pattern, ary); } return status; @@ -1468,22 +1491,18 @@ rb_push_glob(str, flags) /* '\0' is delimiter */ VALUE str; int flags; { - const char *p, *pend; + long offset = 0; VALUE ary; FilePathValue(str); ary = rb_ary_new(); - p = RSTRING(str)->ptr; - pend = p + RSTRING(str)->len; - while (p < pend) { - if (*p) { - int status = push_glob(ary, p, flags); - if (status) rb_jump_tag(status); - p += strlen(p); - } - else p++; + while (offset < RSTRING(str)->len) { + int status = push_glob(ary, str, offset, flags); + if (status) rb_jump_tag(status); + offset += strlen(RSTRING(str)->ptr+offset) + 1; + while (!RSTRING(str)->ptr[offset]) offset++; } if (rb_block_given_p()) { diff --git a/eval.c b/eval.c index 40b79fe99a..cb6de62ae1 100644 --- a/eval.c +++ b/eval.c @@ -1393,6 +1393,7 @@ ruby_finalize_0() static void ruby_finalize_1() { + signal(SIGINT, SIG_DFL); ruby_errinfo = 0; rb_gc_call_finalizer_at_exit(); trace_func = 0; diff --git a/ext/socket/socket.c b/ext/socket/socket.c index 0e7b539588..0e44cdc94c 100644 --- a/ext/socket/socket.c +++ b/ext/socket/socket.c @@ -476,9 +476,6 @@ s_recvfrom(sock, argc, argv, from) retry: rb_str_locktmp(str); rb_thread_wait_fd(fd); - if (buflen != RSTRING(str)->len) { - rb_raise(rb_eRuntimeError, "buffer modified"); - } TRAP_BEG; slen = recvfrom(fd, RSTRING(str)->ptr, buflen, flags, (struct sockaddr*)buf, &alen); TRAP_END; @@ -1989,8 +1986,6 @@ sock_connect(sock, addr) int fd, n; StringValue(addr); - rb_str_modify(addr); - GetOpenFile(sock, fptr); fd = fileno(fptr->f); rb_str_locktmp(addr); @@ -2010,8 +2005,6 @@ sock_bind(sock, addr) OpenFile *fptr; StringValue(addr); - rb_str_modify(addr); - GetOpenFile(sock, fptr); if (bind(fileno(fptr->f), (struct sockaddr*)RSTRING(addr)->ptr, RSTRING(addr)->len) < 0) rb_sys_fail("bind(2)"); diff --git a/gc.c b/gc.c index 71e2225609..98ff2af246 100644 --- a/gc.c +++ b/gc.c @@ -709,7 +709,7 @@ gc_mark(ptr, lev) if (obj->as.basic.flags & FL_MARK) return; /* already marked */ obj->as.basic.flags |= FL_MARK; - if (lev > GC_LEVEL_MAX) { + if (lev > GC_LEVEL_MAX || (lev == 0 && ruby_stack_check())) { if (!mark_stack_overflow) { if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) { *mark_stack_ptr = ptr; diff --git a/io.c b/io.c index 0dbb6b741c..5abe8dd5c8 100644 --- a/io.c +++ b/io.c @@ -330,7 +330,9 @@ io_fflush(f, fptr) rb_io_check_closed(fptr); } for (;;) { + TRAP_BEG; n = fflush(f); + TRAP_END; if (n != EOF) break; if (!rb_io_wait_writable(fileno(f))) rb_sys_fail(fptr->path); @@ -1216,6 +1218,9 @@ io_read(argc, argv, io) rb_str_locktmp(str); READ_CHECK(fptr->f); + if (RSTRING(str)->len != len) { + rb_raise(rb_eRuntimeError, "buffer string modified"); + } n = rb_io_fread(RSTRING(str)->ptr, len, fptr->f); rb_str_unlocktmp(str); if (n == 0) { diff --git a/lib/shellwords.rb b/lib/shellwords.rb index 99c0bf8437..e87b9e656b 100644 --- a/lib/shellwords.rb +++ b/lib/shellwords.rb @@ -41,8 +41,8 @@ module Shellwords snippet = $1 elsif line =~ /\A'/ then raise ArgumentError, "Unmatched single quote: #{line}" - elsif line.sub!(/\A\\(.)/, '') then - snippet = $1 + elsif line.sub!(/\A\\(.)?/, '') then + snippet = $1 || '\\' elsif line.sub!(/\A([^\s\\'"]+)/, '') then snippet = $1 else diff --git a/pack.c b/pack.c index 5e7ae09e20..9a83dc7041 100644 --- a/pack.c +++ b/pack.c @@ -175,7 +175,7 @@ define_swapx(d, double) #endif /* #if SIZEOF_LONG == 8 */ #else /* SIZEOF_DOUBLE != 8 */ define_swapx(d, double) -#endif /* #if SIZEOF_DPOUBLE == 8 */ +#endif /* #if SIZEOF_DOUBLE == 8 */ #undef define_swapx @@ -248,7 +248,7 @@ endian() #define hton32(x) (x) # endif #else /* LITTLE ENDIAN */ -#ifndef ntohs +#ifdef ntohs #undef ntohs #undef ntohl #undef htons diff --git a/string.c b/string.c index ac3efa3c5f..3df8fb9555 100644 --- a/string.c +++ b/string.c @@ -252,13 +252,6 @@ rb_str_shared_replace(str, str2) if (str == str2) return; rb_str_modify(str); 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; - FL_UNSET(str, STR_NOCAPA); - return; - } RSTRING(str)->ptr = RSTRING(str2)->ptr; RSTRING(str)->len = RSTRING(str2)->len; FL_UNSET(str, STR_NOCAPA); @@ -640,6 +633,9 @@ VALUE rb_str_locktmp(str) VALUE str; { + if (FL_TEST(str, STR_TMPLOCK)) { + rb_raise(rb_eRuntimeError, "temporal locking already locked string"); + } FL_SET(str, STR_TMPLOCK); return str; } @@ -648,6 +644,9 @@ VALUE rb_str_unlocktmp(str) VALUE str; { + if (!FL_TEST(str, STR_TMPLOCK)) { + rb_raise(rb_eRuntimeError, "temporal unlocking already unlocked string"); + } FL_UNSET(str, STR_TMPLOCK); return str; } @@ -2278,7 +2277,8 @@ rb_str_clear(str) } RSTRING(str)->aux.shared = 0; FL_UNSET(str, STR_NOCAPA); - RSTRING(str)->ptr = 0; + FL_SET(str, ELTS_SHARED); + RSTRING(str)->ptr = null_str; RARRAY(str)->len = 0; return str; }