]> git.saurik.com Git - bison.git/commitdiff
portability: fix several issues with M4 subprocess.
authorJoel E. Denny <jdenny@clemson.edu>
Mon, 22 Feb 2010 23:09:19 +0000 (18:09 -0500)
committerJoel E. Denny <jdenny@clemson.edu>
Mon, 22 Feb 2010 23:09:19 +0000 (18:09 -0500)
M4's output pipe was not being drained upon fatal errors during
scan_skel.  As a result, broken-pipe messages from M4 were seen
on at least AIX, HP-UX, Solaris, and RHEL4, and this caused a
failure in the test suite.  The problem was that, on platforms
where the default disposition for SIGPIPE is ignore instead of
terminate, M4 sometimes saw fwrite fail with errno=EPIPE and
then reported it.  However, there's some sort of race condition,
because the new test group occasionally succeeded.
Reported by Albert Chin at
<http://lists.gnu.org/archive/html/bug-bison/2010-02/msg00004.html>.

There were also problems with the test suite livelocking on
Tru64 5.1b.  Reported by Didier Godefroy at
<http://lists.gnu.org/archive/html/bug-bison/2009-05/msg00005.html>.
Switching to create_pipe_bidi suggested by Akim Demaille.

To attempt to solve both of these problems, switch to gnulib's
create_pipe_bidi and register M4 process as a slave.  Along the
way, clean up file name conflict handling, which was affected by
the broken-pipe problem before the switch.
* NEWS (2.4.2): Document.
* THANKS (Didier Godefroy): Add.
* bootstrap.conf (gnulib_modules): Add pipe.
* gnulib: Update to latest to make sure we have all the latest
fixes.
* lib/Makefile.am (libbison_a_SOURCES): Remove subpipe.h and
subpipe.c.
* po/POTFILES.in (lib/subpipe.c): Remove.
* src/files.c (compute_output_file_names): Update invocations
of output_file_name_check.
(output_file_name_check): In the case that the grammar file
would be overwritten, use complain instead of fatal, but replace
the output file name with /dev/null.  Use the /dev/null solution
for the case of two conflicting output files as well because it
seems safer in case Bison one day tries to open both files at
the same time.
* src/files.h (output_file_name_check): Update prototype.
* src/output.c (output_skeleton): Use create_pipe_bidi and
wait_subprocess.  Assert that scan_skel completely drains the
pipe.
* src/scan-skel.l (at_directive_perform): Update
output_file_name_check invocation.
* tests/output.at (AT_CHECK_CONFLICTING_OUTPUT): Check that the
grammar file actually isn't overwritten.
(Conflicting output files: -o foo.y): Update expected output.
* tests/skeletons.at (Fatal errors but M4 continues producing
output): New test group.

19 files changed:
ChangeLog
NEWS
THANKS
bootstrap.conf
gnulib
lib/.cvsignore
lib/.gitignore
lib/Makefile.am
lib/subpipe.c [deleted file]
lib/subpipe.h [deleted file]
m4/.cvsignore
m4/.gitignore
po/POTFILES.in
src/files.c
src/files.h
src/output.c
src/scan-skel.l
tests/output.at
tests/skeletons.at

