]> git.ipfire.org Git - thirdparty/make.git/commitdiff
[SV 63333] Be more lenient when failing to create temporary files
authorDmitry Goncharov <dgoncharov@users.sf.net>
Sun, 13 Nov 2022 21:20:33 +0000 (16:20 -0500)
committerPaul Smith <psmith@gnu.org>
Sun, 13 Nov 2022 21:34:01 +0000 (16:34 -0500)
If make cannot create a temporary lock file for output sync, continue
without output sync enabled rather than dying.

However, if make cannot store a makefile from stdin to a temporary
file that is still a fatal error.

* misc.c (get_tmppath): Keep running on failure to generate a
temporary file name.
(get_tmpfd): Keep running on failure to get a temporary file.
(get_tmpfile): Keep running on failure to open a temporary file.
Ensure memory is freed if we return an error.
* posixos.c (os_anontmp): Keep running on failure to open an
anonymous temporary file.
* output.c (setup_tmpfile): Print an error on failure to create an
output sync lock file.
* main.c (main): Die on failure to store makefile from stdin to a
temporary file.
* tests/scripts/features/output-sync: Add tests.
* tests/scripts/features/temp_stdin: Ditto.

src/main.c
src/misc.c
src/output.c
src/posixos.c
tests/scripts/features/output-sync
tests/scripts/features/temp_stdin

index f2caf7a82fd9d56d242dbcdae2e42bf2441af527..78729de107ede34661d8ae09109ca4437dd195f0 100644 (file)
@@ -1928,6 +1928,9 @@ main (int argc, char **argv, char **envp)
                  _("Makefile from standard input specified twice"));
 
             outfile = get_tmpfile (&newnm);
