]> git.ipfire.org Git - thirdparty/make.git/commitdiff
[SV 13651] Handle out-of-memory conditions slightly more gracefully.
authorPaul Smith <psmith@gnu.org>
Mon, 2 Jan 2017 20:46:30 +0000 (15:46 -0500)
committerPaul Smith <psmith@gnu.org>
Sun, 4 Jun 2017 22:37:20 +0000 (18:37 -0400)
* makeint.h: Change OUT_OF_MEM() macro to out_of_memory() function.
* output.h, job.h: Move FD_* macros from job.h to output.h.
* output.c (output_write): Write a buffer to an FD directly.
(out_of_memory): Use output_write() to avoid allocating more
memory while writing the error, and call exit() instead of die().
This does mean we can't translate the error string, though.
* misc.c (xmalloc, xcalloc, xrealloc, xstrdup, xstrndup): Call new
out_of_memory() rather than OUT_OF_MEM().
* read.c (parse_file_seq): Ditto.

arscan.c
config.ami.template
config.h.W32.template
configh.dos.template
job.h
makeint.h
misc.c
output.c
output.h
read.c

index f4978486a309c7fd804a4564c46886a28e5ce29b..ba8987e6a3778d229e976fc7cce3aaa951e6a718 100644 (file)
--- a/arscan.c
+++ b/arscan.c
@@ -375,6 +375,8 @@ struct ar_hdr
 #ifndef AR_HDR_SIZE
 # define   AR_HDR_SIZE  (sizeof (struct ar_hdr))
 #endif
+
+#include "output.h"
 \f
 /* Takes three arguments ARCHIVE, FUNCTION and ARG.
 
@@ -891,7 +893,7 @@ ar_member_touch (const char *arname, const char *memname)
   EINTRLOOP (o, lseek (fd, pos, 0));
   if (o < 0)
     goto lose;
-  EINTRLOOP (r, write (fd, &ar_hdr, AR_HDR_SIZE));
+  r = output_write (fd, &ar_hdr, AR_HDR_SIZE);
   if (r != AR_HDR_SIZE)
     goto lose;
   /* The file's mtime is the time we we want.  */
@@ -913,7 +915,7 @@ ar_member_touch (const char *arname, const char *memname)
   EINTRLOOP (o, lseek (fd, pos, 0));
   if (o < 0)
     goto lose;
-  EINTRLOOP (r, write (fd, &ar_hdr, AR_HDR_SIZE));
+  r = output_write (fd, &ar_hdr, AR_HDR_SIZE);
   if (r != AR_HDR_SIZE)
     goto lose;
   close (fd);
index 4c5bb78baf8da56f8fbc140b6e9d8f478399b791..8235f06bef8896e48f338a6ab71ff60903252416 100644 (file)
@@ -335,3 +335,6 @@ this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* Build host information. */
 #define MAKE_HOST "Amiga"
+
+/* Define to `int' if <sys/types.h> does not define. */
+#define ssize_t int
index 117ea4abed746b6a41e1f93011cab1cf957e1d97..ce0706794378191737da6625bcab733b837fff9f 100644 (file)
@@ -484,6 +484,9 @@ char *ttyname (int);
 #endif
 #endif
 
+/* Define to `int' if <sys/types.h> does not define. */
+#define ssize_t int
+
 /* Define to 'int' if <sys/types.h> doesn't define. */
 #define uid_t int
 
index c43e6442b9324c550dc77e9dd1ab8e28c8a33e20..50d86ccfa0a68151040d40ce06864e2530d4208a 100644 (file)
@@ -111,3 +111,6 @@ this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 /* Grok DOS paths (drive specs and backslash path element separators) */
 #define HAVE_DOS_PATHS
+
+/* Define to `int' if <sys/types.h> does not define. */
+#define ssize_t int
diff --git a/job.h b/job.h
index 48cce764faa4a609430523e404345ed510444b38..9bea9a728cc3251cc3ad52f95043af276f7f6565 100644 (file)
--- a/job.h
+++ b/job.h
@@ -62,9 +62,6 @@ char **construct_command_argv (char *line, char **restp, struct file *file,
 #ifdef VMS
 int child_execute_job (struct child *child, char *argv);
 #else
-# define FD_STDIN       (fileno (stdin))
-# define FD_STDOUT      (fileno (stdout))
-# define FD_STDERR      (fileno (stderr))
 int child_execute_job (struct output *out, int good_stdin, char **argv, char **envp);
 #endif
 
index 9fb2dd8381ef2bf839acd0a788f029dbc48f54e8..53a895e3346a9f7ffc21e3778019bd6f0dce59c0 100644 (file)
--- a/makeint.h
+++ b/makeint.h
@@ -484,6 +484,7 @@ void error (const floc *flocp, size_t length, const char *fmt, ...)
             __attribute__ ((__format__ (__printf__, 3, 4)));
 void fatal (const floc *flocp, size_t length, const char *fmt, ...)
             __attribute__ ((noreturn, __format__ (__printf__, 3, 4)));
+void out_of_memory () __attribute__((noreturn));
 
 /* When adding macros to this list be sure to update the value of
    XGETTEXT_OPTIONS in the po/Makevars file.  */
@@ -501,8 +502,6 @@ void fatal (const floc *flocp, size_t length, const char *fmt, ...)
 #define ONS(_t,_a,_f,_n,_s)   _t((_a), INTSTR_LENGTH + strlen (_s), \
                                  (_f), (_n), (_s))
 
