Test for a bug that causes glibc's getcwd to suffer a failed assertion.
authorJim Meyering <jim@meyering.net>
Sun, 18 Jun 2006 21:52:03 +0000 (21:52 +0000)
committerJim Meyering <jim@meyering.net>
Sun, 18 Jun 2006 21:52:03 +0000 (21:52 +0000)
* getcwd-abort-bug.m4 (gl_FUNC_GETCWD_ABORT_BUG): New file and macro.
* getcwd.m4 (gl_FUNC_GETCWD): If we detect support for getcwd_null,
also check for glibc-2.4's abort-inducing bug.

m4/ChangeLog
m4/getcwd-abort-bug.m4 [new file with mode: 0644]
m4/getcwd.m4

index ced95dd..2fc9a18 100644 (file)
@@ -1,5 +1,10 @@
 2006-06-18  Jim Meyering  <jim@meyering.net>
 
+       Test for a bug that causes glibc's getcwd to suffer a failed assertion.
+       * getcwd-abort-bug.m4 (gl_FUNC_GETCWD_ABORT_BUG): New file and macro.
+       * getcwd.m4 (gl_FUNC_GETCWD): If we detect support for getcwd_null,
+       also check for glibc-2.4's abort-inducing bug.
+
        * getcwd-path-max.m4 (gl_FUNC_GETCWD_PATH_MAX): Fix typo.
        Low-probability clean-up should be to use rmdir to get rid of
        the just-created directory, not unlink.
diff --git a/m4/getcwd-abort-bug.m4 b/m4/getcwd-abort-bug.m4
new file mode 100644 (file)
index 0000000..a431a7c
--- /dev/null
@@ -0,0 +1,106 @@
+#serial 1
+# Determine whether getcwd aborts when the length of the working directory
+# name is unusually large.  Any length between 4k and 16k trigger the bug
+# when using glibc-2.4.90-9 or older.
+
+# Copyright (C) 2006 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# From Jim Meyering
+
+# gl_FUNC_GETCWD_ABORT_BUG([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+AC_DEFUN([gl_FUNC_GETCWD_ABORT_BUG],
+[
+  AC_CHECK_DECLS_ONCE(getcwd)
+  AC_CHECK_FUNCS(getpagesize)
+  AC_CACHE_CHECK([whether getcwd aborts when 4k < cwd_length < 16k],
+    gl_cv_func_getcwd_abort_bug,
+    [# Remove any remnants of a previous test.
+     rm -rf confdir-14B---
+     # Arrange for deletion of the temporary directory this test creates.
+     ac_clean_files="$ac_clean_files confdir-14B---"
+     AC_RUN_IFELSE(
+       [AC_LANG_SOURCE(
+         [[
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/stat.h>
+
+/* Don't get link errors because mkdir is redefined to rpl_mkdir.  */
+#undef mkdir
+
+#ifndef S_IRWXU
+# define S_IRWXU 0700
+#endif
+
+/* FIXME: skip the run-test altogether on systems without getpagesize.  */
+#if ! HAVE_GETPAGESIZE
+# define getpagesize() 0
+#endif
+
+/* This size is chosen to be larger than PATH_MAX (4k), yet smaller than
+   the 16kB pagesize on ia64 linux.  Those conditions make the code below
+   trigger a bug in glibc's getcwd implementation before 2.4.90-10.  */
+#define TARGET_LEN (5 * 1024)
+
+int
+main ()
+{
+  char const *dir_name = "confdir-14B---";
+  char *cwd;
+  size_t initial_cwd_len;
+  int fail = 0;
+  size_t desired_depth;
+  size_t d;
+
+  /* The bug is triggered when PATH_MAX < getpagesize (), so skip
+     this relative expensive and invasive test if that's not true.  */
+  if (getpagesize () <= PATH_MAX)
+    return 0;
+
+  cwd = getcwd (NULL, 0);
+  if (cwd == NULL)
+    return 0;
+
+  initial_cwd_len = strlen (cwd);
+  free (cwd);
+  desired_depth = ((TARGET_LEN - 1 - initial_cwd_len)
+                  / (1 + strlen (dir_name)));
+  for (d = 0; d < desired_depth; d++)
+    {
+      if (mkdir (dir_name, S_IRWXU) < 0 || chdir (dir_name) < 0)
+       {
+         fail = 3; /* Unable to construct deep hierarchy.  */
+         break;
+       }
+    }
+
+  /* If libc has the bug in question, this invocation of getcwd
+     results in a failed assertion.  */
+  cwd = getcwd (NULL, 0);
+  if (cwd == NULL)
+    fail = 4; /* getcwd failed.  This is ok, and expected.  */
+  free (cwd);
+
+  /* Call rmdir first, in case the above chdir failed.  */
+  rmdir (dir_name);
+  while (0 < d--)
+    {
+      if (chdir ("..") < 0)
+       break;
+      rmdir (dir_name);
+    }
+
+  return 0;
+}
+          ]])],
+    [gl_cv_func_getcwd_abort_bug=no],
+    [gl_cv_func_getcwd_abort_bug=yes],
+    [gl_cv_func_getcwd_abort_bug=yes])
+  ])
+  AS_IF([test $gl_cv_func_getcwd_abort_bug = yes], [$1], [$2])
+])
index 35d0b53..8f17432 100644 (file)
@@ -1,6 +1,6 @@
 # getcwd.m4 - check for working getcwd that is compatible with glibc
 
-# Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+# Copyright (C) 2001, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
@@ -40,12 +40,15 @@ AC_DEFUN([gl_FUNC_GETCWD],
 [
   AC_REQUIRE([gl_FUNC_GETCWD_NULL])
 
+  gl_abort_bug=no
   case $gl_cv_func_getcwd_null in
-  yes) gl_FUNC_GETCWD_PATH_MAX;;
+  yes)
+    gl_FUNC_GETCWD_PATH_MAX
+    gl_FUNC_GETCWD_ABORT_BUG([gl_abort_bug=yes]);;
   esac
 
-  case $gl_cv_func_getcwd_null,$gl_cv_func_getcwd_path_max in
-  yes,yes) ;;
+  case $gl_cv_func_getcwd_null,$gl_cv_func_getcwd_path_max,$gl_abort_bug in
+  yes,yes,no) ;;
   *)
     AC_LIBOBJ([getcwd])
     AC_DEFINE([__GETCWD_PREFIX], [[rpl_]],