getdelim: ensure error indicator is set on error (bug 29917)
authorAndreas Schwab <schwab@suse.de>
Mon, 19 Dec 2022 11:40:45 +0000 (12:40 +0100)
committerAndreas Schwab <schwab@suse.de>
Mon, 2 Jan 2023 09:58:49 +0000 (10:58 +0100)
POSIX requires that getdelim and getline set the error indicator on the
stream when an error occured, in addition to setting errno.

libio/Makefile
libio/iogetdelim.c
libio/tst-getdelim.c [new file with mode: 0644]

index 64398ab..9c69a85 100644 (file)
@@ -66,7 +66,7 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc   \
        tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
        tst-ftell-append tst-fputws tst-bz22415 tst-fgetc-after-eof \
        tst-sprintf-ub tst-sprintf-chk-ub tst-bz24051 tst-bz24153 \
-       tst-wfile-sync tst-bz28828
+       tst-wfile-sync tst-bz28828 tst-getdelim
 
 tests-internal = tst-vtables tst-vtables-interposed
 
index b6c4c07..591526e 100644 (file)
@@ -43,11 +43,6 @@ __getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
   ssize_t cur_len = 0;
   ssize_t len;
 
-  if (lineptr == NULL || n == NULL)
-    {
-      __set_errno (EINVAL);
-      return -1;
-    }
   CHECK_FILE (fp, -1);
   _IO_acquire_lock (fp);
   if (_IO_ferror_unlocked (fp))
@@ -56,12 +51,21 @@ __getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
       goto unlock_return;
     }
 
+  if (lineptr == NULL || n == NULL)
+    {
+      __set_errno (EINVAL);
+      fseterr_unlocked (fp);
+      result = -1;
+      goto unlock_return;
+    }
+
   if (*lineptr == NULL || *n == 0)
     {
       *n = 120;
       *lineptr = (char *) malloc (*n);
       if (*lineptr == NULL)
        {
+         fseterr_unlocked (fp);
          result = -1;
          goto unlock_return;
        }
@@ -88,6 +92,7 @@ __getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
       if (__glibc_unlikely (len >= SSIZE_MAX - cur_len))
        {
          __set_errno (EOVERFLOW);
+         fseterr_unlocked (fp);
          result = -1;
          goto unlock_return;
        }
@@ -102,6 +107,7 @@ __getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
          new_lineptr = (char *) realloc (*lineptr, needed);
          if (new_lineptr == NULL)
            {
+             fseterr_unlocked (fp);
              result = -1;
              goto unlock_return;
            }
diff --git a/libio/tst-getdelim.c b/libio/tst-getdelim.c
new file mode 100644 (file)
index 0000000..4443732
--- /dev/null
@@ -0,0 +1,36 @@
+/* Check that getdelim sets error indicator on error (BZ #29917)
+
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <errno.h>
+
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+  clearerr (stdin);
+  TEST_VERIFY (getdelim (0, 0, '\n', stdin) == -1);
+  TEST_VERIFY (ferror (stdin) != 0);
+  TEST_VERIFY (errno == EINVAL);
+
+  return 0;
+}
+
+#include <support/test-driver.c>