From ca369c8d661a10d8a0ae3d712e7dfa91664921f1 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 3 Feb 2013 21:28:30 -0800 Subject: [PATCH] getcwd: break fdopendir + save_cwd recursive loop (Bug#13516) Reported for OS X 10.8.2 by Assaf Gordon in . * lib/getcwd.c (HAVE_OPENAT_SUPPORT): Do not define if !HAVE_OPENAT && !HAVE_FDOPENDIR. * m4/getcwd-abort-bug.m4: Reformat to match test-getcwd.c so that they can be kept in sync more easily. Avoid PATH_MAX test on the Hurd. Sync from test-getcwd.c for errno tests after mkdir or chdir failure. * tests/test-getcwd.c (HAVE_OPENAT_SUPPORT): New macro, from lib/getcwd.c. (test_abort_bug): Do not test for the deep directory bug unless we have openat support. Avoid PATH_MAX test on the Hurd. --- ChangeLog | 14 ++++++++++ lib/getcwd.c | 6 ++--- m4/getcwd-abort-bug.m4 | 62 +++++++++++++++++++++++++------------------ tests/test-getcwd.c | 71 +++++++++++++++++++++++++++++--------------------- 4 files changed, 95 insertions(+), 58 deletions(-) diff --git a/ChangeLog b/ChangeLog index 688b7e062..f5676e1f8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,19 @@ 2013-02-03 Paul Eggert + getcwd: break fdopendir + save_cwd recursive loop (Bug#13516) + Reported for OS X 10.8.2 by Assaf Gordon in + . + * lib/getcwd.c (HAVE_OPENAT_SUPPORT): Do not define if + !HAVE_OPENAT && !HAVE_FDOPENDIR. + * m4/getcwd-abort-bug.m4: Reformat to match test-getcwd.c + so that they can be kept in sync more easily. Avoid PATH_MAX + test on the Hurd. Sync from test-getcwd.c for errno tests after + mkdir or chdir failure. + * tests/test-getcwd.c (HAVE_OPENAT_SUPPORT): New macro, from + lib/getcwd.c. + (test_abort_bug): Do not test for the deep directory bug unless we + have openat support. Avoid PATH_MAX test on the Hurd. + regex-tests, regex: fix bug: memset undeclared * tests/test-regex.c: Don't include regex.h twice. Include string.h, to declare memset. Christensen's report also mentioned diff --git a/lib/getcwd.c b/lib/getcwd.c index a4cbe0138..4b781389b 100644 --- a/lib/getcwd.c +++ b/lib/getcwd.c @@ -28,9 +28,9 @@ #include /* For AT_FDCWD on Solaris 9. */ /* If this host provides the openat function or if we're using the - gnulib replacement function, then enable code below to make getcwd - more efficient and robust. */ -#if defined HAVE_OPENAT || defined GNULIB_OPENAT + gnulib replacement function with a native fdopendir, then enable + code below to make getcwd more efficient and robust. */ +#if defined HAVE_OPENAT || (defined GNULIB_OPENAT && defined HAVE_FDOPENDIR) # define HAVE_OPENAT_SUPPORT 1 #else # define HAVE_OPENAT_SUPPORT 0 diff --git a/m4/getcwd-abort-bug.m4 b/m4/getcwd-abort-bug.m4 index a6ee6cd7e..9b3b5636b 100644 --- a/m4/getcwd-abort-bug.m4 +++ b/m4/getcwd-abort-bug.m4 @@ -58,16 +58,18 @@ AC_DEFUN([gl_FUNC_GETCWD_ABORT_BUG], 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 relatively expensive and invasive test if that's not true. */ - if (getpagesize () <= PATH_MAX) +#ifdef PATH_MAX + int bug_possible = PATH_MAX < getpagesize (); +#else + int bug_possible = 0; +#endif + if (! bug_possible) return 0; cwd = getcwd (NULL, 0); @@ -76,35 +78,43 @@ main () 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 (1) { - if (mkdir (dir_name, S_IRWXU) < 0 || chdir (dir_name) < 0) + static char const dir_name[] = "confdir-14B---"; + size_t desired_depth = ((TARGET_LEN - 1 - initial_cwd_len) + / sizeof dir_name); + size_t d; + for (d = 0; d < desired_depth; d++) { - fail = 3; /* Unable to construct deep hierarchy. */ - break; + if (mkdir (dir_name, S_IRWXU) < 0 || chdir (dir_name) < 0) + { + if (! (errno == ERANGE || errno == ENAMETOOLONG + || errno == ENOENT)) + 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: it refuses to return a string longer - than PATH_MAX. */ - free (cwd); + /* 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 didn't assert, but it failed for a long name + where the answer could have been learned. */ + free (cwd); - /* Call rmdir first, in case the above chdir failed. */ - rmdir (dir_name); - while (0 < d--) - { - if (chdir ("..") < 0) + /* Call rmdir first, in case the above chdir failed. */ + rmdir (dir_name); + while (0 < d--) { - fail = 5; - break; + if (chdir ("..") < 0) + { + fail = 5; + break; + } + rmdir (dir_name); } - rmdir (dir_name); } return fail; diff --git a/tests/test-getcwd.c b/tests/test-getcwd.c index 4b951e079..810b47667 100644 --- a/tests/test-getcwd.c +++ b/tests/test-getcwd.c @@ -38,23 +38,29 @@ trigger a bug in glibc's getcwd implementation before 2.4.90-10. */ #define TARGET_LEN (5 * 1024) +#if defined HAVE_OPENAT || (defined GNULIB_OPENAT && defined HAVE_FDOPENDIR) +# define HAVE_OPENAT_SUPPORT 1 +#else +# define HAVE_OPENAT_SUPPORT 0 +#endif + /* Keep this test in sync with m4/getcwd-abort-bug.m4. */ static int test_abort_bug (void) { - char const *dir_name = "confdir-14B---"; char *cwd; size_t initial_cwd_len; int fail = 0; - size_t desired_depth; - size_t d; -#ifdef PATH_MAX /* The bug is triggered when PATH_MAX < getpagesize (), so skip this relatively expensive and invasive test if that's not true. */ - if (getpagesize () <= PATH_MAX) - return 0; +#ifdef PATH_MAX + int bug_possible = PATH_MAX < getpagesize (); +#else + int bug_possible = 0; #endif + if (! bug_possible) + return 0; cwd = getcwd (NULL, 0); if (cwd == NULL) @@ -62,36 +68,43 @@ test_abort_bug (void) 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 (HAVE_OPENAT_SUPPORT) { - if (mkdir (dir_name, S_IRWXU) < 0 || chdir (dir_name) < 0) + static char const dir_name[] = "confdir-14B---"; + size_t desired_depth = ((TARGET_LEN - 1 - initial_cwd_len) + / sizeof dir_name); + size_t d; + for (d = 0; d < desired_depth; d++) { - if (! (errno == ERANGE || errno == ENAMETOOLONG || errno == ENOENT)) - fail = 3; /* Unable to construct deep hierarchy. */ - break; + if (mkdir (dir_name, S_IRWXU) < 0 || chdir (dir_name) < 0) + { + if (! (errno == ERANGE || errno == ENAMETOOLONG + || errno == ENOENT)) + 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 didn't assert, but it failed for a long name - where the answer could have been learned. */ - free (cwd); + /* 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 didn't assert, but it failed for a long name + where the answer could have been learned. */ + free (cwd); - /* Call rmdir first, in case the above chdir failed. */ - rmdir (dir_name); - while (0 < d--) - { - if (chdir ("..") < 0) + /* Call rmdir first, in case the above chdir failed. */ + rmdir (dir_name); + while (0 < d--) { - fail = 5; - break; + if (chdir ("..") < 0) + { + fail = 5; + break; + } + rmdir (dir_name); } - rmdir (dir_name); } return fail; -- 2.11.0