bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Bug-tar] getline() differences FreeBSD / GNU libc


From: Bruno Haible
Subject: Re: [Bug-tar] getline() differences FreeBSD / GNU libc
Date: Sun, 31 Jan 2010 17:43:12 +0100
User-agent: KMail/1.9.9

> 2010-01-31  Bruno Haible  <address@hidden>
> 
>       Work around getline() bug on FreeBSD 8.0.
>       * m4/getline.m4 (gl_FUNC_GETLINE): Also test result for a NULL buffer
>       and a non-zero size.
>       * tests/test-getline.c (main): Likewise.
>       * doc/posix-functions/getline.texi: Mention the FreeBSD bug.
>       Reported by Dennis <address@hidden> via Eric Blake.

And similarly for getdelim.

2010-01-31  Bruno Haible  <address@hidden>

        Work around getdelim() bug on FreeBSD 8.0.
        * m4/getdelim.m4 (gl_FUNC_GETDELIM): Test whether getdelim supports an
        initially NULL line. Set REPLACE_GETDELIM if getdelim exists but does
        not work.
        * lib/stdio.in.h (getdelim): Define as an alias if REPLACE_GETDELIM
        is 1.
        * m4/stdio_h.m4 (gl_STDIO_H_DEFAULTS): Initialize REPLACE_GETDELIM.
        * modules/stdio (Makefile.am): Also substitute REPLACE_GETDELIM.
        * tests/test-getdelim.c (main): Also test result for a NULL buffer and
        a non-zero size.
        * doc/posix-functions/getdelim.texi: Mention the FreeBSD bug.

--- doc/posix-functions/getdelim.texi.orig      Sun Jan 31 17:33:06 2010
+++ doc/posix-functions/getdelim.texi   Sun Jan 31 17:30:59 2010
@@ -14,6 +14,10 @@
 @item
 This function is missing a declaration on some platforms:
 BeOS.
address@hidden
+This function crashes when passed a pointer to a NULL buffer together with a
+pointer to a non-zero buffer size on some platforms:
+FreeBSD 8.0.
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- lib/stdio.in.h.orig Sun Jan 31 17:33:06 2010
+++ lib/stdio.in.h      Sun Jan 31 17:30:59 2010
@@ -340,7 +340,11 @@
 #endif
 
 #if @GNULIB_GETDELIM@
-# if address@hidden@
+# if @REPLACE_GETDELIM@
+#  undef getdelim
+#  define getdelim rpl_getdelim
+# endif
+# if address@hidden@ || @REPLACE_GETDELIM@
 /* Read input, up to (and including) the next occurrence of DELIMITER, from
    STREAM, store it in *LINEPTR (and NUL-terminate it).
    *LINEPTR is a pointer returned from malloc (or NULL), pointing to *LINESIZE
--- m4/getdelim.m4.orig Sun Jan 31 17:33:06 2010
+++ m4/getdelim.m4      Sun Jan 31 17:30:59 2010
@@ -1,6 +1,6 @@
-# getdelim.m4 serial 5
+# getdelim.m4 serial 6
 
-dnl Copyright (C) 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+dnl Copyright (C) 2005-2007, 2009-2010 Free Software Foundation, Inc.
 dnl
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -15,16 +15,71 @@
   dnl Persuade glibc <stdio.h> to declare getdelim().
   AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
 
-  AC_REPLACE_FUNCS([getdelim])
   AC_CHECK_DECLS_ONCE([getdelim])
 
-  if test $ac_cv_func_getdelim = no; then
-    gl_PREREQ_GETDELIM
+  AC_CHECK_FUNCS_ONCE([getdelim])
+  if test $ac_cv_func_getdelim = yes; then
+    dnl Found it in some library.  Verify that it works.
+    AC_CACHE_CHECK([for working getdelim function], 
[gl_cv_func_working_getdelim],
+    [echo fooNbarN | tr -d '\012' | tr N '\012' > conftest.data
+    AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#    include <stdio.h>
+#    include <stdlib.h>
+#    include <string.h>
+    int main ()
+    {
+      FILE *in = fopen ("./conftest.data", "r");
+      if (!in)
+        return 1;
+      {
+        /* Test result for a NULL buffer and a zero size.
+           Based on a test program from Karl Heuer.  */
+        char *line = NULL;
+        size_t siz = 0;
+        int len = getdelim (&line, &siz, '\n', in);
+        if (!(len == 4 && line && strcmp (line, "foo\n") == 0))
+          return 1;
+      }
+      {
+        /* Test result for a NULL buffer and a non-zero size.
+           This crashes on FreeBSD 8.0.  */
+        char *line = NULL;
+        size_t siz = (size_t)(~0) / 4;
+        if (getdelim (&line, &siz, '\n', in) == -1)
+          return 1;
+      }
+      return 0;
+    }
+    ]])], [gl_cv_func_working_getdelim=yes] dnl The library version works.
+    , [gl_cv_func_working_getdelim=no] dnl The library version does NOT work.
+    , dnl We're cross compiling. Assume it works on glibc2 systems.
+      [AC_EGREP_CPP([Lucky GNU user],
+         [
+#include <features.h>
+#ifdef __GNU_LIBRARY__
+ #if (__GLIBC__ >= 2)
+  Lucky GNU user
+ #endif
+#endif
+         ],
+         [gl_cv_func_working_getdelim=yes],
+         [gl_cv_func_working_getdelim=no])]
+    )])
+  else
+    gl_cv_func_working_getdelim=no
   fi
 
   if test $ac_cv_have_decl_getdelim = no; then
     HAVE_DECL_GETDELIM=0
   fi
