Hi,

At Fri, 8 Nov 2002 03:16:50 +0900,
Jos Backus wrote:
> Hm, the return value of the fwrite() call in w_byten() is not checked at all,
> that seems to be a potential troublespot to me.  Perhaps move the fwrite()
> wrapper into its own function (rb_safe_write()?) and call it in both places
> instead?

Perhaps, rb_io_fwrite()?

I'm not sure BROKEN_FWRITE is better or not.


Index: io.c =================================================================== RCS file: /cvs/ruby/src/ruby/io.c,v retrieving revision 1.167 diff -u -2 -p -r1.167 io.c --- io.c 29 Oct 2002 21:35:28 -0000 1.167 +++ io.c 8 Nov 2002 01:34:58 -0000 @@ -25,5 +25,9 @@ #include <errno.h> +#ifdef BROKEN_FWRITE +# include <signal.h> +#endif + #if defined(MSDOS) || defined(__BOW__) || defined(__CYGWIN__) || defined(NT) || defined(__human68k__) || defined(__EMX__) || defined(__BEOS__) # define NO_SAFE_RENAME @@ -352,4 +356,76 @@ rb_io_wait_writable(f) /* writing functions */ +#ifdef BROKEN_FWRITE +# ifdef HAVE_SIGPROCMASK +static sigset_t fwrite_mask; +# define Init_fwrite() (sigemptyset(&fwrite_mask), sigaddset(&fwrite_mask, SIGVTALRM)) +# else +# define Init_fwrite() (void)0 +# endif + +static int +safe_fwrite(ptr, size, len, f) + const void *ptr; + int size, len; + FILE *f; +{ + int n; +# ifdef HAVE_SIGPROCMASK + sigset_t set; + sigprocmask(SIG_BLOCK, &fwrite_mask, &set); +# else + int mask = siggetmask(); + sigblock(sigmask(SIGVTALRM)); +# endif + + n = fwrite(ptr, size, len, f); + +# ifdef HAVE_SIGPROCMASK + sigprocmask(SIG_UNBLOCK, &set, 0); +# else + sigsetmask(mask); +# endif + return n; +} + +#else +# define safe_fwrite(p, n, f) fwrite((p), 1, (n), (f)) +#endif + +long +rb_io_fwrite(ptr, len, f) + const char *ptr; + long len; + FILE *f; +{ + long n, r; + + if ((n = len) <= 0) return n; +#if defined(__human68k__) || defined(sun) + do { + if (fputc(*ptr, f) == EOF) { + if (!ferror(f)) break; + if (rb_io_wait_writable(fileno(f))) { + clearerr(f); + continue; + } + return -1L; + } + p++; + } while (--n > 0); +#else + while (ptr += (r = safe_fwrite(ptr, n, f)), (n -= r) > 0) { + if (ferror(f)) { + if (rb_io_wait_writable(fileno(f))) { + clearerr(f); + continue; + } + return -1L; + } + } +#endif + return len - n; +} + static VALUE io_write(io, str) @@ -358,6 +434,5 @@ io_write(io, str) OpenFile *fptr; FILE *f; - long n, r; - register char *ptr; + long n; rb_secure(4); @@ -375,25 +450,6 @@ io_write(io, str) f = GetWriteFile(fptr); - ptr = RSTRING(str)->ptr; - n = RSTRING(str)->len; -#ifdef __human68k__ - do { - if (fputc(*ptr++, f) == EOF) { - if (ferror(f)) rb_sys_fail(fptr->path); - break; - } - } while (--n > 0); -#else - while (ptr += (r = fwrite(ptr, 1, n, f)), (n -= r) > 0) { - if (ferror(f)) { - if (rb_io_wait_writable(fileno(f))) { - clearerr(f); - continue; - } - rb_sys_fail(fptr->path); - } - } -#endif - n = ptr - RSTRING(str)->ptr; + n = rb_io_fwrite(RSTRING(str)->ptr, RSTRING(str)->len, f); + if (n == -1L) rb_sys_fail(fptr->path); if (fptr->mode & FMODE_SYNC) { io_fflush(f, fptr); Index: marshal.c =================================================================== RCS file: /cvs/ruby/src/ruby/marshal.c,v retrieving revision 1.73 diff -u -2 -p -r1.73 marshal.c --- marshal.c 17 Oct 2002 10:20:52 -0000 1.73 +++ marshal.c 8 Nov 2002 01:33:38 -0000 @@ -103,5 +103,6 @@ w_byten(s, n, arg) { if (arg->fp) { - fwrite(s, 1, n, arg->fp); + if (rb_io_fwrite(s, n, arg->fp) < 0) + rb_sys_fail(0); } else { Index: rubyio.h =================================================================== RCS file: /cvs/ruby/src/ruby/rubyio.h,v retrieving revision 1.20 diff -u -2 -p -r1.20 rubyio.h --- rubyio.h 2 Oct 2002 14:59:25 -0000 1.20 +++ rubyio.h 8 Nov 2002 01:31:21 -0000 @@ -60,4 +60,5 @@ FILE *rb_fdopen _((int, const char*)); int rb_getc _((FILE*)); long rb_io_fread _((char *, long, FILE *)); +long rb_io_fwrite _((const char *, long, FILE *)); int rb_io_mode_flags _((const char*)); void rb_io_check_writable _((OpenFile*));
-- Nobu Nakada