From: nobu@... Date: 2004-10-13T12:09:05+09:00 Subject: [ruby-dev:24488] Re: Dir.glob dumps core なかだです。 At Tue, 12 Oct 2004 23:59:47 +0900, Tanaka Akira wrote in [ruby-dev:24487]: > 次のようにすると core を吐きます。 > > % mkdir -p /tmp/tst/{a,b,c}/{d,e,f} > % ./ruby -e ' > Dir.glob("/tmp/tst/**/*") {|f| callcc {|k| $k = k } if f == "/tmp/tst/a/f" } > $k.call' バッファの類をStringにしてみたらどうかとも思ったんですが、 opendir/closedirの間でyieldしてるんですよねぇ。 もっと簡単な方法はないかな。 Index: dir.c =================================================================== RCS file: /cvs/ruby/src/ruby/dir.c,v retrieving revision 1.127 diff -u -2 -p -r1.127 dir.c --- dir.c 21 Sep 2004 03:08:32 -0000 1.127 +++ dir.c 13 Oct 2004 03:03:05 -0000 @@ -950,11 +950,25 @@ do_lstat(path, pst) static DIR * -do_opendir(path) +do_opendir(path, vdir) const char *path; + volatile VALUE *vdir; { DIR *dirp = opendir(path); - if (dirp == NULL && errno != ENOENT && errno != ENOTDIR) - rb_sys_warning(path); + if (dirp == NULL) { + switch (errno) { + case EMFILE: + case ENFILE: + rb_gc(); + dirp = opendir(path); + } + if (dirp == NULL) { + if (errno != ENOENT && errno != ENOTDIR) + rb_sys_warning(path); + return 0; + } + } + + *vdir = Data_Wrap_Struct(rb_cData, 0, closedir, dirp); return dirp; } @@ -1056,23 +1070,42 @@ remove_backslashes(p) enum glob_pattern_type { PLAIN, MAGICAL, RECURSIVE, MATCH_ALL, MATCH_DIR }; +#define GLOB_PTR(p) ((struct glob_pattern *)DATA_PTR(p)) + struct glob_pattern { char *str; enum glob_pattern_type type; - struct glob_pattern *next; + VALUE next; }; -static struct glob_pattern * +static void +glob_mark_pattern(p) + void *p; +{ + rb_gc_mark(((struct glob_pattern *)p)->next); +} + +static void +glob_free_pattern(p) + void *p; +{ + xfree(((struct glob_pattern *)p)->str); + xfree(p); +} + +static VALUE glob_make_pattern(p, flags) const char *p; int flags; { - struct glob_pattern *list, *tmp, **tail = &list; + VALUE list, *tail = &list; + struct glob_pattern *tmp; int dirsep = 0; /* pattern is terminated with '/' */ while (*p) { - tmp = ALLOC(struct glob_pattern); if (p[0] == '*' && p[1] == '*' && p[2] == '/') { /* fold continuous RECURSIVEs (needed in glob_helper) */ do { p += 3; } while (p[0] == '*' && p[1] == '*' && p[2] == '/'); + *tail = Data_Make_Struct(rb_cData, struct glob_pattern, + glob_mark_pattern, -1, tmp); tmp->type = RECURSIVE; tmp->str = 0; @@ -1084,4 +1117,6 @@ glob_make_pattern(p, flags) memcpy(buf, p, m-p); buf[m-p] = '\0'; + *tail = Data_Make_Struct(rb_cData, struct glob_pattern, + glob_mark_pattern, glob_free_pattern, tmp); tmp->type = has_magic(buf, flags) ? MAGICAL : PLAIN; tmp->str = buf; @@ -1095,12 +1130,11 @@ glob_make_pattern(p, flags) } } - *tail = tmp; tail = &tmp->next; } - tmp = ALLOC(struct glob_pattern); + *tail = Data_Make_Struct(rb_cData, struct glob_pattern, + glob_mark_pattern, -1, tmp); tmp->type = dirsep ? MATCH_DIR : MATCH_ALL; tmp->str = 0; - *tail = tmp; tmp->next = 0; @@ -1108,18 +1142,7 @@ glob_make_pattern(p, flags) } -static void -glob_free_pattern(list) - struct glob_pattern *list; -{ - while (list) { - struct glob_pattern *tmp = list; - list = list->next; - if (tmp->str) - free(tmp->str); - free(tmp); - } -} +#define HIDDEN_STRING(str) do {OBJ_FREEZE(str); RBASIC(str)->klass = 0;} while (0) -static char * +static VALUE join_path(path, dirsep, name) const char *path; @@ -1128,5 +1151,7 @@ join_path(path, dirsep, name) { const int len = strlen(path); - char *buf = ALLOC_N(char, len+1+strlen(name)+1); + VALUE str = rb_str_new(0, len+1+strlen(name)+1); + char *buf = RSTRING(str)->ptr; + HIDDEN_STRING(str); strcpy(buf, path); if (dirsep) { @@ -1137,5 +1162,5 @@ join_path(path, dirsep, name) strcpy(buf+len, name); } - return buf; + return str; } @@ -1154,39 +1179,5 @@ enum answer { YES, NO, UNKNOWN }; #endif -struct glob_args { - void (*func) _((const char*, VALUE)); - const char *c; - VALUE v; -}; - -static VALUE glob_func_caller _((VALUE)); - -static VALUE -glob_func_caller(val) - VALUE val; -{ - struct glob_args *args = (struct glob_args *)val; - (*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 +static void glob_helper(path, dirsep, exist, isdir, beg, end, flags, func, arg) const char *path; @@ -1194,6 +1185,6 @@ glob_helper(path, dirsep, exist, isdir, 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; + VALUE *beg; + VALUE *end; int flags; void (*func) _((const char*, VALUE)); @@ -1201,14 +1192,13 @@ glob_helper(path, dirsep, exist, isdir, { struct stat st; - int status = 0; - struct glob_pattern **cur, **new_beg, **new_end; + VALUE *cur, *new_beg, *new_end; int plain = 0, magical = 0, recursive = 0, match_all = 0, match_dir = 0; int escape = !(flags & FNM_NOESCAPE); for (cur = beg; cur < end; ++cur) { - struct glob_pattern *p = *cur; + struct glob_pattern *p = DATA_PTR(*cur); if (p->type == RECURSIVE) { recursive = 1; - p = p->next; + p = GLOB_PTR(p->next); } switch (p->type) { @@ -1252,25 +1242,23 @@ glob_helper(path, dirsep, exist, isdir, if (match_all && exist == YES) { - status = glob_call_func(func, path, arg); - if (status) return status; + (*func)(path, arg); } if (match_dir && isdir == YES) { - char *buf = join_path(path, dirsep, ""); - status = glob_call_func(func, buf, arg); - free(buf); - if (status) return status; + VALUE buf = join_path(path, dirsep, ""); + (*func)(RSTRING(buf)->ptr, arg); } } - if (exist == NO || isdir == NO) return 0; + if (exist == NO || isdir == NO) return; if (magical || recursive) { + volatile VALUE vdir, ary; struct dirent *dp; - DIR *dirp = do_opendir(*path ? path : "."); - if (dirp == NULL) return 0; + DIR *dirp = do_opendir(*path ? path : ".", &vdir); + if (dirp == NULL) return; for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) { - char *buf = join_path(path, dirsep, dp->d_name); + volatile VALUE buf = join_path(path, dirsep, dp->d_name); enum answer new_isdir = UNKNOWN; @@ -1278,5 +1266,5 @@ glob_helper(path, dirsep, exist, isdir, && 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 @@ -1287,12 +1275,14 @@ glob_helper(path, dirsep, exist, isdir, } - new_beg = new_end = ALLOC_N(struct glob_pattern *, (end - beg) * 2); + ary = rb_ary_new2((end - beg) * 2); + OBJ_FREEZE(ary); + new_beg = new_end = RARRAY(ary)->ptr; for (cur = beg; cur < end; ++cur) { - struct glob_pattern *p = *cur; + struct glob_pattern *p = DATA_PTR(*cur); if (p->type == RECURSIVE) { if (new_isdir == YES) /* not symlink but real directory */ - *new_end++ = p; /* append recursive pattern */ - p = p->next; /* 0 times recursion */ + *new_end++ = *cur; /* append recursive pattern */ + p = DATA_PTR(p->next); /* 0 times recursion */ } if (p->type == PLAIN || p->type == MAGICAL) { @@ -1302,51 +1292,44 @@ glob_helper(path, dirsep, exist, isdir, } - status = glob_helper(buf, 1, YES, new_isdir, new_beg, new_end, flags, func, arg); - free(new_beg); - free(buf); - if (status) break; + glob_helper(RSTRING(buf)->ptr, 1, YES, new_isdir, new_beg, new_end, flags, func, arg); } - - closedir(dirp); } else if (plain) { - struct glob_pattern **copy_beg, **copy_end, **cur2; + VALUE *copy_beg, *copy_end, *cur2; + volatile VALUE copy = rb_ary_new2(end - beg); - copy_beg = copy_end = ALLOC_N(struct glob_pattern *, end - beg); + OBJ_FREEZE(copy); + copy_beg = copy_end = RARRAY(copy)->ptr; for (cur = beg; cur < end; ++cur) - *copy_end++ = (*cur)->type == PLAIN ? *cur : 0; + *copy_end++ = GLOB_PTR(*cur)->type == PLAIN ? *cur : 0; for (cur = copy_beg; cur < copy_end; ++cur) { - if (*cur) { - char *name, *buf; - name = ALLOC_N(char, strlen((*cur)->str) + 1); - strcpy(name, (*cur)->str); - if (escape) remove_backslashes(name); - - new_beg = new_end = ALLOC_N(struct glob_pattern *, end - beg); - *new_end++ = (*cur)->next; + struct glob_pattern *p = GLOB_PTR(*cur); + if (p) { + volatile VALUE buf, ary; + VALUE name = rb_str_new2(p->str); + HIDDEN_STRING(name); + buf = name; + if (escape) remove_backslashes(RSTRING(name)->ptr); + + ary = rb_ary_new2(end - beg); + OBJ_FREEZE(ary); + new_beg = new_end = RARRAY(ary)->ptr; + *new_end++ = GLOB_PTR(*cur)->next; for (cur2 = cur + 1; cur2 < copy_end; ++cur2) { - if (*cur2 && fnmatch((*cur2)->str, name, flags) == 0) { - *new_end++ = (*cur2)->next; + if (*cur2 && fnmatch(GLOB_PTR(*cur2)->str, RSTRING(name)->ptr, flags) == 0) { + *new_end++ = GLOB_PTR(*cur2)->next; *cur2 = 0; } } - 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); - if (status) break; + buf = name = join_path(path, dirsep, RSTRING(name)->ptr); + glob_helper(RSTRING(name)->ptr, 1, UNKNOWN, UNKNOWN, new_beg, new_end, flags, func, arg); } } - - free(copy_beg); } - - return status; } -static int +static void rb_glob2(path, flags, func, arg) const char *path; @@ -1355,9 +1338,7 @@ rb_glob2(path, flags, func, arg) VALUE arg; { - struct glob_pattern *list; + VALUE list[1]; const char *root = path; - char *buf; - int n; - int status; + volatile VALUE buf; if (flags & FNM_CASEFOLD) { @@ -1374,16 +1355,10 @@ rb_glob2(path, flags, func, arg) if (*root == '/') root++; - n = root - path; - buf = ALLOC_N(char, n+1); - memcpy(buf, path, n); - buf[n] = '\0'; - - 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); + buf = rb_str_new(path, root - path); + HIDDEN_STRING(buf); - return status; + list[0] = glob_make_pattern(root, flags); + glob_helper(RSTRING(buf)->ptr, 0, UNKNOWN, UNKNOWN, + list, list + 1, flags, func, arg); } @@ -1394,7 +1369,5 @@ rb_glob(path, func, arg) VALUE arg; { - int status = rb_glob2(path, 0, func, arg); - - if (status) rb_jump_tag(status); + rb_glob2(path, 0, func, arg); } @@ -1414,5 +1387,5 @@ push_pattern(path, ary) } -static int +static void push_glob(ary, s, flags) VALUE ary; @@ -1424,5 +1397,5 @@ push_glob(ary, s, flags) const char *p = s; const char *lbrace = 0, *rbrace = 0; - int nest = 0, status = 0; + int nest = 0; while (*p) { @@ -1441,6 +1414,7 @@ push_glob(ary, s, flags) if (lbrace && rbrace) { - char *buf, *b; - buf = xmalloc(strlen(s) + 1); + volatile VALUE str = rb_str_new(0, strlen(s) + 1); + char *buf = RSTRING(str)->ptr, *b; + HIDDEN_STRING(str); memcpy(buf, s, lbrace-s); b = buf + (lbrace-s); @@ -1459,14 +1433,10 @@ push_glob(ary, s, flags) memcpy(b, t, p-t); strcpy(b+(p-t), rbrace+1); - status = push_glob(ary, buf, flags); - if (status) break; + push_glob(ary, buf, flags); } - free(buf); } else if (!lbrace && !rbrace) { - status = rb_glob2(s, flags, push_pattern, ary); + rb_glob2(s, flags, push_pattern, ary); } - - return status; } @@ -1486,4 +1456,5 @@ rb_push_glob(str, flags) /* '\0' is deli FilePathValue(str); + *(volatile VALUE *)&str = rb_str_new4(str); p = RSTRING(str)->ptr; pend = p + RSTRING(str)->len; @@ -1491,6 +1462,5 @@ rb_push_glob(str, flags) /* '\0' is deli while (p < pend) { if (*p) { - int status = push_glob(ary, p, flags); - if (status) rb_jump_tag(status); + push_glob(ary, p, flags); p += strlen(p); } -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