+
+  if test $gl_cv_func_working_getdelim = no; then
+    if test $ac_cv_func_getdelim = yes; then
+      REPLACE_GETDELIM=1
+    fi
+    AC_LIBOBJ([getdelim])
+    gl_PREREQ_GETDELIM
+  fi
 ])
 
 # Prerequisites of lib/getdelim.c.
--- m4/stdio_h.m4.orig  Sun Jan 31 17:33:06 2010
+++ m4/stdio_h.m4       Sun Jan 31 17:30:59 2010
@@ -1,4 +1,4 @@
-# stdio_h.m4 serial 24
+# stdio_h.m4 serial 25
 dnl Copyright (C) 2007-2010 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -111,6 +111,7 @@
   REPLACE_FSEEKO=0;              AC_SUBST([REPLACE_FSEEKO])
   REPLACE_FTELL=0;               AC_SUBST([REPLACE_FTELL])
   REPLACE_FTELLO=0;              AC_SUBST([REPLACE_FTELLO])
+  REPLACE_GETDELIM=0;            AC_SUBST([REPLACE_GETDELIM])
   REPLACE_GETLINE=0;             AC_SUBST([REPLACE_GETLINE])
   REPLACE_OBSTACK_PRINTF=0;      AC_SUBST([REPLACE_OBSTACK_PRINTF])
   REPLACE_PERROR=0;              AC_SUBST([REPLACE_PERROR])
--- modules/stdio.orig  Sun Jan 31 17:33:06 2010
+++ modules/stdio       Sun Jan 31 17:30:59 2010
@@ -89,6 +89,7 @@
              -e 's|@''REPLACE_FSEEKO''@|$(REPLACE_FSEEKO)|g' \
              -e 's|@''REPLACE_FTELL''@|$(REPLACE_FTELL)|g' \
              -e 's|@''REPLACE_FTELLO''@|$(REPLACE_FTELLO)|g' \
+             -e 's|@''REPLACE_GETDELIM''@|$(REPLACE_GETDELIM)|g' \
              -e 's|@''REPLACE_GETLINE''@|$(REPLACE_GETLINE)|g' \
              -e 's|@''REPLACE_OBSTACK_PRINTF''@|$(REPLACE_OBSTACK_PRINTF)|g' \
              -e 's|@''REPLACE_PERROR''@|$(REPLACE_PERROR)|g' \
--- tests/test-getdelim.c.orig  Sun Jan 31 17:33:06 2010
+++ tests/test-getdelim.c       Sun Jan 31 17:30:59 2010
@@ -33,13 +33,13 @@
 main (void)
 {
   FILE *f;
-  char *line = NULL;
-  size_t len = 0;
+  char *line;
+  size_t len;
   ssize_t result;
 
   /* Create test file.  */
   f = fopen ("test-getdelim.txt", "wb");
-  if (!f || fwrite ("anbcnd\0f", 1, 8, f) != 8 || fclose (f) != 0)
+  if (!f || fwrite ("anAnbcnd\0f", 1, 10, f) != 10 || fclose (f) != 0)
     {
       fputs ("Failed to create sample file.\n", stderr);
       remove ("test-getdelim.txt");
@@ -54,13 +54,24 @@
     }
 
   /* Test initial allocation, which must include trailing NUL.  */
+  line = NULL;
+  len = 0;
   result = getdelim (&line, &len, 'n', f);
   ASSERT (result == 2);
   ASSERT (strcmp (line, "an") == 0);
   ASSERT (2 < len);
+  free (line);
 
-  /* Test growth of buffer.  */
+  /* Test initial allocation again, with line = NULL and len != 0.  */
+  line = NULL;
+  len = (size_t)(~0) / 4;
+  result = getdelim (&line, &len, 'n', f);
+  ASSERT (result == 2);
+  ASSERT (strcmp (line, "An") == 0);
+  ASSERT (2 < len);
   free (line);
+
+  /* Test growth of buffer.  */
   line = malloc (1);
   len = 1;
   result = getdelim (&line, &len, 'n', f);




reply via email to

[Prev in Thread] Current Thread [Next in Thread]