[#24536] 「Rubyの落し方」 v.s. ruby_1_8 — akira yamada / やまだあきら <akira@...>

<URL:http://jp.rubyist.net/magazine/?0002-RubyCore>

40 messages 2004/10/20
[#24541] Re: 「Rubyの落し方」 v.s. ruby_1_8 — Yukihiro Matsumoto <matz@...> 2004/10/20

まつもと ゆきひろです

[#24599] 1.8.2 preview3? — akira yamada / やまだあきら <akira@...> 2004/10/26

2004-10-20 (水) の 21:38 +0900 に Yukihiro Matsumoto さんは書きました:

[#24605] Re: 1.8.2 preview3? — akira yamada / やまだあきら <akira@...> 2004/10/27

2004-10-26 (火) の 16:16 +0900 に akira yamada / やまだあきら さんは書きました:

[#24606] Re: 1.8.2 preview3? — Yukihiro Matsumoto <matz@...> 2004/10/27

まつもと ゆきひろです

[#24608] Re: 1.8.2 preview3? — akira yamada / やまだあきら <akira@...> 2004/10/27

2004-10-27 (水) の 11:48 +0900 に Yukihiro Matsumoto さんは書きました:

[#24620] Re: 1.8.2 preview3? — akira yamada / やまだあきら <akira@...> 2004/10/27

2004-10-27 (水) の 12:42 +0900 に akira yamada / やまだあきら さんは書きました:

[#24629] Re: 1.8.2 preview3? — Tanaka Akira <akr@...17n.org> 2004/10/29

In article <1098888819.9446.14.camel@rice.p.arika.org>,

[ruby-dev:24488] Re: Dir.glob dumps core

From: nobu@...
Date: 2004-10-13 03:09:05 UTC
List: ruby-dev #24488
なかだです。

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はできる。
    中田 伸悦

In This Thread