[Top][All Lists]
[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
+])
- Bison fix to not generate a temporary file,
Paul Eggert <=