Re: io_write()/fwrite() and EINTR on Solaris
From:
nobu.nokada@...
Date:
2002-11-08 01:48:56 UTC
List:
ruby-core #570
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