Hi,
In message "Re: [Fix] Dir mem leak"
on 02/09/10, nobu.nokada / softhome.net <nobu.nokada / softhome.net> writes:
|glob_helper() calls arbitrary functions, even ruby blocks
|passed to Dir.glob, so this function must be exception safe.
|Also, closedir() must be ensured.
I haven't noticed that. How hard to work on non GC environment.
|I thought 2 approaches, 1) wrap resources by VALUE, 2) use
|rb_protect() all *func and recursive call, but feel the latter
|is too complex.
The latter should not be too complex. Here's my modifies. not
tested. Maybe it's still incomplete though.
Index: dir.c
===================================================================
RCS file: /src/ruby/dir.c,v
retrieving revision 1.71
diff -u -1 -r1.71 dir.c
--- dir.c 2002/06/15 10:24:38 1.71
+++ dir.c 2002/09/10 16:16:21
@@ -655,3 +655,34 @@
-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)
@@ -665,2 +696,3 @@
char *p, *m;
+ int status = 0;
@@ -674,3 +706,4 @@
if (lstat(path, &st) == 0) {
- (*func)(path, arg);
+ status = glob_call_func(func, path, arg);
+ if (status) return status;
}
@@ -681,6 +714,6 @@
}
- return;
+ return 0;
}
- while (p) {
+ while (p && !status) {
if (*p == '/') p++;
@@ -706,2 +739,3 @@
free(base);
+ free(magic);
break;
@@ -714,4 +748,5 @@
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;
}
@@ -721,2 +756,3 @@
free(base);
+ free(magic);
break;
@@ -726,2 +762,3 @@
free(base);
+ free(magic);
break;
@@ -749,3 +786,5 @@
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;
}
@@ -758,4 +797,4 @@
if (!m) {
- (*func)(buf, arg);
- free(buf);
+ status = glob_call_func(func, path, arg);
+ if (status) goto finalize;
continue;
@@ -768,2 +807,3 @@
}
+ finalize:
closedir(dirp);
@@ -773,15 +813,17 @@
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);
-
- sprintf(t, "%s%s", link->path, m);
- glob_helper(t, t+len, flags, func, arg);
- free(t);
+ 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);
+ status = glob_helper(t, t+len, flags, func, arg);
+ free(t);
+ }
}
- }
- else {
- rb_sys_warning(link->path);
+ else {
+ rb_sys_warning(link->path);
+ }
}
@@ -797,2 +839,3 @@
}
+ return status;
}
@@ -806,3 +849,4 @@
{
- glob_helper(path, 0, flags, func, arg);
+ int status = glob_helper(path, 0, flags, func, arg);
+ if (status) rb_jump_tag(status);
}