diff options
| author | Paul Eggert | 2019-07-13 09:39:09 -0700 |
|---|---|---|
| committer | Paul Eggert | 2019-07-13 16:53:21 -0700 |
| commit | a8ffbb20da67b20a85ddca38e20c609144c3bef3 (patch) | |
| tree | 3ce64362d7d1a8b14f0a5ea4286ea6af27109de2 /src | |
| parent | 3767628dc534e64cdc21bdff16d5dd4726feacd2 (diff) | |
| download | emacs-a8ffbb20da67b20a85ddca38e20c609144c3bef3.tar.gz emacs-a8ffbb20da67b20a85ddca38e20c609144c3bef3.zip | |
Avoid interleaving stderr in a few cases
* src/sysdep.c (buferr): New static var.
(init_standard_fds) [_PC_PIPE_BUF]: Initialize it.
(errstream, errputc, verrprintf, errwrite): New functions.
(close_output_streams): Check buferr status too.
* src/xdisp.c: Include sysstdio.h instead of stdio.h.
(message_to_stderr, vmessage): Use the new functions
to avoid interleaving stderr.
Diffstat (limited to 'src')
| -rw-r--r-- | src/sysdep.c | 59 | ||||
| -rw-r--r-- | src/sysstdio.h | 3 | ||||
| -rw-r--r-- | src/xdisp.c | 19 |
3 files changed, 63 insertions, 18 deletions
diff --git a/src/sysdep.c b/src/sysdep.c index 99d3ee60698..4c3d546962c 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -232,6 +232,10 @@ force_open (int fd, int flags) | |||
| 232 | } | 232 | } |
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | /* A stream that is like stderr, except line buffered. It is NULL | ||
| 236 | during startup, or if line buffering is not in use. */ | ||
| 237 | static FILE *buferr; | ||
| 238 | |||
| 235 | /* Make sure stdin, stdout, and stderr are open to something, so that | 239 | /* Make sure stdin, stdout, and stderr are open to something, so that |
| 236 | their file descriptors are not hijacked by later system calls. */ | 240 | their file descriptors are not hijacked by later system calls. */ |
| 237 | void | 241 | void |
| @@ -244,6 +248,14 @@ init_standard_fds (void) | |||
| 244 | force_open (STDIN_FILENO, O_WRONLY); | 248 | force_open (STDIN_FILENO, O_WRONLY); |
| 245 | force_open (STDOUT_FILENO, O_RDONLY); | 249 | force_open (STDOUT_FILENO, O_RDONLY); |
| 246 | force_open (STDERR_FILENO, O_RDONLY); | 250 | force_open (STDERR_FILENO, O_RDONLY); |
| 251 | |||
| 252 | /* Set buferr if possible on platforms defining _PC_PIPE_BUF, as | ||
| 253 | they support the notion of atomic writes to pipes. */ | ||
| 254 | #ifdef _PC_PIPE_BUF | ||
| 255 | buferr = fdopen (STDERR_FILENO, "w"); | ||
| 256 | if (buferr) | ||
| 257 | setvbuf (buferr, NULL, _IOLBF, 0); | ||
| 258 | #endif | ||
| 247 | } | 259 | } |
| 248 | 260 | ||
| 249 | /* Return the current working directory. The result should be freed | 261 | /* Return the current working directory. The result should be freed |
| @@ -2769,6 +2781,46 @@ safe_strsignal (int code) | |||
| 2769 | return signame; | 2781 | return signame; |
| 2770 | } | 2782 | } |
| 2771 | 2783 | ||
| 2784 | /* Output to stderr. */ | ||
| 2785 | |||
| 2786 | /* Return the error output stream. */ | ||
| 2787 | static FILE * | ||
| 2788 | errstream (void) | ||
| 2789 | { | ||
| 2790 | FILE *err = buferr; | ||
| 2791 | if (!err) | ||
| 2792 | return stderr; | ||
| 2793 | fflush_unlocked (stderr); | ||
| 2794 | return err; | ||
| 2795 | } | ||
| 2796 | |||
| 2797 | /* These functions are like fputc, vfprintf, and fwrite, | ||
| 2798 | except that they output to stderr and buffer better on | ||
| 2799 | platforms that support line buffering. This avoids interleaving | ||
| 2800 | output when Emacs and other processes write to stderr | ||
| 2801 | simultaneously, so long as the lines are short enough. When a | ||
| 2802 | single diagnostic is emitted via a sequence of calls of one or more | ||
| 2803 | of these functions, the caller should arrange for the last called | ||
| 2804 | function to output a newline at the end. */ | ||
| 2805 | |||
| 2806 | void | ||
| 2807 | errputc (int c) | ||
| 2808 | { | ||
| 2809 | fputc_unlocked (c, errstream ()); | ||
| 2810 | } | ||
| 2811 | |||
| 2812 | void | ||
| 2813 | verrprintf (char const *fmt, va_list ap) | ||
| 2814 | { | ||
| 2815 | vfprintf (errstream (), fmt, ap); | ||
| 2816 | } | ||
| 2817 | |||
| 2818 | void | ||
| 2819 | errwrite (void const *buf, ptrdiff_t nbuf) | ||
| 2820 | { | ||
| 2821 | fwrite_unlocked (buf, 1, nbuf, errstream ()); | ||
| 2822 | } | ||
| 2823 | |||
| 2772 | /* Close standard output and standard error, reporting any write | 2824 | /* Close standard output and standard error, reporting any write |
| 2773 | errors as best we can. This is intended for use with atexit. */ | 2825 | errors as best we can. This is intended for use with atexit. */ |
| 2774 | void | 2826 | void |
| @@ -2782,9 +2834,10 @@ close_output_streams (void) | |||
| 2782 | 2834 | ||
| 2783 | /* Do not close stderr if addresses are being sanitized, as the | 2835 | /* Do not close stderr if addresses are being sanitized, as the |
| 2784 | sanitizer might report to stderr after this function is invoked. */ | 2836 | sanitizer might report to stderr after this function is invoked. */ |
| 2785 | if (ADDRESS_SANITIZER | 2837 | bool err = buferr && (fflush (buferr) != 0 || ferror (buferr)); |
| 2786 | ? fflush (stderr) != 0 || ferror (stderr) | 2838 | if (err | (ADDRESS_SANITIZER |
| 2787 | : close_stream (stderr) != 0) | 2839 | ? fflush (stderr) != 0 || ferror (stderr) |
| 2840 | : close_stream (stderr) != 0)) | ||
| 2788 | _exit (EXIT_FAILURE); | 2841 | _exit (EXIT_FAILURE); |
| 2789 | } | 2842 | } |
| 2790 | 2843 | ||
diff --git a/src/sysstdio.h b/src/sysstdio.h index 68ae043fe33..5303e8a15b2 100644 --- a/src/sysstdio.h +++ b/src/sysstdio.h | |||
| @@ -25,6 +25,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 25 | #include "unlocked-io.h" | 25 | #include "unlocked-io.h" |
| 26 | 26 | ||
| 27 | extern FILE *emacs_fopen (char const *, char const *); | 27 | extern FILE *emacs_fopen (char const *, char const *); |
| 28 | extern void errputc (int); | ||
| 29 | extern void verrprintf (char const *, va_list) ATTRIBUTE_FORMAT_PRINTF (1, 0); | ||
| 30 | extern void errwrite (void const *, ptrdiff_t); | ||
| 28 | extern void close_output_streams (void); | 31 | extern void close_output_streams (void); |
| 29 | 32 | ||
| 30 | #if O_BINARY | 33 | #if O_BINARY |
diff --git a/src/xdisp.c b/src/xdisp.c index 7f0d577cebc..50f6443f6b2 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -10714,7 +10714,7 @@ message_to_stderr (Lisp_Object m) | |||
| 10714 | if (noninteractive_need_newline) | 10714 | if (noninteractive_need_newline) |
| 10715 | { | 10715 | { |
| 10716 | noninteractive_need_newline = false; | 10716 | noninteractive_need_newline = false; |
| 10717 | putc ('\n', stderr); | 10717 | errputc ('\n'); |
| 10718 | } | 10718 | } |
| 10719 | if (STRINGP (m)) | 10719 | if (STRINGP (m)) |
| 10720 | { | 10720 | { |
| @@ -10728,21 +10728,10 @@ message_to_stderr (Lisp_Object m) | |||
| 10728 | else | 10728 | else |
| 10729 | s = m; | 10729 | s = m; |
| 10730 | 10730 | ||
| 10731 | /* We want to write this out with a single call so that | 10731 | errwrite (SDATA (s), SBYTES (s)); |
| 10732 | output doesn't interleave with other processes writing to | ||
| 10733 | stderr at the same time. */ | ||
| 10734 | { | ||
| 10735 | int length = min (INT_MAX, SBYTES (s) + 1); | ||
| 10736 | char *string = xmalloc (length); | ||
| 10737 | |||
| 10738 | memcpy (string, SSDATA (s), length - 1); | ||
| 10739 | string[length - 1] = '\n'; | ||
| 10740 | fwrite (string, 1, length, stderr); | ||
| 10741 | xfree (string); | ||
| 10742 | } | ||
| 10743 | } | 10732 | } |
| 10744 | else if (!cursor_in_echo_area) | 10733 | if (STRINGP (m) || !cursor_in_echo_area) |
| 10745 | putc ('\n', stderr); | 10734 | errputc ('\n'); |
| 10746 | } | 10735 | } |
| 10747 | 10736 | ||
| 10748 | /* The non-logging version of message3. | 10737 | /* The non-logging version of message3. |