bug-bison
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Bison fix to not generate a temporary file


From: Paul Eggert
Subject: Bison fix to not generate a temporary file
Date: Sun, 20 Oct 2002 00:39:11 -0700 (PDT)

> From: Akim Demaille <address@hidden>
> Date: 14 Oct 2002 10:52:06 +0200
> 
> Florian had signed all the FSF papers, but finally lacked time to
> finish what he was on.

I finally got around to looking into this problem and installed the
following patch.  As part of the process I rewrote Florian Krohm's
changes fairly thoroughly, but if you look hard you can still see a
few lines of his code.  In particular, I did not use his approach of
buffering the output in memory and then sending it off to m4 all in
one go: instead, output is sent down the pipe as the output is
generated.


2002-10-19  Paul Eggert  <address@hidden>

        Do not create a temporary file, as that involves security and
        cleanup headaches.  Instead, use a pair of pipes.
        Derived from a suggestion by Florian Krohm.
        * lib/subpipe.c, lib/subpipe.h, m4/subpipe.m4: New files.
        * lib/mkstemp.c, lib/readpipe.c, lib/tempname.c, m4/mkstemp.m4: Remove.
        * configure.ac (UTILS_FUNC_MKSTEMP, jm_PREREQ_TEMPNAME): Remove.
        (BISON_PREREQ_SUBPIPE): Add.
        * lib/Makefile.am (libbison_a_SOURCES): Remove readpipe.c.
        Add subpipe.h, subpipe.c.
        * m4/Makefile.am (EXTRA_DIST): Remove mkstemp.m4.  Add subpipe.m4.
        * po/POTFILES.in: Add lib/subpipe.c.
        * src/output.c: Include "subpipe.h".
        (m4_invoke): Remove decl.
        (scan_skel): New decl.
        (output_skeleton): Use pipe rather than temporary file for m4 input.
        Check that m4sugar.m4 is readable, to avoid deadlock.
        Check for pipe I/O error.
        * src/scan-skel.l (readpipe): Remove decl.
        (scan_skel): New function, to be used in place of m4_invoke.
        Read from stream rather than file.

Index: configure.ac
===================================================================
RCS file: /cvsroot/bison/bison/configure.ac,v
retrieving revision 1.14
diff -p -u -r1.14 configure.ac
--- configure.ac        16 Oct 2002 06:32:07 -0000      1.14
+++ configure.ac        20 Oct 2002 06:03:43 -0000
@@ -82,7 +82,6 @@ AC_FUNC_ALLOCA
 AC_FUNC_OBSTACK
 AC_FUNC_ERROR_AT_LINE
 AC_FUNC_STRNLEN