index b9fb00a89e115a3ead6b9baeebaa40479ee096aa..5fe369d6d0da705bbbfb143e2b92a29aa4032a1a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,55 @@
+2010-02-22  Joel E. Denny  <jdenny@ces.clemson.edu>
+
+       portability: fix several issues with M4 subprocess.
+
+       M4's output pipe was not being drained upon fatal errors during
+       scan_skel.  As a result, broken-pipe messages from M4 were seen
+       on at least AIX, HP-UX, Solaris, and RHEL4, and this caused a
+       failure in the test suite.  The problem was that, on platforms
+       where the default disposition for SIGPIPE is ignore instead of
+       terminate, M4 sometimes saw fwrite fail with errno=EPIPE and
+       then reported it.  However, there's some sort of race condition,
+       because the new test group occasionally succeeded.
+       Reported by Albert Chin at
+       <http://lists.gnu.org/archive/html/bug-bison/2010-02/msg00004.html>.
+
+       There were also problems with the test suite livelocking on
+       Tru64 5.1b.  Reported by Didier Godefroy at
+       <http://lists.gnu.org/archive/html/bug-bison/2009-05/msg00005.html>.
+       Switching to create_pipe_bidi suggested by Akim Demaille.
+
+       To attempt to solve both of these problems, switch to gnulib's
+       create_pipe_bidi and register M4 process as a slave.  Along the
+       way, clean up file name conflict handling, which was affected by
+       the broken-pipe problem before the switch.
+       * NEWS (2.4.2): Document.
+       * THANKS (Didier Godefroy): Add.
+       * bootstrap.conf (gnulib_modules): Add pipe.
+       * gnulib: Update to latest to make sure we have all the latest
+       fixes.
+       * lib/Makefile.am (libbison_a_SOURCES): Remove subpipe.h and
+       subpipe.c.
+       * po/POTFILES.in (lib/subpipe.c): Remove.
+       * src/files.c (compute_output_file_names): Update invocations
+       of output_file_name_check.
+       (output_file_name_check): In the case that the grammar file
+       would be overwritten, use complain instead of fatal, but replace
+       the output file name with /dev/null.  Use the /dev/null solution
+       for the case of two conflicting output files as well because it
+       seems safer in case Bison one day tries to open both files at
+       the same time.
+       * src/files.h (output_file_name_check): Update prototype.
+       * src/output.c (output_skeleton): Use create_pipe_bidi and
+       wait_subprocess.  Assert that scan_skel completely drains the
+       pipe.
+       * src/scan-skel.l (at_directive_perform): Update
+       output_file_name_check invocation.
+       * tests/output.at (AT_CHECK_CONFLICTING_OUTPUT): Check that the
+       grammar file actually isn't overwritten.
+       (Conflicting output files: -o foo.y): Update expected output.
+       * tests/skeletons.at (Fatal errors but M4 continues producing
+       output): New test group.
+
 2010-02-04  Joel E. Denny  <jdenny@ces.clemson.edu>
 
        Update POTFILES.
diff --git a/NEWS b/NEWS
index 9b33d13f0bb222c658ab46970324975e92596034..f11844de3738893ba112fccacdf2b52f4c7b8cc0 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,8 +3,11 @@ Bison News
 
 * Changes in version 2.4.2 (????-??-??):
 
