Skip to content

Commit

Permalink
getcwd: break fdopendir + save_cwd recursive loop (Bug#13516)
Browse files Browse the repository at this point in the history
Reported for OS X 10.8.2 by Assaf Gordon in
<http://bugs.gnu.org/13516>.
* 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.
  • Loading branch information
eggert committed Feb 4, 2013
1 parent 6668cfa commit ca369c8
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 58 deletions.
14 changes: 14 additions & 0 deletions ChangeLog
@@ -1,5 +1,19 @@
2013-02-03 Paul Eggert <eggert@cs.ucla.edu>

getcwd: break fdopendir + save_cwd recursive loop (Bug#13516)
Reported for OS X 10.8.2 by Assaf Gordon in
<http://bugs.gnu.org/13516>.
* 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
Expand Down
6 changes: 3 additions & 3 deletions lib/getcwd.c
Expand Up @@ -28,9 +28,9 @@
#include <fcntl.h> /* 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
Expand Down
62 changes: 36 additions & 26 deletions m4/getcwd-abort-bug.m4
Expand Up @@ -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);
Expand All @@ -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;
Expand Down
71 changes: 42 additions & 29 deletions tests/test-getcwd.c
Expand Up @@ -38,60 +38,73 @@
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)
return 2;

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;
Expand Down

0 comments on commit ca369c8

Please sign in to comment.