-UTILS_FUNC_MKSTEMP
 AC_CHECK_FUNCS(setlocale)
 AC_CHECK_DECLS([free, getenv, getopt,
                 stpcpy, strchr, strspn, strnlen,
@@ -94,8 +93,8 @@ AC_FUNC_REALLOC
 jm_PREREQ_QUOTEARG
 jm_FUNC_ARGMATCH
 jm_PREREQ_ERROR
-jm_PREREQ_TEMPNAME
 AM_WITH_DMALLOC
+BISON_PREREQ_SUBPIPE
 BISON_PREREQ_TIMEVAR
 
 # Gettext.
Index: lib/Makefile.am
===================================================================
RCS file: /cvsroot/bison/bison/lib/Makefile.am,v
retrieving revision 1.32
diff -p -u -r1.32 Makefile.am
--- lib/Makefile.am     17 Oct 2002 01:27:56 -0000      1.32
+++ lib/Makefile.am     20 Oct 2002 06:03:44 -0000
@@ -35,7 +35,7 @@ libbison_a_SOURCES = \
   getopt.h getopt.c getopt1.c \
   hash.h hash.c \
   quote.h quote.c quotearg.h quotearg.c \
-  readpipe.c unlocked-io.h \
+  subpipe.h subpipe.c unlocked-io.h \
   xalloc.h xmalloc.c xstrdup.c xstrndup.c \
   $(bitsets_sources) $(additional_bitsets_sources) $(timevars_sources)
 
Index: m4/Makefile.am
===================================================================
RCS file: /cvsroot/bison/bison/m4/Makefile.am,v
retrieving revision 1.20
diff -p -u -r1.20 Makefile.am
--- m4/Makefile.am      13 Oct 2002 19:39:29 -0000      1.20
+++ m4/Makefile.am      20 Oct 2002 06:03:44 -0000
@@ -1,6 +1,6 @@
 ## Process this file with automake to produce Makefile.in -*-Makefile-*-
 EXTRA_DIST = \
   dmalloc.m4 error.m4 \
-  m4.m4 mbrtowc.m4 memcmp.m4 mkstemp.m4 \
-  prereq.m4 timevar.m4 warning.m4 \
+  m4.m4 mbrtowc.m4 memcmp.m4 \
+  prereq.m4 subpipe.m4 timevar.m4 warning.m4 \
   gettext.m4 iconv.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 progtest.m4
Index: po/POTFILES.in
===================================================================
RCS file: /cvsroot/bison/bison/po/POTFILES.in,v
retrieving revision 1.15
diff -p -u -r1.15 POTFILES.in
--- po/POTFILES.in      27 Sep 2002 14:50:18 -0000      1.15
+++ po/POTFILES.in      20 Oct 2002 06:03:44 -0000
@@ -20,5 +20,6 @@ lib/error.c
 lib/getopt.c
 lib/obstack.c
 lib/quotearg.c
+lib/subpipe.c
 lib/timevar.c
 lib/xmalloc.c
Index: src/output.c
===================================================================
RCS file: /cvsroot/bison/bison/src/output.c,v
retrieving revision 1.197
diff -p -u -r1.197 output.c
--- src/output.c        20 Oct 2002 06:01:07 -0000      1.197
+++ src/output.c        20 Oct 2002 06:03:44 -0000
@@ -88,6 +88,7 @@
 #include "system.h"
 #include "quotearg.h"
 #include "error.h"
+#include "subpipe.h"
 #include "getargs.h"
 #include "files.h"
 #include "gram.h"
@@ -99,7 +100,7 @@
 #include "muscle_tab.h"
 
 /* From src/scan-skel.l. */
-void m4_invoke PARAMS ((const char *definitions));
+void scan_skel (FILE *);
 
 
 static struct obstack format_obstack;
@@ -526,23 +527,59 @@ prepare_actions (void)
 static void
 output_skeleton (void)
 {
-  /* Store the definition of all the muscles. */
-  const char *tempdir = getenv ("TMPDIR");
-  char *tempfile = NULL;
-  FILE *out = NULL;
-  int fd;
-
-  if (tempdir == NULL)
-    tempdir = DEFAULT_TMPDIR;
-  tempfile = xmalloc (strlen (tempdir) + 11);
-  sprintf (tempfile, "%s/bsnXXXXXX", tempdir);
-  fd = mkstemp (tempfile);
-  if (fd == -1)
-    error (EXIT_FAILURE, errno, "%s", tempfile);
-
-  out = fdopen (fd, "w");
-  if (out == NULL)
-    error (EXIT_FAILURE, errno, "%s", tempfile);
+  FILE *in;
+  FILE *out;
+  int filter_fd[2];
+  char const *argv[7];
+  pid_t pid;
+
+  /* Compute the names of the package data dir and skeleton file.
+     Test whether m4sugar.m4 is readable, to check for proper
+     installation.  A faulty installation can cause deadlock, so a
+     cheap sanity check is worthwhile.  */
+  char const m4sugar[] = "m4sugar/m4sugar.m4";
+  char *full_path;
+  char const *p;
+  char const *m4 = (p = getenv ("M4")) ? p : M4;
+  char const *pkgdatadir = (p = getenv ("BISON_PKGDATADIR")) ? p : PKGDATADIR;
+  size_t skeleton_size = strlen (skeleton) + 1;
+  size_t pkgdatadirlen = strlen (pkgdatadir);
+  while (pkgdatadirlen && pkgdatadir[pkgdatadirlen - 1] == '/')
+    pkgdatadirlen--;
+  full_path = xmalloc (pkgdatadirlen + 1
+                      + (skeleton_size < sizeof m4sugar
+                         ? sizeof m4sugar : skeleton_size));
+  strcpy (full_path, pkgdatadir);
+  full_path[pkgdatadirlen] = '/';
+  strcpy (full_path + pkgdatadirlen + 1, m4sugar);
+  in = fopen (full_path, "r");
+  if (! in || fclose (in) != 0)
+    error (EXIT_FAILURE, errno, "%s", full_path);
+  strcpy (full_path + pkgdatadirlen + 1, skeleton);
+
+  /* Create an m4 subprocess connected to us via two pipes.  */
+
+  if (trace_flag & trace_tools)
+    fprintf (stderr, "running: %s -I %s %s - %s\n",
+            m4, pkgdatadir, m4sugar, full_path);
+
+  argv[0] = m4;
+  argv[1] = "-I";
+  argv[2] = pkgdatadir;
+  argv[3] = m4sugar;
+  argv[4] = "-";
+  argv[5] = full_path;
+  argv[6] = NULL;
+
+  init_subpipe ();
+  pid = create_subpipe (argv, filter_fd);
+  free (full_path);
+
+  out = fdopen (filter_fd[0], "w");
+  if (! out)
+    error (EXIT_FAILURE, errno, "fdopen");
+
+  /* Output the definitions of all the muscles.  */
 
   /* There are no comments, especially not `#': we do want M4 expansion
      after `#': think of CPP macros!  */
@@ -559,17 +596,21 @@ output_skeleton (void)
 
   fputs ("m4_wrap([m4_divert_pop(0)])\n", out);
   fputs ("m4_divert_push(0)dnl\n", out);
+  if (ferror (out))
+    error (EXIT_FAILURE, 0, "pipe output error");
   xfclose (out);
 
+  /* Read and process m4's output.  */
   timevar_push (TV_M4);
-  m4_invoke (tempfile);
+  in = fdopen (filter_fd[1], "r");
+  if (! in)
+    error (EXIT_FAILURE, errno, "fdopen");
+  scan_skel (in);
+  if (ferror (in))
+    error (EXIT_FAILURE, 0, "pipe input error");
+  xfclose (in);
+  reap_subpipe (pid, m4);
   timevar_pop (TV_M4);
-
-  /* If `debugging', keep this file alive. */
-  if (!(trace_flag & trace_tools))
-    unlink (tempfile);
-
-  free (tempfile);
 }
 
 static void
Index: src/scan-skel.l
===================================================================
RCS file: /cvsroot/bison/bison/src/scan-skel.l,v
retrieving revision 1.13
diff -p -u -r1.13 scan-skel.l
--- src/scan-skel.l     31 Jul 2002 21:52:00 -0000      1.13
+++ src/scan-skel.l     20 Oct 2002 06:03:45 -0000
@@ -52,47 +52,16 @@ static char *yyoutname = NULL;
 <<EOF>>          xfclose (yyout); free (yyoutname); return EOF;
 %%
 
-/* From lib/readpipe.c.  */
-FILE *readpipe PARAMS ((const char *, ...));
+/*------------------------.
+| Scan a Bison skeleton.  |
+`------------------------*/
 
-/*----------------------.
-| Run our backend, M4.  |
-`----------------------*/
-
-void m4_invoke PARAMS ((const char *definitions));
+void scan_skel (FILE *);
 
 void
-m4_invoke (const char *definitions)
+scan_skel (FILE *in)
 {
-  /* Invoke m4 on the definition of the muscles, and the skeleton. */
-  const char *bison_pkgdatadir = getenv ("BISON_PKGDATADIR");
-  const char *m4 = getenv ("M4");
-  int pkg_data_len;
-  char *full_skeleton;
-
-  if (!m4)
-    m4 = M4;
-  if (!bison_pkgdatadir)
-    bison_pkgdatadir = PKGDATADIR;
-  pkg_data_len = strlen (bison_pkgdatadir);
-  full_skeleton = XMALLOC (char, pkg_data_len + strlen (skeleton) + 2);
-  if (bison_pkgdatadir[pkg_data_len-1] == '/')
-    sprintf (full_skeleton, "%s%s", bison_pkgdatadir, skeleton);
-  else
-    sprintf (full_skeleton, "%s/%s", bison_pkgdatadir, skeleton);
-  if (trace_flag & trace_tools)
-    fprintf (stderr,
-            "running: %s -I %s m4sugar/m4sugar.m4 %s %s\n",
-            m4, bison_pkgdatadir, definitions, full_skeleton);
-  skel_in = readpipe (m4,
-                     "-I", bison_pkgdatadir,
-                     "m4sugar/m4sugar.m4",
-                     definitions,
-                     full_skeleton,
-                     NULL);
-  XFREE (full_skeleton);
-  if (!skel_in)
-    error (EXIT_FAILURE, errno, "cannot run m4");
+  skel_in = in;
   skel_lex ();
 
   /* Reclaim Flex's buffers.  */
--- /dev/null   2002-10-20 06:01:01.000000000 +0000
+++ lib/subpipe.h       2002-10-20 06:24:21.324563000 +0000
@@ -0,0 +1,26 @@
+/* Subprocesses with pipes.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+
+   This file is part of Bison, the GNU Compiler Compiler.
+
+   Bison 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 2, or (at your option)
+   any later version.
+
+   Bison 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 Bison; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+/* Written by Paul Eggert <address@hidden>
+   and Florian Krohm <address@hidden>.  */
+
+void init_subpipe (void);
+pid_t create_subpipe (char const * const *, int[2]);
+void reap_subpipe (pid_t, char const *);
--- /dev/null   2002-10-20 06:01:01.000000000 +0000
+++ lib/subpipe.c       2002-10-19 05:18:32.020561000 +0000
@@ -0,0 +1,196 @@
+/* Subprocesses with pipes.
+
+   Copyright (C) 2002 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 2, 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, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Written by Paul Eggert <address@hidden>
+   and Florian Krohm <address@hidden>.  */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#include <signal.h>
+#if ! defined SIGCHLD && defined SIGCLD
+# define SIGCHLD SIGCLD
+#endif
+
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+/* The following test is to work around the gross typo in
+   systems like Sony NEWS-OS Release 4.0C, whereby EXIT_FAILURE
+   is defined to 0, not 1.  */
+#if ! EXIT_FAILURE
+# undef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifndef STDIN_FILENO
+# define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+# define STDOUT_FILENO 1
+#endif
+#if ! HAVE_DUP2 && ! defined dup2
+# if HAVE_FCNTL_H
+#  include <fcntl.h>
+# endif
+# 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 "gettext.h"
+#define _(Msgid)  gettext (Msgid)
+
+#include "subpipe.h"
+
+
+/* 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 from_in_fd;
+  int from_out_fd;
+  int to_in_fd;
+  int to_out_fd;
+  pid_t pid;
+
+  if (pipe (pipe_fd) != 0)
+    error (EXIT_FAILURE, errno, "pipe");
+  to_in_fd = pipe_fd[0];
+  to_out_fd = pipe_fd[1];
+
+  if (pipe (pipe_fd) != 0)
+    error (EXIT_FAILURE, errno, "pipe");
+  from_in_fd = pipe_fd[0];
+  from_out_fd = pipe_fd[1];
+
+  pid = vfork ();
+  if (pid < 0)
+    error (EXIT_FAILURE, errno, "fork");
+
+  if (! pid)
+    {
+      /* Child.  */
+      close (to_out_fd);
+      close (from_in_fd);
+
+      if (to_in_fd != STDIN_FILENO)
+       {
+         dup2 (to_in_fd, STDIN_FILENO);
+         close (to_in_fd);
+       }
+      if (from_out_fd != STDOUT_FILENO)
+       {
+         dup2 (from_out_fd, STDOUT_FILENO);
+         close (from_out_fd);
+       }
+
+      /* 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 (to_in_fd);
+  close (from_out_fd);
+  fd[0] = to_out_fd;
+  fd[1] = from_in_fd;
+  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
+}
--- /dev/null   2002-10-20 06:01:01.000000000 +0000
+++ m4/subpipe.m4       2002-10-20 06:24:54.184561000 +0000
@@ -0,0 +1,30 @@
+# -*- Autoconf -*-
+# Checks required to run `subpipe'.
+#
+# Copyright (C) 2002 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+# 02111-1307  USA
+
+# Written by Paul Eggert <address@hidden>.
+
+AC_DEFUN([BISON_PREREQ_SUBPIPE],
+[
+ AC_TYPE_PID_T
+ AC_CHECK_HEADERS([fcntl.h sys/wait.h])
+ AC_HEADER_SYS_WAIT
+ AC_CHECK_FUNCS(dup2 waitpid)
+ AC_FUNC_FORK
+])




reply via email to

[Prev in Thread] Current Thread [Next in Thread]