-** Some portability problems in the testsuite that resulted in failures
-   on at least Solaris 2.7 have been fixed.
+** Some portability problems that resulted in failures and livelocks
+   in the test suite on some versions of at least Solaris, AIX, HP-UX,
+   RHEL4, and Tru64 have been fixed.  As part of those fixes, fatal
+   Bison errors no longer cause M4 to report a broken pipe on the
+   affected platforms.
 
 ** `%prec IDENTIFIER' requires IDENTIFIER to be defined separately.
 
diff --git a/THANKS b/THANKS
index d4f399444ec65d818187abfb4bfaa12d26ae789d..41b08c97251b3f51fb4f093be8f59b92cbc5fe3c 100644 (file)
--- a/THANKS
+++ b/THANKS
@@ -29,6 +29,7 @@ David J. MacKenzie        djm@gnu.org
 Derek M. Jones            derek@knosof.co.uk
 Di-an Jan                 dianj@freeshell.org
 Dick Streefland           dick.streefland@altium.nl
+Didier Godefroy           dg@ulysium.net
 Enrico Scholz             enrico.scholz@informatik.tu-chemnitz.de
 Eric Blake                ebb9@byu.net
 Evgeny Stambulchik        fnevgeny@plasma-gate.weizmann.ac.il
index 0c421074aa2138bea64254e7ade8efd546ee4582..fc5a0e962c9b14e2c17afb0a6f90be1a9d064c5c 100644 (file)
@@ -20,9 +20,10 @@ gnulib_modules='
   announce-gen argmatch assert config-h c-strcase configmake dirname
   error extensions fopen-safer gendocs getopt-gnu gettext
   git-version-gen hash inttypes javacomp-script javaexec-script
-  maintainer-makefile malloc mbswidth obstack quote quotearg stdbool
-  stpcpy strerror strtoul strverscmp unistd unistd-safer unlocked-io
-  update-copyright unsetenv verify warnings xalloc xalloc-die xstrndup
+  maintainer-makefile malloc mbswidth obstack pipe quote quotearg
+  stdbool stpcpy strerror strtoul strverscmp unistd unistd-safer
+  unlocked-io update-copyright unsetenv verify warnings xalloc
+  xalloc-die xstrndup
 '
 
 # Additional xgettext options to use.  Use "\\\newline" to break lines.
diff --git a/gnulib b/gnulib
index 102c411be0dfd9ac6aa0bb6450415e87bf0842ca..9d0ad652de159d08e5f679842f8a2a5658196361 160000 (submodule)
--- a/gnulib
+++ b/gnulib
@@ -1 +1 @@
-Subproject commit 102c411be0dfd9ac6aa0bb6450415e87bf0842ca
+Subproject commit 9d0ad652de159d08e5f679842f8a2a5658196361
index 5baf477953db58b5938e438e78f000455e5a491b..bc1393365ce1ac17e729e9336486067b10abf145 100644 (file)
@@ -1,10 +1,13 @@
 .deps
 Makefile
 Makefile.in
+alloca.h
+alloca.in.h
 argmatch.c
 argmatch.h
 basename-lgpl.c
 basename.c
+binary-io.h
 bitrotate.h
 c-ctype.c
 c-ctype.h
@@ -12,6 +15,8 @@ c-strcase.h
 c-strcasecmp.c
 c-strncasecmp.c
 charset.alias
+cloexec.c
+cloexec.h
 config.charset
 config.h
 config.hin
@@ -19,6 +24,7 @@ configmake.h
 dirname-lgpl.c
 dirname.c
 dirname.h
+dup-safer-flag.c
 dup-safer.c
 dup2.c
 errno.h
@@ -27,12 +33,16 @@ error.c
 error.h
 exitfail.c
 exitfail.h
+fatal-signal.c
+fatal-signal.h
 fcntl.c
 fcntl.h
 fcntl.in.h
+fd-safer-flag.c
 fd-safer.c
 fopen-safer.c
 fopen.c
+getdtablesize.c
 getopt.c
 getopt.h
 getopt.in.h
@@ -59,16 +69,45 @@ memchr.c
 memchr.valgrind
 obstack.c
 obstack.h
+open.c
 pipe-safer.c
+pipe.c
+pipe.h
+pipe2-safer.c
+pipe2.c
 quote.c
 quote.h
 quotearg.c
 quotearg.h
+rawmemchr.c
+rawmemchr.valgrind
 ref-add.sed
 ref-add.sin
 ref-del.sed
 ref-del.sin
+sched.h
+sched.in.h
+sig-handler.h
+sigaction.c
+signal.h
+signal.in.h
+sigprocmask.c
+spawn.h
+spawn.in.h
+spawn_faction_addclose.c
+spawn_faction_adddup2.c
+spawn_faction_addopen.c
+spawn_faction_destroy.c
+spawn_faction_init.c
+spawn_int.h
+spawnattr_destroy.c
+spawnattr_init.c
+spawnattr_setflags.c
+spawnattr_setsigmask.c
+spawni.c
+spawnp.c
 stamp-h1
+stat.c
 stdbool.h
 stdbool.in.h
 stdbool_.h
@@ -86,6 +125,8 @@ stdlib.h
 stdlib.in.h
 stdlib_.h
 stpcpy.c
+strchrnul.c
+strchrnul.valgrind
 streq.h
 strerror.c
 string.h
@@ -98,6 +139,13 @@ strtol.c
 strtoul.c
 strverscmp.c
 strverscmp.h
+sys
+sys_stat.h
+sys_stat.in.h
+sys_wait.h
+sys_wait.in.h
+time.h
+time.in.h
 unistd--.h
 unistd-safer.h
 unistd.h
@@ -109,6 +157,9 @@ uniwidth.h
 unlocked-io.h
 unsetenv.c
 verify.h
+w32spawn.h
+wait-process.c
+wait-process.h
 wchar.h
 wchar.in.h
 wchar_.h
index 38965d69c1bbbe621f878d4a7e5a6d80794a9e19..6746b557e343ecc2b2d55fc3821eadea5fef218c 100644 (file)
@@ -4,10 +4,13 @@
 /.deps
 /Makefile
 /Makefile.in
+/alloca.h
+/alloca.in.h
 /argmatch.c
 /argmatch.h
 /basename-lgpl.c
 /basename.c
+/binary-io.h
 /bitrotate.h
 /c-ctype.c
 /c-ctype.h
@@ -15,6 +18,8 @@
 /c-strcasecmp.c
 /c-strncasecmp.c
 /charset.alias
+/cloexec.c
+/cloexec.h
 /config.charset
 /config.h
 /config.hin
@@ -22,6 +27,7 @@
 /dirname-lgpl.c
 /dirname.c
 /dirname.h
+/dup-safer-flag.c
 /dup-safer.c
 /dup2.c
 /errno.h
 /error.h
 /exitfail.c
 /exitfail.h
+/fatal-signal.c
+/fatal-signal.h
 /fcntl.c
 /fcntl.h
 /fcntl.in.h
+/fd-safer-flag.c
 /fd-safer.c
 /fopen-safer.c
 /fopen.c
+/getdtablesize.c
 /getopt.c
 /getopt.h
 /getopt.in.h
 /memchr.valgrind
 /obstack.c
 /obstack.h
+/open.c
 /pipe-safer.c
+/pipe.c
+/pipe.h
+/pipe2-safer.c
+/pipe2.c
 /quote.c
 /quote.h
 /quotearg.c
 /quotearg.h
+/rawmemchr.c
+/rawmemchr.valgrind
 /ref-add.sed
 /ref-add.sin
 /ref-del.sed
 /ref-del.sin
+/sched.h
+/sched.in.h
+/sig-handler.h
+/sigaction.c
+/signal.h
+/signal.in.h
+/sigprocmask.c
+/spawn.h
+/spawn.in.h
+/spawn_faction_addclose.c
+/spawn_faction_adddup2.c
+/spawn_faction_addopen.c
+/spawn_faction_destroy.c
+/spawn_faction_init.c
+/spawn_int.h
+/spawnattr_destroy.c
+/spawnattr_init.c
+/spawnattr_setflags.c
+/spawnattr_setsigmask.c
+/spawni.c
+/spawnp.c
 /stamp-h1
+/stat.c
 /stdbool.h
 /stdbool.in.h
 /stdbool_.h
 /stdlib.in.h
 /stdlib_.h
 /stpcpy.c
+/strchrnul.c
+/strchrnul.valgrind
 /streq.h
 /strerror.c
 /string.h
 /strtoul.c
 /strverscmp.c
 /strverscmp.h
+/sys
+/sys_stat.h
+/sys_stat.in.h
+/sys_wait.h
+/sys_wait.in.h
+/time.h
+/time.in.h
 /unistd--.h
 /unistd-safer.h
 /unistd.h
 /unlocked-io.h
 /unsetenv.c
 /verify.h
+/w32spawn.h
+/wait-process.c
+/wait-process.h
 /wchar.h
 /wchar.in.h
 /wchar_.h
index 77ca6646c87e59aaac9d8a82953dcaae1ddbaf03..c2b4ec27fae6d57c49381d7cb0c30dfdd02b7d45 100644 (file)
@@ -37,7 +37,6 @@ timevars_sources = \
 # Non-gnulib sources in Bison's internal library.
 libbison_a_SOURCES += \
   get-errno.h get-errno.c \
-  subpipe.h subpipe.c \
   $(bitsets_sources) $(additional_bitsets_sources) $(timevars_sources)
 
 # The Yacc compatibility library.
diff --git a/lib/subpipe.c b/lib/subpipe.c
deleted file mode 100644 (file)
index 1b7c36d..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/* Subprocesses with pipes.
-
-   Copyright (C) 2002, 2004-2006, 2009-2010 Free Software Foundation,
-   Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-/* Written by Paul Eggert <eggert@twinsun.com>
-   and Florian Krohm <florian@edamail.fishkill.ibm.com>.  */
-
-#include <config.h>
-
-#include "subpipe.h"
-
-#include <errno.h>
-
-#include <signal.h>
-#if ! defined SIGCHLD && defined SIGCLD
-# define SIGCHLD SIGCLD
-#endif
-
-#include <stdlib.h>
-
-#include <unistd.h>
-#ifndef STDIN_FILENO
-# define STDIN_FILENO 0
-#endif
-#ifndef STDOUT_FILENO
-# define STDOUT_FILENO 1
-#endif
-#if ! HAVE_DUP2 && ! defined dup2
-# include <fcntl.h>
-# define dup2(f, t) (close (t), fcntl (f, F_DUPFD, t))
-#endif
-
-#if HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-#ifndef WEXITSTATUS
-# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8)
-#endif
-#ifndef WIFEXITED
-# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
-#endif
-
-#if HAVE_VFORK_H
-# include <vfork.h>
-#endif
-#if ! HAVE_WORKING_VFORK
-# define vfork fork
-#endif
-
-#include "error.h"
-#include "unistd-safer.h"
-
-#include "gettext.h"
-#define _(Msgid)  gettext (Msgid)
-
-#ifndef __attribute__
-/* This feature is available in gcc versions 2.5 and later.  */
-# if ! defined __GNUC__ || __GNUC__ < 2 || \
-(__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
-#  define __attribute__(Spec) /* empty */
-# endif
-#endif
-
-#ifndef ATTRIBUTE_UNUSED
-# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
-#endif
-
-
-/* Initialize this module.  */
-
-void
-init_subpipe (void)
-{
-#ifdef SIGCHLD
-  /* System V fork+wait does not work if SIGCHLD is ignored.  */
-  signal (SIGCHLD, SIG_DFL);
-#endif
-}
-
-
-/* Create a subprocess that is run as a filter.  ARGV is the
-   NULL-terminated argument vector for the subprocess.  Store read and
-   write file descriptors for communication with the subprocess into
-   FD[0] and FD[1]: input meant for the process can be written into
-   FD[0], and output from the process can be read from FD[1].  Return
-   the subprocess id.
-
-   To avoid deadlock, the invoker must not let incoming data pile up
-   in FD[1] while writing data to FD[0].  */
-
-pid_t
-create_subpipe (char const * const *argv, int fd[2])
-{
-  int pipe_fd[2];
-  int child_fd[2];
-  pid_t pid;
-
-  if (pipe_safer (child_fd) != 0 || pipe_safer (pipe_fd) != 0)
-    error (EXIT_FAILURE, errno, "pipe");
-  fd[0] = child_fd[1];
-  fd[1] = pipe_fd[0];
-  child_fd[1] = pipe_fd[1];
-
-  pid = vfork ();
-  if (pid < 0)
-    error (EXIT_FAILURE, errno, "fork");
-
-  if (! pid)
-    {
-      /* Child.  */
-      close (fd[0]);
-      close (fd[1]);
-      dup2 (child_fd[0], STDIN_FILENO);
-      close (child_fd[0]);
-      dup2 (child_fd[1], STDOUT_FILENO);
-      close (child_fd[1]);
-
-      /* The cast to (char **) rather than (char * const *) is needed
-        for portability to older hosts with a nonstandard prototype
-        for execvp.  */
-      execvp (argv[0], (char **) argv);
-
-      _exit (errno == ENOENT ? 127 : 126);
-    }
-
-  /* Parent.  */
-  close (child_fd[0]);
-  close (child_fd[1]);
-  return pid;
-}
-
-
-/* Wait for the subprocess to exit.  */
-
-void
-reap_subpipe (pid_t pid, char const *program)
-{
-#if HAVE_WAITPID || defined waitpid
-  int wstatus;
-  if (waitpid (pid, &wstatus, 0) < 0)
-    error (EXIT_FAILURE, errno, "waitpid");
-  else
-    {
-      int status = WIFEXITED (wstatus) ? WEXITSTATUS (wstatus) : -1;
-      if (status)
-       error (EXIT_FAILURE, 0,
-              _(status == 126
-                ? "subsidiary program `%s' could not be invoked"
-                : status == 127
-                ? "subsidiary program `%s' not found"
-                : status < 0
-                ? "subsidiary program `%s' failed"
-                : "subsidiary program `%s' failed (exit status %d)"),
-              program, status);
-    }
-#endif
-}
-
-void
-end_of_output_subpipe (pid_t pid ATTRIBUTE_UNUSED,
-                      int fd[2] ATTRIBUTE_UNUSED)
-{
-}
diff --git a/lib/subpipe.h b/lib/subpipe.h
deleted file mode 100644 (file)
index ff791a8..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Subprocesses with pipes.
-   Copyright (C) 2002, 2004-2005, 2009-2010 Free Software Foundation,
-   Inc.
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-/* Written by Paul Eggert <eggert@twinsun.com>
-   and Florian Krohm <florian@edamail.fishkill.ibm.com>.  */
-
-#if HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-void init_subpipe (void);
-pid_t create_subpipe (char const * const *, int[2]);
-void end_of_output_subpipe (pid_t, int[2]);
-void reap_subpipe (pid_t, char const *);
index d4016ed6c0010b465b362f5ba2f2171d1e664bf5..0ebd70a58cb3c54492653498cc8cbf8c6fb2b219 100644 (file)
@@ -1,7 +1,9 @@
 00gnulib.m4
 absolute-header.m4