+            if (!outfile)
+              O (fatal, NILF,
+                 _("cannot store makefile from stdin to a temporary file"));
 
             while (!feof (stdin) && ! ferror (stdin))
               {
index 8264fe9f7a2a0a1a413fba7a9a1072a7fbb0062a..00dce749d353576edb87eb3c53995dfd527e4fe0 100644 (file)
@@ -20,8 +20,7 @@ this program.  If not, see <https://www.gnu.org/licenses/>.  */
 #include "os.h"
 #include "debug.h"
 
-/* GNU make no longer supports pre-ANSI89 environments.  */
-
+#include <assert.h>
 #include <stdarg.h>
 
 #ifdef WINDOWS32
@@ -650,11 +649,19 @@ get_tmppath ()
 # ifdef HAVE_MKTEMP
   path = get_tmptemplate ();
   if (*mktemp (path) == '\0')
-    pfatal_with_name ("mktemp");
+    {
+      OSS (error, NILF,
+           _("cannot generate temp path from %s: %s"), path, strerror (errno));
+      return NULL;
+    }
 # else
   path = xmalloc (L_tmpnam + 1);
   if (tmpnam (path) == NULL)
-    pfatal_with_name ("tmpnam");
+    {
+      OS (error, NILF,
+        _("cannot generate temp name: %s"), strerror (errno));
+      return NULL;
+    }
 # endif
 
   return path;
@@ -662,7 +669,9 @@ get_tmppath ()
 #endif
 
 /* Generate a temporary file and return an fd for it.  If name is NULL then
-   the temp file is anonymous and will be deleted when the process exits.  */
+   the temp file is anonymous and will be deleted when the process exits.  If
+   name is not null then *name will point to an allocated buffer, or set to
+   NULL on failure.  */
 int
 get_tmpfd (char **name)
 {
@@ -670,9 +679,11 @@ get_tmpfd (char **name)
   char *tmpnm;
   mode_t mask;
 
-  /* If there's an os-specific way to get an anoymous temp file use it.  */
-  if (!name)
+  if (name)
+    *name = NULL;
+  else
     {
+      /* If there's an os-specific way to get an anoymous temp file use it.  */
       fd = os_anontmp ();
       if (fd >= 0)
         return fd;
@@ -689,13 +700,19 @@ get_tmpfd (char **name)
   EINTRLOOP (fd, mkstemp (tmpnm));
 #else
   tmpnm = get_tmppath ();
+  if (!tmpnm)
+    return -1;
 
   /* Can't use mkstemp(), but try to guard against a race condition.  */
   EINTRLOOP (fd, open (tmpnm, O_CREAT|O_EXCL|O_RDWR, 0600));
 #endif
   if (fd < 0)
-    OSS (fatal, NILF,
-         _("create temporary file %s: %s"), tmpnm, strerror (errno));
+    {
+      OSS (error, NILF,
+           _("cannot create temporary file %s: %s"), tmpnm, strerror (errno));
+      free (tmpnm);
+      return -1;
+    }
 
   if (name)
     *name = tmpnm;
@@ -704,8 +721,8 @@ get_tmpfd (char **name)
       int r;
       EINTRLOOP (r, unlink (tmpnm));
       if (r < 0)
-        OSS (fatal, NILF,
-             _("unlink temporary file %s: %s"), tmpnm, strerror (errno));
+        OSS (error, NILF,
+             _("cannot unlink temporary file %s: %s"), tmpnm, strerror (errno));
       free (tmpnm);
     }
 
@@ -715,8 +732,8 @@ get_tmpfd (char **name)
 }
 
 /* Return a FILE* for a temporary file, opened in the safest way possible.
-   Set name to point to an allocated buffer containing the name of the file.
-   Note, this cannot be NULL!  */
+   Set name to point to an allocated buffer containing the name of the file,
+   or NULL on failure.  Note, name cannot be NULL!  */
 FILE *
 get_tmpfile (char **name)
 {
@@ -725,26 +742,37 @@ get_tmpfile (char **name)
   FILE *file;
 
 #if defined(HAVE_FDOPEN)
-  int fd = get_tmpfd (name);
+  int fd;
+  assert (name);
+  fd = get_tmpfd (name);
+  if (fd < 0)
+    return NULL;
+  assert (*name);
 
   ENULLLOOP (file, fdopen (fd, tmpfile_mode));
   if (file == NULL)
-    OSS (fatal, NILF,
+    OSS (error, NILF,
          _("fdopen: temporary file %s: %s"), *name, strerror (errno));
 #else
   /* Preserve the current umask, and set a restrictive one for temp files.  */
   mode_t mask = umask (0077);
-  int err;
 
+  assert (name);
   *name = get_tmppath ();
+  if (!*name)
+    return NULL;
 
   /* Although this fopen is insecure, it is executed only on non-fdopen
      platforms, which should be a rarity nowadays.  */
 
   ENULLLOOP (file, fopen (*name, tmpfile_mode));
   if (file == NULL)
-    OSS (fatal, NILF,
-         _("fopen: temporary file %s: %s"), *name, strerror (errno));
+    {
+      OSS (error, NILF,
+           _("fopen: temporary file %s: %s"), *name, strerror (errno));
+      free (*name);
+      *name = NULL;
+    }
 
   umask (mask);
 #endif
index 43eb2f065f67c632d962d77d138ec64fa1d5ecd1..22387dff4ac8e6cb6248d836782b702da75f1dc0 100644 (file)
@@ -248,6 +248,9 @@ setup_tmpfile (struct output *out)
 
   /* If we failed to create a temp file, disable output sync going forward.  */
  error:
+  O (error, NILF,
+     _("cannot open output-sync lock file, suppressing output-sync."));
+
   output_close (out);
   output_sync = OUTPUT_SYNC_NONE;
   osync_clear ();
index 3d7d6614a77f171951569b17b6e8ddcdcbb4823f..78358dd8dc78423bedd54d98380de75da186a56d 100644 (file)
@@ -872,12 +872,15 @@ os_anontmp ()
       FILE *tfile;
       ENULLLOOP (tfile, tmpfile ());
       if (!tfile)
-        pfatal_with_name ("tmpfile");
+        {
+          OS (error, NILF, "tmpfile: %s", strerror (errno));
+          return -1;
+        }
       umask (mask);
 
       EINTRLOOP (fd, dup (fileno (tfile)));
       if (fd < 0)
-        pfatal_with_name ("dup");
+        OS (error, NILF, "dup: %s", strerror (errno));
       fclose (tfile);
     }
 #endif
index 40546994751e0df99e84f5bcb281ae2da6db1bc1..18c85c0ab4acc9902f7a40fe1c45cb6c8d9548a1 100644 (file)
@@ -363,8 +363,24 @@ pid:=$(shell echo $$PPID)
 all:; @#HELPER# term $(pid) sleep 10
 !, '-O -j2', '/#MAKE#: \*\*\* \[#MAKEFILE#:3: all] Terminated/', POSIX::SIGTERM);
 }
-
 unlink($fout);
+
+# SV 63333. Test that make continues to run without output sync when we
+# cannot create a temporary file.
+# Create a non-writable temporary directory.
+# Run the test twice, because run_make_test cannot match a regex againt a
+# multiline input.
+my $tdir = 'test_tmp_dir';
+mkdir($tdir, 0500);
+$ENV{'TMPDIR'} = $tdir;
+
+run_make_test(q!
+all:; $(info hello, world)
+!, '-Orecurse', "/suppressing output-sync/");
+
+run_make_test(undef, '-Orecurse', "/#MAKE#: 'all' is up to date./");
+
+rmdir($tdir);
 }
 
 # This tells the test driver that the perl test script executed properly.
index c01d627cd6ad1796f4010fb5b6aaa6bb9c1640b4..3bd53e0224c1c192bae1fad012c324dde215f3a0 100644 (file)
@@ -109,6 +109,21 @@ force:
 @make_command = @make_orig;
 unlink($makecopy);
 rmdir($tmakedir);
+
+# SV 63333. Test that make exits with an error message if we cannot store a
+# makefile from stdin to a temporary file.
+# Create a non-writable temporary directory.
+
+my $tdir = 'test_tmp_dir';
+mkdir($tdir, 0500);
+$ENV{'TMPDIR'} = $tdir;
+close(STDIN);
+open(STDIN, "<", 'input.mk') || die "$0: cannot open input.mk for reading: $!";
+
+run_make_test(q!
+all:; $(info hello, world)
+!, '-f-', '/cannot store makefile from stdin to a temporary file.  Stop./', 512);
+rmdir($tdir);
 }
 
 close(STDIN);