comparison tests/test-getcwd.c @ 17311:ab5135d5ff83

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.
author Paul Eggert <eggert@cs.ucla.edu>
date Sun, 03 Feb 2013 21:28:30 -0800
parents e542fd46ad6f
children 344018b6e5d7
comparison
equal deleted inserted replaced
17310:a9f418d6d676 17311:ab5135d5ff83
36 /* This size is chosen to be larger than PATH_MAX (4k), yet smaller than 36 /* This size is chosen to be larger than PATH_MAX (4k), yet smaller than
37 the 16kB pagesize on ia64 linux. Those conditions make the code below 37 the 16kB pagesize on ia64 linux. Those conditions make the code below
38 trigger a bug in glibc's getcwd implementation before 2.4.90-10. */ 38 trigger a bug in glibc's getcwd implementation before 2.4.90-10. */
39 #define TARGET_LEN (5 * 1024) 39 #define TARGET_LEN (5 * 1024)
40 40
41 #if defined HAVE_OPENAT || (defined GNULIB_OPENAT && defined HAVE_FDOPENDIR)
42 # define HAVE_OPENAT_SUPPORT 1
43 #else
44 # define HAVE_OPENAT_SUPPORT 0
45 #endif
46
41 /* Keep this test in sync with m4/getcwd-abort-bug.m4. */ 47 /* Keep this test in sync with m4/getcwd-abort-bug.m4. */
42 static int 48 static int
43 test_abort_bug (void) 49 test_abort_bug (void)
44 { 50 {
45 char const *dir_name = "confdir-14B---";
46 char *cwd; 51 char *cwd;
47 size_t initial_cwd_len; 52 size_t initial_cwd_len;
48 int fail = 0; 53 int fail = 0;
49 size_t desired_depth; 54
50 size_t d;
51
52 #ifdef PATH_MAX
53 /* The bug is triggered when PATH_MAX < getpagesize (), so skip 55 /* The bug is triggered when PATH_MAX < getpagesize (), so skip
54 this relatively expensive and invasive test if that's not true. */ 56 this relatively expensive and invasive test if that's not true. */
55 if (getpagesize () <= PATH_MAX) 57 #ifdef PATH_MAX
58 int bug_possible = PATH_MAX < getpagesize ();
59 #else
60 int bug_possible = 0;
61 #endif
62 if (! bug_possible)
56 return 0; 63 return 0;
57 #endif
58 64
59 cwd = getcwd (NULL, 0); 65 cwd = getcwd (NULL, 0);
60 if (cwd == NULL) 66 if (cwd == NULL)
61 return 2; 67 return 2;
62 68
63 initial_cwd_len = strlen (cwd); 69 initial_cwd_len = strlen (cwd);
64 free (cwd); 70 free (cwd);
65 desired_depth = ((TARGET_LEN - 1 - initial_cwd_len) 71
66 / (1 + strlen (dir_name))); 72 if (HAVE_OPENAT_SUPPORT)
67 for (d = 0; d < desired_depth; d++)
68 { 73 {
69 if (mkdir (dir_name, S_IRWXU) < 0 || chdir (dir_name) < 0) 74 static char const dir_name[] = "confdir-14B---";
70 { 75 size_t desired_depth = ((TARGET_LEN - 1 - initial_cwd_len)
71 if (! (errno == ERANGE || errno == ENAMETOOLONG || errno == ENOENT)) 76 / sizeof dir_name);
72 fail = 3; /* Unable to construct deep hierarchy. */ 77 size_t d;
73 break; 78 for (d = 0; d < desired_depth; d++)
74 } 79 {
75 } 80 if (mkdir (dir_name, S_IRWXU) < 0 || chdir (dir_name) < 0)
76 81 {
77 /* If libc has the bug in question, this invocation of getcwd 82 if (! (errno == ERANGE || errno == ENAMETOOLONG
78 results in a failed assertion. */ 83 || errno == ENOENT))
79 cwd = getcwd (NULL, 0); 84 fail = 3; /* Unable to construct deep hierarchy. */
80 if (cwd == NULL) 85 break;
81 fail = 4; /* getcwd didn't assert, but it failed for a long name 86 }
82 where the answer could have been learned. */ 87 }
83 free (cwd); 88
84 89 /* If libc has the bug in question, this invocation of getcwd
85 /* Call rmdir first, in case the above chdir failed. */ 90 results in a failed assertion. */
86 rmdir (dir_name); 91 cwd = getcwd (NULL, 0);
87 while (0 < d--) 92 if (cwd == NULL)
88 { 93 fail = 4; /* getcwd didn't assert, but it failed for a long name
89 if (chdir ("..") < 0) 94 where the answer could have been learned. */
90 { 95 free (cwd);
91 fail = 5; 96
92 break; 97 /* Call rmdir first, in case the above chdir failed. */
93 }
94 rmdir (dir_name); 98 rmdir (dir_name);
99 while (0 < d--)
100 {
101 if (chdir ("..") < 0)
102 {
103 fail = 5;
104 break;
105 }
106 rmdir (dir_name);
107 }
95 } 108 }
96 109
97 return fail; 110 return fail;
98 } 111 }
99 112