+alloca.m4
 argmatch.m4
 assert.m4
+cloexec.m4
 config-h.m4
 dirname.m4
 dos.m4
@@ -12,10 +14,12 @@ errno_h.m4
 error.m4
 exitfail.m4
 extensions.m4
+fatal-signal.m4
 fcntl-o.m4
 fcntl.m4
 fcntl_h.m4
 fopen.m4
+getdtablesize.m4
 getopt.m4
 getpagesize.m4
 gettext.m4
@@ -48,13 +52,26 @@ mbstate_t.m4
 mbswidth.m4
 memchr.m4
 mmap-anon.m4
+mode_t.m4
 multiarch.m4
 nls.m4
+open.m4
+pipe.m4
+pipe2.m4
 po.m4
+posix_spawn.m4
 progtest.m4
 quote.m4
 quotearg.m4
+rawmemchr.m4
+sched_h.m4
 setenv.m4
+sig_atomic_t.m4
+sigaction.m4
+signal_h.m4
+signalblocking.m4
+spawn_h.m4
+stat.m4
 stdbool.m4
 stddef_h.m4
 stdint.m4
@@ -63,6 +80,7 @@ stdio-safer.m4
 stdio_h.m4
 stdlib_h.m4
 stpcpy.m4
+strchrnul.m4
 strerror.m4
 string_h.m4
 strndup.m4
