Richard W.M. Jones
2023-May-09 14:51 UTC
[Libguestfs] [PATCH nbdkit v3 5/6] server: debug: Fix error handling
Preserve errno even if the function fails. We need to set
errno = err again on every exit path out of the function.
Check if close_memstream failed and go to the error path if so. This
is most important on Windows where close_memstream is what actually
allocates the memory. But even on Unix, close_memstream (which is an
alias for fclose) can return an error.
Move the error-handling code to the end of the function.
I added a comment above the 'fputs' explaining why exactly we're
using
memstream in the first place -- because it is more atomic than using
multiple fprintf.
See: https://listman.redhat.com/archives/libguestfs/2023-May/031456.html
Thanks: Laszlo Ersek
---
server/debug.c | 28 ++++++++++++++++------------
1 file changed, 16 insertions(+), 12 deletions(-)
diff --git a/server/debug.c b/server/debug.c
index 8afa0ae8b..177d9d5da 100644
--- a/server/debug.c
+++ b/server/debug.c
@@ -81,14 +81,8 @@ debug_common (bool in_server, const char *fs, va_list args)
FILE *fp;
fp = open_memstream (&str, &len);
- if (fp == NULL) {
- fail:
- /* Try to emit what we can. */
- errno = err;
- vfprintf (stderr, fs, args);
- fprintf (stderr, "\n");
- return;
- }
+ if (fp == NULL)
+ goto fail;
#ifndef WIN32
tty = isatty (fileno (stderr));
@@ -104,13 +98,23 @@ debug_common (bool in_server, const char *fs, va_list args)
if (!in_server && tty) ansi_force_restore (fp);
#endif
fprintf (fp, "\n");
- close_memstream (fp);
+ if (close_memstream (fp) == -1)
+ goto fail;
- if (str)
- fputs (str, stderr);
- else
+ if (!str)
goto fail;
+ /* Send it to stderr as atomically as possible. */
+ fputs (str, stderr);
+
+ errno = err;
+ return;
+
+ fail:
+ /* Try to emit what we can. */
+ errno = err;
+ vfprintf (stderr, fs, args);
+ fprintf (stderr, "\n");
errno = err;
}
--
2.39.2
Eric Blake
2023-May-09 18:25 UTC
[Libguestfs] [PATCH nbdkit v3 5/6] server: debug: Fix error handling
On Tue, May 09, 2023 at 03:51:20PM +0100, Richard W.M. Jones wrote:> Preserve errno even if the function fails. We need to set > errno = err again on every exit path out of the function. > > Check if close_memstream failed and go to the error path if so. This > is most important on Windows where close_memstream is what actually > allocates the memory. But even on Unix, close_memstream (which is an > alias for fclose) can return an error. > > Move the error-handling code to the end of the function. > > I added a comment above the 'fputs' explaining why exactly we're using > memstream in the first place -- because it is more atomic than using > multiple fprintf. > > See: https://listman.redhat.com/archives/libguestfs/2023-May/031456.html > Thanks: Laszlo Ersek > --- > server/debug.c | 28 ++++++++++++++++------------ > 1 file changed, 16 insertions(+), 12 deletions(-)Reviewed-by: Eric Blake <eblake at redhat.com>> + fail: > + /* Try to emit what we can. */ > + errno = err; > + vfprintf (stderr, fs, args); > + fprintf (stderr, "\n"); > errno = err;It might make more sense if the first line were written: errno = err; /* In case fs uses %m */ so that no one tries to "optimize" out what looks like a redundant assignment when both are really required. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org