From: nobu@... Date: 2004-12-16T23:52:14+09:00 Subject: [ruby-dev:25225] STDIN.reopen(STDOUT).reopen(STDOUT) なかだです。 http://diary.does.notwork.org/gotoyuzo/?date=20041122#p02 | NetBSDでは、STDIN限定で上のようなコードが失敗するようだ。 | | * 1回目のreopenでSTDINがFMODE_WRITABLEに変わる。 | * 2回目のreopenでFMODE_WRITABLEなのでfflush(stdin)が呼ばれる。 | * しかし、FILE*が以前のモードを憶えたままなのでfflushでエラー。 という件ですが、STDINなどは特別扱いにして、modeの変更を禁止して しまってはどうでしょうか。 * io.c (io_reopen, rb_io_reopen): prohibit to change access mode for special IO ports. Index: io.c =================================================================== RCS file: /cvs/ruby/src/ruby/io.c,v retrieving revision 1.351 diff -U2 -p -d -r1.351 io.c --- io.c 9 Dec 2004 03:34:47 -0000 1.351 +++ io.c 16 Dec 2004 06:24:03 -0000 @@ -1917,4 +1917,8 @@ rb_io_isatty(io) } +#define FMODE_PREP (1<<16) +#define IS_PREP_STDIO(f) ((f)->mode & FMODE_PREP) +#define PREP_STDIO_NAME(f) ((f)->path) + static void fptr_finalize(fptr, noraise) @@ -1925,7 +1929,5 @@ fptr_finalize(fptr, noraise) io_fflush(fptr); } - if (fptr->stdio_file == stdin || - fptr->stdio_file == stdout || - fptr->stdio_file == stderr || + if (IS_PREP_STDIO(fptr) || fptr->fd <= 2) { return; @@ -3272,4 +3274,14 @@ io_reopen(io, nfile) if (fptr == orig) return io; +#if !defined __CYGWIN__ + if (IS_PREP_STDIO(fptr)) { + if ((fptr->mode & FMODE_READWRITE) != (orig->mode & FMODE_READWRITE)) { + rb_raise(rb_eArgError, + "%s cannot change access mode from \"%s\" to \"%s\"", + PREP_STDIO_NAME(fptr), rb_io_flags_mode(fptr->mode), + rb_io_flags_mode(orig->mode)); + } + } +#endif if (orig->mode & FMODE_READABLE) { pos = io_tell(orig); @@ -3295,7 +3307,5 @@ io_reopen(io, nfile) if (fd != fd2) { #if !defined __CYGWIN__ - if (fptr->stdio_file == stdin || - fptr->stdio_file == stdout || - fptr->stdio_file == stderr) { + if (IS_PREP_STDIO(fptr)) { /* need to keep stdio objects */ if (dup2(fd2, fd) < 0) @@ -3378,5 +3388,13 @@ rb_io_reopen(argc, argv, file) if (!NIL_P(nmode)) { - fptr->mode = rb_io_mode_flags(StringValuePtr(nmode)); + int flags = rb_io_mode_flags(StringValuePtr(nmode)); + if (IS_PREP_STDIO(fptr) && + (fptr->mode & FMODE_READWRITE) != (flags & FMODE_READWRITE)) { + rb_raise(rb_eArgError, + "%s cannot change access mode from \"%s\" to \"%s\"", + PREP_STDIO_NAME(fptr), rb_io_flags_mode(fptr->mode), + rb_io_flags_mode(flags)); + } + fptr->mode = flags; } @@ -3858,8 +3876,9 @@ deferr_setter(val, id, variable) static VALUE -prep_stdio(f, mode, klass) +prep_stdio(f, mode, klass, path) FILE *f; int mode; VALUE klass; + const char *path; { OpenFile *fp; @@ -3875,5 +3894,5 @@ prep_stdio(f, mode, klass) #endif fp->stdio_file = f; - fp->mode = mode; + fp->mode = mode | FMODE_PREP; if (fp->mode & FMODE_WRITABLE) { if (fp->fd == 2) { /* stderr must be unbuffered */ @@ -3884,20 +3903,9 @@ prep_stdio(f, mode, klass) } } + fp->path = strdup(path); return io; } -static void -prep_path(io, path) - VALUE io; - char *path; -{ - OpenFile *fptr; - - GetOpenFile(io, fptr); - if (fptr->path) rb_bug("illegal prep_path() call"); - fptr->path = strdup(path); -} - FILE *rb_io_stdio_file(OpenFile *fptr) { @@ -4214,10 +4222,8 @@ next_argv() } #endif - rb_stdout = prep_stdio(fw, FMODE_WRITABLE, rb_cFile); - prep_path(rb_stdout, fn); + rb_stdout = prep_stdio(fw, FMODE_WRITABLE, rb_cFile, fn); if (stdout_binmode) rb_io_binmode(rb_stdout); } - current_file = prep_stdio(fr, FMODE_READABLE, rb_cFile); - prep_path(current_file, fn); + current_file = prep_stdio(fr, FMODE_READABLE, rb_cFile, fn); } if (binmode) rb_io_binmode(current_file); @@ -5553,9 +5559,9 @@ Init_IO() rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0); - rb_stdin = prep_stdio(stdin, FMODE_READABLE, rb_cIO); + rb_stdin = prep_stdio(stdin, FMODE_READABLE, rb_cIO, ""); rb_define_variable("$stdin", &rb_stdin); - rb_stdout = prep_stdio(stdout, FMODE_WRITABLE, rb_cIO); + rb_stdout = prep_stdio(stdout, FMODE_WRITABLE, rb_cIO, ""); rb_define_hooked_variable("$stdout", &rb_stdout, 0, stdout_setter); - rb_stderr = prep_stdio(stderr, FMODE_WRITABLE, rb_cIO); + rb_stderr = prep_stdio(stderr, FMODE_WRITABLE, rb_cIO, ""); rb_define_hooked_variable("$stderr", &rb_stderr, 0, stdout_setter); rb_define_hooked_variable("$>", &rb_stdout, 0, stdout_setter); -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