[Libguestfs] [PATCH nbdkit v3 5/6] server: debug: Fix error handling

Richard W.M. Jones
Tue, 09 May 2023 14:51:20 -0000

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