From 68be4f74fce91b76e5915449268d6b5eb687aab9 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Mon, 2 Jan 2017 15:46:30 -0500 Subject: [PATCH] [SV 13651] Handle out-of-memory conditions slightly more gracefully. * 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 | 6 ++++-- config.ami.template | 3 +++ config.h.W32.template | 3 +++ configh.dos.template | 3 +++ job.h | 3 --- makeint.h | 3 +-- misc.c | 10 +++++----- output.c | 42 +++++++++++++++++++++++++++++++++--------- output.h | 8 ++++++++ read.c | 2 +- 10 files changed, 61 insertions(+), 22 deletions(-) diff --git a/arscan.c b/arscan.c index f4978486..ba8987e6 100644 --- 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" /* 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); diff --git a/config.ami.template b/config.ami.template index 4c5bb78b..8235f06b 100644 --- a/config.ami.template +++ b/config.ami.template @@ -335,3 +335,6 @@ this program. If not, see . */ /* Build host information. */ #define MAKE_HOST "Amiga" + +/* Define to `int' if does not define. */ +#define ssize_t int diff --git a/config.h.W32.template b/config.h.W32.template index 117ea4ab..ce070679 100644 --- a/config.h.W32.template +++ b/config.h.W32.template @@ -484,6 +484,9 @@ char *ttyname (int); #endif #endif +/* Define to `int' if does not define. */ +#define ssize_t int + /* Define to 'int' if doesn't define. */ #define uid_t int diff --git a/configh.dos.template b/configh.dos.template index c43e6442..50d86ccf 100644 --- a/configh.dos.template +++ b/configh.dos.template @@ -111,3 +111,6 @@ this program. If not, see . */ /* Grok DOS paths (drive specs and backslash path element separators) */ #define HAVE_DOS_PATHS + +/* Define to `int' if does not define. */ +#define ssize_t int diff --git a/job.h b/job.h index 48cce764..9bea9a72 100644 --- 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 diff --git a/makeint.h b/makeint.h index 9fb2dd83..53a895e3 100644 --- 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 e7ab8092..c9e88b61 100644 --- 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) diff --git a/output.c b/output.c index b6ba3cfc..4945433d 100644 --- 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); } } @@ -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); +} diff --git a/output.h b/output.h index bcd98051..b398cdd0 100644 --- 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 3e399848..0ca456c0 100644 --- 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. */