-#define OUT_OF_MEM() O (fatal, NILF, _("virtual memory exhausted"))
-
 void die (int) __attribute__ ((noreturn));
 void pfatal_with_name (const char *) __attribute__ ((noreturn));
 void perror_with_name (const char *, const char *);
diff --git a/misc.c b/misc.c
index e7ab809242932c958af27ec66fc3aca354bb0330..c9e88b61fe75a04f5d9d72079a41f0b2554c7c00 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -220,7 +220,7 @@ xmalloc (unsigned int size)
   /* Make sure we don't allocate 0, for pre-ISO implementations.  */
   void *result = malloc (size ? size : 1);
   if (result == 0)
-    OUT_OF_MEM();
+    out_of_memory ();
   return result;
 }
 
@@ -231,7 +231,7 @@ xcalloc (unsigned int size)
   /* Make sure we don't allocate 0, for pre-ISO implementations.  */
   void *result = calloc (size ? size : 1, 1);
   if (result == 0)
-    OUT_OF_MEM();
+    out_of_memory ();
   return result;
 }
 
@@ -246,7 +246,7 @@ xrealloc (void *ptr, unsigned int size)
     size = 1;
   result = ptr ? realloc (ptr, size) : malloc (size);
   if (result == 0)
-    OUT_OF_MEM();
+    out_of_memory ();
   return result;
 }
 
@@ -263,7 +263,7 @@ xstrdup (const char *ptr)
 #endif
 
   if (result == 0)
-    OUT_OF_MEM();
+    out_of_memory ();
 
 #ifdef HAVE_STRDUP
   return result;
@@ -282,7 +282,7 @@ xstrndup (const char *str, unsigned int length)
 #ifdef HAVE_STRNDUP
   result = strndup (str, length);
   if (result == 0)
-    OUT_OF_MEM();
+    out_of_memory ();
 #else
   result = xmalloc (length + 1);
   if (length > 0)
index b6ba3cfce1765448016cc77708522fcfe7c40ca8..4945433db3da34ca837a1d927a63d3ca63a5a0a0 100644 (file)
--- a/output.c
+++ b/output.c
@@ -61,6 +61,26 @@ unsigned int stdio_traced = 0;
 # define MODE_T     int
 #endif
 
+/* Write a BUFFER of size LEN to file descriptor FD.
+   Handle EINTR and other short writes.  If we get an error, ignore it.  */
+int
+output_write (int fd, const void *buffer, size_t len)
+{
+  const char *msg = buffer;
+  while (1)
+    {
+      ssize_t r;
+
+      EINTRLOOP (r, write (fd, msg, len));
+
+      if (r < 0 || (size_t)r == len)
+        return r;
+
+      len -= r;
+      msg += r;
+    }
+}
+
 /* Write a string to the current STDOUT or STDERR.  */
 static void
 _outputs (struct output *out, int is_err, const char *msg)
@@ -76,16 +96,8 @@ _outputs (struct output *out, int is_err, const char *msg)
       int fd = is_err ? out->err : out->out;
       int len = strlen (msg);
       int r;
-
       EINTRLOOP (r, lseek (fd, 0, SEEK_END));
-      while (1)
-        {
-          EINTRLOOP (r, write (fd, msg, len));
-          if (r == len || r <= 0)
-            break;
-          len -= r;
-          msg += r;
-        }
+      output_write (fd, msg, len);
     }
 }
 \f
@@ -745,3 +757,15 @@ pfatal_with_name (const char *name)
 
   /* NOTREACHED */
 }
+
+/* Print a message about out of memory (not using more heap) and exit.
+   Our goal here is to be sure we don't try to allocate more memory, which
+   means we don't want to use string translations or normal cleanup.  */
+
+void
+out_of_memory ()
+{
+  output_write (FD_STDOUT, program, strlen (program));
+  output_write (FD_STDOUT, STRING_SIZE_TUPLE (": *** virtual memory exhausted\n"));
+  exit (MAKE_FAILURE);
+}
index bcd98051e986ddbef68bafb6bbdecaa5dbf4db69..b398cdd02d707a5d986791fb92a37ec0d40795ae 100644 (file)
--- a/output.h
+++ b/output.h
@@ -24,6 +24,10 @@ struct output
 extern struct output *output_context;
 extern unsigned int stdio_traced;
 
+#define FD_STDIN  (fileno (stdin))
+#define FD_STDOUT (fileno (stdout))
+#define FD_STDERR (fileno (stderr))
+
 #define OUTPUT_SET(_new)    do{ output_context = (_new)->syncout ? (_new) : NULL; }while(0)
 #define OUTPUT_UNSET()      do{ output_context = NULL; }while(0)
 
@@ -32,6 +36,10 @@ extern unsigned int stdio_traced;
 
 FILE *output_tmpfile (char **, const char *);
 
+/* Write a buffer directly to the given file descriptor.
+   This handles errors etc.  */
+int output_write (int fd, const void *buffer, size_t len);
+
 /* Initialize and close a child output structure: if NULL do this program's
    output (this should only be done once).  */
 void output_init (struct output *out);
diff --git a/read.c b/read.c
index 3e3998482eedf197ece4806c8a934310bb78058e..0ca456c0124447d7ab10c7f308aab169031784a2 100644 (file)
--- a/read.c
+++ b/read.c
@@ -3276,7 +3276,7 @@ parse_file_seq (char **stringp, unsigned int size, int stopmap,
         switch (glob (name, GLOB_NOSORT|GLOB_ALTDIRFUNC, NULL, &gl))
           {
           case GLOB_NOSPACE:
-            OUT_OF_MEM();
+            out_of_memory ();
 
           case 0:
             /* Success.  */