@@ -70,10 +88,14 @@ strnlen.m4
 strtol.m4
 strtoul.m4
 strverscmp.m4
+sys_stat_h.m4
+sys_wait_h.m4
 threadlib.m4
+time_h.m4
 unistd-safer.m4
 unistd_h.m4
 unlocked-io.m4
+wait-process.m4
 warn-on-use.m4
 warning.m4
 warnings.m4
index 6b147a8032e3746e61b9dc6b90573b04ad256165..bdae61af92c60d04de57a5aa76b7b5d0c9aa267b 100644 (file)
@@ -1,7 +1,9 @@
 /00gnulib.m4
 /absolute-header.m4
+/alloca.m4
 /argmatch.m4
 /assert.m4
+/cloexec.m4
 /config-h.m4
 /dirname.m4
 /dos.m4
 /error.m4
 /exitfail.m4
 /extensions.m4
+/fatal-signal.m4
 /fcntl-o.m4
 /fcntl.m4
 /fcntl_h.m4
 /fopen.m4
+/getdtablesize.m4
 /getopt.m4
 /getpagesize.m4
 /gettext.m4
 /mbswidth.m4
 /memchr.m4
 /mmap-anon.m4
+/mode_t.m4
 /multiarch.m4
 /nls.m4
+/open.m4
+/pipe.m4
+/pipe2.m4
 /po.m4
