splice_cat can leave open file descriptors around. This breaks the
valgrind testsuite with --track-fds=yes. This is fairly innocent, like
still reachable memory, but does need a new suppression when tracking
file descriptor handling.  Introduce a new splice_cat_close function
that can be used on error from splice_cat and before exiting main.

* src/cat.c (splice_cat): Move static pipefd and pipefd_pipe_size to
file level, guarded by HAVE_SPLICE. Move pipefd close and cleanup from
error handler to...
(splice_cat_close): New function. Empty if we don't HAVE_SPLICE.
(main): Call splice_cat_close before exit.
---
 src/cat.c | 47 +++++++++++++++++++++++++++++++++++------------
 1 file changed, 35 insertions(+), 12 deletions(-)

diff --git a/src/cat.c b/src/cat.c
index 43063fb9b27e..33ef4db9cdc7 100644
--- a/src/cat.c
+++ b/src/cat.c
@@ -549,6 +549,38 @@ copy_cat (void)
       }
 }
 
+#if HAVE_SPLICE
+
+/* If PIPEFD[0] is a non-negative value, we have an open pipe from a
+   previous call to splice_cat.  At the start of splice_cat the pipe
+   will always be empty.  Use splice_cat_close on error or end of
+   program.  */
+static int pipefd[2] = { -1, -1 };
+
+/* The size of the pipe referred to by PIPEFD.  */
+static idx_t pipefd_pipe_size = 0;
+
+/* Close PIDEFD[0] and PIPEFD[1] if not -1, reset pipefd_pipe_size.  */
+static void
+splice_cat_close (void)
+{
+  if (pipefd[0] >= 0)
+    {
+      close (pipefd[0]);
+      close (pipefd[1]);
+    }
+
+  pipefd[0] = pipefd[1] = -1;
+  pipefd_pipe_size = 0;
+}
+
+#else
+
+/* No splice no close.  */
+static void splice_cat_close (void) { }
+
+#endif
+
 /* Copy data from input to output using splice if possible.
    Return 1 if successful, 0 if ordinary read+write should be tried,
    -1 if a serious problem has been diagnosed.  */
@@ -562,14 +594,6 @@ splice_cat (void)
 
 #if HAVE_SPLICE
 
-  /* If PIPEFD[0] is a non-negative value, we have an open pipe from a
-     previous call to this function.  At the start of this function the
-     pipe will always be empty.  */
-  static int pipefd[2] = { -1, -1 };
-
-  /* The size of the pipe referred to by PIPEFD.  */
-  static idx_t pipefd_pipe_size = 0;
-
   /* Create an intermediate pipe if it is not already open.
      Even if both input and output are pipes,
      so that read and write errors can be distinguished.  */
@@ -645,11 +669,8 @@ splice_cat (void)
     {
       /* Recreate the pipe on internal error.  */
       int saved_errno = errno;
-      close (pipefd[0]);
-      close (pipefd[1]);
+      splice_cat_close ();
       errno = saved_errno;
-      pipefd[0] = pipefd[1] = -1;
-      pipefd_pipe_size = 0;
       error (0, errno, "%s", _("splice error"));
     }
   else if (! in_ok)
@@ -968,6 +989,8 @@ main (int argc, char **argv)
   alignfree (inbuf);
 #endif
 
+  splice_cat_close ();
+
   if (have_read_stdin && close (STDIN_FILENO) < 0)
     error (EXIT_FAILURE, errno, _("closing standard input"));
 
-- 
2.56.0


Reply via email to