Change 16333 by gsar@onru on 2002/05/02 07:08:42
fix yet more race conditions related to fdopen() and dup2():
fclose() is not thread-safe when two FILE* structures point
to the same underlying fd, as it happens in perl's socket
handles; need to invalidate the fileno slot of one of the
FILE* structures, but unfortunately stdio has no interface
to do this; we can do little else but fiddle with the
FILE* structure directly (yuck! hope this could be done better
under native PerlIO in 5.8)
Affected files ...
.... //depot/maint-5.6/perl/doio.c#20 edit
.... //depot/maint-5.6/perl/embed.h#37 edit
.... //depot/maint-5.6/perl/embed.pl#53 edit
.... //depot/maint-5.6/perl/objXSUB.h#30 edit
.... //depot/maint-5.6/perl/perlapi.c#33 edit
.... //depot/maint-5.6/perl/proto.h#42 edit
Differences ...
==== //depot/maint-5.6/perl/doio.c#20 (text) ====
Index: perl/doio.c
--- perl/doio.c.~1~ Thu May 2 01:15:05 2002
+++ perl/doio.c Thu May 2 01:15:05 2002
@@ -51,6 +51,61 @@
#include <signal.h>
#endif
+#if defined(USE_ITHREADS)
+STATIC void
+S_invalidate_fileno(pTHX_ PerlIO *f)
+{
+ int fd = PerlIO_fileno(f);
+ PerlIO_flush(f);
+# if defined(USE_SFIO)
+# error "dont know how to set FILE.fileno under sfio"
+# endif
+ /* XXX this could use PerlIO_canset_fileno() and
+ * PerlIO_set_fileno() support from Configure */
+# if defined(__GLIBC__)
+ ((FILE*)f)->_fileno = -1;
+# elif defined(__sun__)
+ /* _file is just a char :-( */
+ ((FILE*)f)->_file = PerlLIO_dup(fd);
+# elif defined(__hpux)
+ ((FILE*)f)->__fileH = 0xff;
+ ((FILE*)f)->__fileL = 0xff;
+# elif defined(__FreeBSD__)
+ ((FILE*)f)->_file = -1;
+# elif defined(WIN32)
+# if defined(__BORLANDC__)
+ ((FILE*)f)->fd = PerlLIO_dup(fd);
+# else
+ ((FILE*)f)->_file = -1;
+# endif
+# else
+# error "dont know how to set FILE.fileno on your platform"
+# endif
+}
+#endif
+
+STATIC int
+S_io_sock_close(pTHX_ IO *io)
+{
+ int result;
+
+#if defined(USE_ITHREADS)
+ /* Avoid race condition: without this, the second fclose() will
+ * attempt to close() the same fd, and that fd could have been
+ * allocated by another thread between the two fclose() calls.
+ * It is potentially better to keep the two fds separate by making
+ * one a dup() of the other, but doing so muddies the perl-level
+ * semantics more than this hack. What should fileno(SOCK) return
+ * in that case? How about fcntl(SOCK,...)? Etc. */
+ if (PerlIO_fileno(IoIFP(io)) == PerlIO_fileno(IoOFP(io)))
+ invalidate_fileno(IoIFP(io));
+#endif
+ result = PerlIO_close(IoOFP(io));
+ PerlIO_close(IoIFP(io)); /* clear stdio, fd already closed */
+
+ return result;
+}
+
bool
Perl_do_open(pTHX_ GV *gv, register char *name, I32 len, int as_raw,
int rawmode, int rawperm, PerlIO *supplied_fp)
@@ -99,10 +154,8 @@
else if (IoTYPE(io) == IoTYPE_PIPE)
result = PerlProc_pclose(IoIFP(io));
else if (IoIFP(io) != IoOFP(io)) {
- if (IoOFP(io)) {
- result = PerlIO_close(IoOFP(io));
- PerlIO_close(IoIFP(io)); /* clear stdio, fd already closed */
- }
+ if (IoOFP(io))
+ result = io_sock_close(io);
else
result = PerlIO_close(IoIFP(io));
}
@@ -458,6 +511,10 @@
if (saveofp) {
PerlIO_flush(saveofp); /* emulate PerlIO_close() */
if (saveofp != saveifp) { /* was a socket? */
+#if defined(USE_ITHREADS)
+ if (fd == PerlIO_fileno(saveofp))
+ invalidate_fileno(saveofp);
+#endif
PerlIO_close(saveofp);
}
}
@@ -496,11 +553,21 @@
if (was_fdopen) {
/* need to close fp without closing underlying fd */
+#if defined(USE_THREADS)
+ /* we do do this only in the non-ithreads case because of
+ * the platform-specific nature of invalidate_fileno() */
+ invalidate_fileno(fp);
+ PerlIO_close(fp);
+#else
int ofd = PerlIO_fileno(fp);
int dupfd = PerlLIO_dup(ofd);
PerlIO_close(fp);
+ /* there is a race condition here that makes this code
+ * thread-unsafe. ofd could have been allocated by
+ * another thread at this point. */
PerlLIO_dup2(dupfd,ofd);
PerlLIO_close(dupfd);
+#endif
}
else
PerlIO_close(fp);
@@ -859,10 +926,8 @@
else if (IoTYPE(io) == IoTYPE_STD)
retval = TRUE;
else {
- if (IoOFP(io) && IoOFP(io) != IoIFP(io)) { /* a socket */
- retval = (PerlIO_close(IoOFP(io)) != EOF);
- PerlIO_close(IoIFP(io)); /* clear stdio, fd already closed */
- }
+ if (IoOFP(io) && IoOFP(io) != IoIFP(io)) /* a socket */
+ retval = (io_sock_close(io) != EOF);
else
retval = (PerlIO_close(IoIFP(io)) != EOF);
}
@@ -1400,7 +1465,7 @@
while (*t && isSPACE(*t))
++t;
- if (!*t && (dup2(1,2) != -1)) {
+ if (!*t && (PerlLIO_dup2(1,2) != -1)) {
s[-2] = '\0';
break;
}
==== //depot/maint-5.6/perl/embed.h#37 (text+w) ====
Index: perl/embed.h
--- perl/embed.h.~1~ Thu May 2 01:15:05 2002
+++ perl/embed.h Thu May 2 01:15:05 2002
@@ -863,6 +863,12 @@
#define avhv_index_sv S_avhv_index_sv
#define avhv_index S_avhv_index
#endif
+#if defined(PERL_IN_DOIO_C) || defined(PERL_DECL_PROT)
+#define io_sock_close S_io_sock_close
+#if defined(USE_ITHREADS)
+#define invalidate_fileno S_invalidate_fileno
+#endif
+#endif
#if defined(PERL_IN_DOOP_C) || defined(PERL_DECL_PROT)
#define do_trans_simple S_do_trans_simple
#define do_trans_count S_do_trans_count
@@ -2321,6 +2327,12 @@
#define avhv_index_sv(a) S_avhv_index_sv(aTHX_ a)
#define avhv_index(a,b,c) S_avhv_index(aTHX_ a,b,c)
#endif
+#if defined(PERL_IN_DOIO_C) || defined(PERL_DECL_PROT)
+#define io_sock_close(a) S_io_sock_close(aTHX_ a)
+#if defined(USE_ITHREADS)
+#define invalidate_fileno(a) S_invalidate_fileno(aTHX_ a)
+#endif
+#endif
#if defined(PERL_IN_DOOP_C) || defined(PERL_DECL_PROT)
#define do_trans_simple(a) S_do_trans_simple(aTHX_ a)
#define do_trans_count(a) S_do_trans_count(aTHX_ a)
@@ -4544,6 +4556,14 @@
#define S_avhv_index CPerlObj::S_avhv_index
#define avhv_index S_avhv_index
#endif
+#if defined(PERL_IN_DOIO_C) || defined(PERL_DECL_PROT)
+#define S_io_sock_close CPerlObj::S_io_sock_close
+#define io_sock_close S_io_sock_close
+#if defined(USE_ITHREADS)
+#define S_invalidate_fileno CPerlObj::S_invalidate_fileno
+#define invalidate_fileno S_invalidate_fileno
+#endif
+#endif
#if defined(PERL_IN_DOOP_C) || defined(PERL_DECL_PROT)
#define S_do_trans_simple CPerlObj::S_do_trans_simple
#define do_trans_simple S_do_trans_simple
==== //depot/maint-5.6/perl/embed.pl#53 (xtext) ====
Index: perl/embed.pl
--- perl/embed.pl.~1~ Thu May 2 01:15:05 2002
+++ perl/embed.pl Thu May 2 01:15:05 2002
@@ -2232,6 +2232,13 @@
s |I32 |avhv_index |AV* av|SV* sv|U32 hash
#endif
+#if defined(PERL_IN_DOIO_C) || defined(PERL_DECL_PROT)
+s |int |io_sock_close |IO *io
+#if defined(USE_ITHREADS)
+s |void |invalidate_fileno|PerlIO *f
+#endif
+#endif
+
#if defined(PERL_IN_DOOP_C) || defined(PERL_DECL_PROT)
s |I32 |do_trans_simple |SV *sv
s |I32 |do_trans_count |SV *sv
==== //depot/maint-5.6/perl/objXSUB.h#30 (text+w) ====
Index: perl/objXSUB.h
--- perl/objXSUB.h.~1~ Thu May 2 01:15:05 2002
+++ perl/objXSUB.h Thu May 2 01:15:05 2002
@@ -2268,6 +2268,10 @@
#endif
#if defined(PERL_IN_AV_C) || defined(PERL_DECL_PROT)
#endif
+#if defined(PERL_IN_DOIO_C) || defined(PERL_DECL_PROT)
+#if defined(USE_ITHREADS)
+#endif
+#endif
#if defined(PERL_IN_DOOP_C) || defined(PERL_DECL_PROT)
#endif
#if defined(PERL_IN_GV_C) || defined(PERL_DECL_PROT)
==== //depot/maint-5.6/perl/perlapi.c#33 (text+w) ====
Index: perl/perlapi.c
--- perl/perlapi.c.~1~ Thu May 2 01:15:05 2002
+++ perl/perlapi.c Thu May 2 01:15:05 2002
@@ -4082,6 +4082,10 @@
#endif
#if defined(PERL_IN_AV_C) || defined(PERL_DECL_PROT)
#endif
+#if defined(PERL_IN_DOIO_C) || defined(PERL_DECL_PROT)
+#if defined(USE_ITHREADS)
+#endif
+#endif
#if defined(PERL_IN_DOOP_C) || defined(PERL_DECL_PROT)
#endif
#if defined(PERL_IN_GV_C) || defined(PERL_DECL_PROT)
==== //depot/maint-5.6/perl/proto.h#42 (text+w) ====
Index: perl/proto.h
--- perl/proto.h.~1~ Thu May 2 01:15:05 2002
+++ perl/proto.h Thu May 2 01:15:05 2002
@@ -972,6 +972,13 @@
STATIC I32 S_avhv_index(pTHX_ AV* av, SV* sv, U32 hash);
#endif
+#if defined(PERL_IN_DOIO_C) || defined(PERL_DECL_PROT)
+STATIC int S_io_sock_close(pTHX_ IO *io);
+#if defined(USE_ITHREADS)
+STATIC void S_invalidate_fileno(pTHX_ PerlIO *f);
+#endif
+#endif
+
#if defined(PERL_IN_DOOP_C) || defined(PERL_DECL_PROT)
STATIC I32 S_do_trans_simple(pTHX_ SV *sv);
STATIC I32 S_do_trans_count(pTHX_ SV *sv);
End of Patch.