+/posix_spawn.m4
 /progtest.m4
 /quote.m4
 /quotearg.m4
+/rawmemchr.m4
+/sched_h.m4
 /setenv.m4
+/sig_atomic_t.m4
+/sigaction.m4
+/signal_h.m4
+/signalblocking.m4
+/spawn_h.m4
+/stat.m4
 /stdbool.m4
 /stddef_h.m4
 /stdint.m4
@@ -63,6 +80,7 @@
 /stdio_h.m4
 /stdlib_h.m4
 /stpcpy.m4
+/strchrnul.m4
 /strerror.m4
 /string_h.m4
 /strndup.m4
 /strtol.m4
 /strtoul.m4
 /strverscmp.m4
+/sys_stat_h.m4
+/sys_wait_h.m4
 /threadlib.m4
+/time_h.m4
 /unistd-safer.m4
 /unistd_h.m4
 /unlocked-io.m4
+/wait-process.m4
 /warn-on-use.m4
 /warning.m4
 /warnings.m4
index 5d6a216b69dfc14b9ce7d93b2056e8b6b992555f..b2b8b5d53142a4f15ddcccbed3b56a799e036b6c 100644 (file)
@@ -22,6 +22,5 @@ lib/error.c
 lib/getopt.c
 lib/obstack.c
 lib/quotearg.c
-lib/subpipe.c
 lib/timevar.c
 lib/xalloc-die.c
