From: matz@... (Yukihiro Matsumoto) Date: 1997-09-11T10:27:43+09:00 Subject: [ruby-dev:457] Re: open, close, waitpid? まつもと ゆきひろです In message "[ruby-dev:452] Re: open, close, waitpid?" on 97/09/10, WATANABE Hirofumi writes: |わたなべです. |謎ですね. 謎はすべて解けたっ! ^^;;; いやあ,実に簡単な見落としでした.布団の中でひらめいたという. 添付のパッチで直ります. 原因を解説すると * 最初のopen("|cat", "w")でfdがオープンされます * 次のopen("|sed 's/a/b/'", "w")で生成されたプロセスにcat と繋がったfdが引き継がれます. * 親がf1(catのfd)をcloseしてもsedのプロセスではまだopenし たままになっていますので,fdはcloseされません(fdの全部の コピーがcloseされないと実際のcloseは起きない). * f2を先にcloseするとプロセスがいなくなるので,catのfdへの 参照は親だけになり,closeと同時にプロセスが終了する. となっていました.対策としてはfdをオープンするたびにfcntlで F_SETFD(close-on-exec)を設定しました.F_SETFDのないプラット フォームではexecする前にcloseするようにしました. まつもと ゆきひろ /:|) --- io.c~ Tue Sep 9 18:03:55 1997 +++ io.c Thu Sep 11 10:22:35 1997 @@ -21,3 +21,3 @@ #endif -#if defined(THREAD) && defined(HAVE_FCNTL) +#if defined(HAVE_FCNTL) #include @@ -45,2 +45,8 @@ +#ifdef HAVE_SYS_PARAM_H +# include +#else +# define NOFILE 64 +#endif + VALUE rb_ad_string(); @@ -759,2 +765,5 @@ } +#if defined(HAVE_FCNTL) && defined(F_SETFD) + fcntl(fileno(f),F_SETFD,fileno(f) >= 3); +#endif return f; @@ -778,2 +787,5 @@ } +#if defined(HAVE_FCNTL) && defined(F_SETFD) + fcntl(fd,F_SETFD,fd >= 3); +#endif return f; @@ -909,4 +919,6 @@ close(pr[0]); - dup2(pr[1], 1); - close(pr[1]); + if (pr[1] != 1) { + dup2(pr[1], 1); + close(pr[1]); + } } @@ -914,4 +926,6 @@ close(pw[1]); - dup2(pw[0], 0); - close(pw[0]); + if (pw[0] != 0) { + dup2(pw[0], 0); + close(pw[0]); + } } @@ -919,4 +933,4 @@ if (doexec) { - VALUE fd = io_fileno(rb_stderr); - int f = FIX2INT(fd); + VALUE serr = io_fileno(rb_stderr); + int fd = FIX2INT(serr); extern char *sourcefile; @@ -924,7 +938,12 @@ - if (f != 2) { + if (fd != 2) { close(2); - dup2(f, 2); - close(f); + dup2(fd, 2); + close(fd); } + +#if !defined(HAVE_FCNTL) || !defined(F_SETFD) + for (fd = 3; fd < NOFILE; fd++) + close(fd); +#endif rb_proc_exec(pname); @@ -954,4 +973,2 @@ MakeOpenFile(port, fptr); - if (modef & FMODE_READABLE) close(pr[1]); - if (modef & FMODE_WRITABLE) close(pw[0]); fptr->mode = modef; @@ -960,6 +977,12 @@ - if (modef & FMODE_READABLE) fptr->f = rb_fdopen(pr[0], "r"); + if (modef & FMODE_READABLE) { + close(pr[1]); + fptr->f = rb_fdopen(pr[0], "r"); + } if (modef & FMODE_WRITABLE) { - if (fptr->f) fptr->f2 = rb_fdopen(pw[1], "w"); - else fptr->f = rb_fdopen(pw[1], "w"); + FILE *f = rb_fdopen(pw[1], "w"); + + close(pw[0]); + if (fptr->f) fptr->f2 = f; + else fptr->f = f; } @@ -1885,2 +1908,7 @@ rb_sys_fail(0); + +#if defined(HAVE_FCNTL) && defined(F_SETFD) + fcntl(pipes[0],F_SETFD,pipes[0] >= 3); + fcntl(pipes[1],F_SETFD,pipes[1] >= 3); +#endif r = prep_stdio(fdopen(pipes[0], "r"), FMODE_READABLE);