index 9761de924c59cf844b3c006587f69ccd96b7eb6f..e8bb20038d28e00a21ebe348030427f0aa6d7415 100644 (file)
@@ -328,21 +328,21 @@ compute_output_file_names (void)
     {
       if (! spec_graph_file)
        spec_graph_file = concat2 (all_but_tab_ext, ".dot");
-      output_file_name_check (spec_graph_file);
+      output_file_name_check (&spec_graph_file);
     }
 
   if (xml_flag)
     {
       if (! spec_xml_file)
        spec_xml_file = concat2 (all_but_tab_ext, ".xml");
-      output_file_name_check (spec_xml_file);
+      output_file_name_check (&spec_xml_file);
     }
 
   if (report_flag)
     {
       if (!spec_verbose_file)
         spec_verbose_file = concat2 (all_but_tab_ext, OUTPUT_EXT);
-      output_file_name_check (spec_verbose_file);
+      output_file_name_check (&spec_verbose_file);
     }
 
   free (all_but_tab_ext);
@@ -351,18 +351,37 @@ compute_output_file_names (void)
 }
 
 void
-output_file_name_check (char const *file_name)
+output_file_name_check (char **file_name)
 {
-  if (0 == strcmp (file_name, grammar_file))
-    fatal (_("refusing to overwrite the input file %s"), quote (file_name));
-  {
-    int i;
-    for (i = 0; i < file_names_count; i++)
-      if (0 == strcmp (file_names[i], file_name))
-        warn (_("conflicting outputs to file %s"), quote (file_name));
-  }
-  file_names = xnrealloc (file_names, ++file_names_count, sizeof *file_names);
-  file_names[file_names_count-1] = xstrdup (file_name);
+  bool conflict = false;
+  if (0 == strcmp (*file_name, grammar_file))
+    {
+      complain (_("refusing to overwrite the input file %s"),
+                quote (*file_name));
+      conflict = true;
+    }
+  else
+    {
+      int i;
+      for (i = 0; i < file_names_count; i++)
+        if (0 == strcmp (file_names[i], *file_name))
+          {
+            warn (_("conflicting outputs to file %s"),
+                  quote (*file_name));
+            conflict = true;
+          }
+    }
+  if (conflict)
+    {
+      free (*file_name);
+      *file_name = strdup ("/dev/null");
+    }
+  else
+    {
+      file_names = xnrealloc (file_names, ++file_names_count,
+                              sizeof *file_names);
+      file_names[file_names_count-1] = xstrdup (*file_name);
+    }
 }
 
 void
index e8f28bff12d21807e38ed16234fd27b8377d11af..536678344f6a17c80ac697c76a19a42ae0e2de54 100644 (file)
@@ -63,7 +63,7 @@ extern char *all_but_ext;
 
 void compute_output_file_names (void);
 void output_file_names_free (void);
-void output_file_name_check (char const *file_name);
+void output_file_name_check (char **file_name);
 
 FILE *xfopen (const char *name, const char *mode);
 void xfclose (FILE *ptr);
index 6a05704b0a25761452b2bf72d47671bc91a04bb1..212fa83208ab52c747aceac2a302efc1ca4cca0a 100644 (file)
 #include <configmake.h>
 #include <error.h>
 #include <get-errno.h>
+#include <pipe.h>
 #include <quotearg.h>
-#include <subpipe.h>
 #include <timevar.h>
+#include <wait-process.h>
 
 #include "complain.h"
 #include "files.h"
@@ -551,13 +552,14 @@ output_skeleton (void)
     assert (i <= ARRAY_CARDINALITY (argv));
   }
 
-  init_subpipe ();
-  pid = create_subpipe (argv, filter_fd);
+  /* The ugly cast is because gnulib gets the const-ness wrong.  */
+  pid = create_pipe_bidi ("m4", m4, (char **)(void*)argv, false, true,
+                          true, filter_fd);
   free (full_m4sugar);
   free (full_m4bison);
   free (full_skeleton);
 
-  out = fdopen (filter_fd[0], "w");
+  out = fdopen (filter_fd[1], "w");
   if (! out)
     error (EXIT_FAILURE, get_errno (),
           "fdopen");
@@ -576,14 +578,17 @@ output_skeleton (void)
 
   /* Read and process m4's output.  */
   timevar_push (TV_M4);
-  end_of_output_subpipe (pid, filter_fd);
-  in = fdopen (filter_fd[1], "r");
+  in = fdopen (filter_fd[0], "r");
   if (! in)
     error (EXIT_FAILURE, get_errno (),
           "fdopen");
   scan_skel (in);
+  /* scan_skel should have read all of M4's output.  Otherwise, when we
+     close the pipe, we risk letting M4 report a broken-pipe to the
+     Bison user.  */
+  aver (feof (in));
   xfclose (in);
-  reap_subpipe (pid, m4);
+  wait_subprocess (pid, "m4", false, false, true, true, NULL);
   timevar_pop (TV_M4);
 }
 
index 90a52ddaf1eb9a1374d7c34ec5cb344e2edff24a..cd30576b4461e83c913252db0de89ae87fad6904 100644 (file)
@@ -107,7 +107,7 @@ static void fail_for_invalid_at (char const *at);
   "@@" { obstack_1grow (&obstack_for_string, '@'); }
   "@{" { obstack_1grow (&obstack_for_string, '['); }
   "@}" { obstack_1grow (&obstack_for_string, ']'); }
-  "@`" /* Emtpy.  Useful for starting an argument
+  "@`" /* Empty.  Useful for starting an argument
           that begins with whitespace. */
   @\n  /* Empty.  */
 
@@ -174,10 +174,10 @@ skel_scanner_free (void)
   yylex_destroy ();
 }
 
-static
-void at_directive_perform (int at_directive_argc,
-                           char *at_directive_argv[],
-                           char **outnamep, int *out_linenop)
+static void
+at_directive_perform (int at_directive_argc,
+                      char *at_directive_argv[],
+                      char **outnamep, int *out_linenop)
 {
   if (0 == strcmp (at_directive_argv[0], "@basename"))
     {
@@ -276,7 +276,7 @@ void at_directive_perform (int at_directive_argc,
           xfclose (yyout);
         }
       *outnamep = xstrdup (at_directive_argv[1]);
-      output_file_name_check (*outnamep);
+      output_file_name_check (outnamep);
       yyout = xfopen (*outnamep, "w");
       *out_linenop = 1;
     }
index f8e165322c881cf86bde3170d76729b331354b67..999ca18420ca2621c2f96497b2a56e608c68660b 100644 (file)
@@ -137,7 +137,9 @@ AT_DATA([$1],
 foo: {};
 ]])
 
+[cp ]$1[ expout]
 AT_BISON_CHECK([$3 $1], $5, [], [$4])
+AT_CHECK([[cat $1]], [[0]], [expout])
 AT_CLEANUP
 ])
 
@@ -157,7 +159,7 @@ AT_CHECK_CONFLICTING_OUTPUT([foo.y],
 ])
 
 AT_CHECK_CONFLICTING_OUTPUT([foo.y], [], [-o foo.y],
-[foo.y: fatal error: refusing to overwrite the input file `foo.y'
+[foo.y: refusing to overwrite the input file `foo.y'
 ], 1)
 
 
index f96d13e2c24540c6ef35ae9b235fa01cbe61b042..18acbc01e7b4fc968f190a680fc5ddbdde69ec1f 100644 (file)
@@ -288,3 +288,45 @@ foo.y:1.5-6: fatal error: M4 should exit immediately here
 ]])
 
 AT_CLEANUP
+
+
+## ------------------------------------------------ ##
+## Fatal errors but M4 continues producing output.  ##
+## ------------------------------------------------ ##
+
+# At one time, if Bison encountered a fatal error during M4 processing,
+# Bison failed to drain M4's output pipe.  The result was a SIGPIPE.
+# On some platforms, the default disposition for SIGPIPE is terminate,
+# which was fine.  On others, it's ignore, which caused M4 to report
+# the broken pipe to the user, but we don't want to bother the user with
+# that.
+
+# There is a race condition somewhere.  That is, before the associated
+# fix, running this test group many times in a row would occasionally
+# produce a pass among all the failures.
+
+AT_SETUP([[Fatal errors but M4 continues producing output]])
+
+AT_DATA([[gen-skel.pl]],
+[[use warnings;
+use strict;
+my $M4 = "m4";
+my $DNL = "d"."nl";
+print "${M4}_divert_push(0)$DNL\n";
+print '@output(@,@)', "\n";
+(print "garbage"x10, "\n") for (1..1000);
+print "${M4}_divert_pop(0)\n";
+]])
+AT_CHECK([[perl gen-skel.pl > skel.c || exit 77]])
+
+AT_DATA([[input.y]],
+[[%skeleton "./skel.c"
+%%
+start: ;
+]])
+
+AT_BISON_CHECK([[input.y]], [[1]], [[]],
+[[input.y: fatal error: too many arguments for @output directive in skeleton
+]])
+
+AT_CLEANUP