getcwd: Fix cross-compilation guess for musl libc.
[gnulib.git] / m4 / getcwd-abort-bug.m4
blobbd32de1b79683b8b4e3bc0694195115c46220709
1 # serial 16
2 # Determine whether getcwd aborts when the length of the working directory
3 # name is unusually large.  Any length between 4k and 16k trigger the bug
4 # when using glibc-2.4.90-9 or older.
6 # Copyright (C) 2006, 2009-2021 Free Software Foundation, Inc.
7 # This file is free software; the Free Software Foundation
8 # gives unlimited permission to copy and/or distribute it,
9 # with or without modifications, as long as this notice is preserved.
11 # From Jim Meyering
13 # gl_FUNC_GETCWD_ABORT_BUG([ACTION-IF-BUGGY[, ACTION-IF-WORKS]])
14 AC_DEFUN([gl_FUNC_GETCWD_ABORT_BUG],
16   AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
17   AC_CHECK_DECLS_ONCE([getcwd])
18   AC_CHECK_HEADERS_ONCE([unistd.h])
19   AC_REQUIRE([gl_PATHMAX_SNIPPET_PREREQ])
21   gl_CHECK_FUNC_GETPAGESIZE
22   if test $gl_cv_func_getpagesize = yes; then
23     AC_DEFINE_UNQUOTED([HAVE_GETPAGESIZE], [1],
24       [Define to 1 if the system has the 'getpagesize' function.])
25   fi
27   AC_CACHE_CHECK([whether getcwd succeeds when 4k < cwd_length < 16k],
28     [gl_cv_func_getcwd_succeeds_beyond_4k],
29     [# Remove any remnants of a previous test.
30      rm -rf confdir-14B---
31      # Arrange for deletion of the temporary directory this test creates.
32      ac_clean_files="$ac_clean_files confdir-14B---"
33      dnl Please keep this in sync with tests/test-getcwd.c.
34      AC_RUN_IFELSE(
35        [AC_LANG_SOURCE(
36           [[
37 #include <errno.h>
38 #include <stdlib.h>
39 #if HAVE_UNISTD_H
40 # include <unistd.h>
41 #else /* on Windows with MSVC */
42 # include <direct.h>
43 #endif
44 #include <string.h>
45 #include <sys/stat.h>
47 ]gl_PATHMAX_SNIPPET[
48 ]GL_MDA_DEFINES[
50 #ifndef S_IRWXU
51 # define S_IRWXU 0700
52 #endif
54 /* FIXME: skip the run-test altogether on systems without getpagesize.  */
55 #if ! HAVE_GETPAGESIZE
56 # define getpagesize() 0
57 #endif
59 /* This size is chosen to be larger than PATH_MAX (4k), yet smaller than
60    the 16kB pagesize on ia64 linux.  Those conditions make the code below
61    trigger a bug in glibc's getcwd implementation before 2.4.90-10.  */
62 #define TARGET_LEN (5 * 1024)
64 int
65 main ()
67   char *cwd;
68   size_t initial_cwd_len;
69   int fail = 0;
71   /* The bug is triggered when PATH_MAX < getpagesize (), so skip
72      this relatively expensive and invasive test if that's not true.  */
73 #ifdef PATH_MAX
74   int bug_possible = PATH_MAX < getpagesize ();
75 #else
76   int bug_possible = 0;
77 #endif
78   if (! bug_possible)
79     return 0;
81   cwd = getcwd (NULL, 0);
82   if (cwd == NULL)
83     return 2;
85   initial_cwd_len = strlen (cwd);
86   free (cwd);
88   if (1)
89     {
90       static char const dir_name[] = "confdir-14B---";
91       size_t desired_depth = ((TARGET_LEN - 1 - initial_cwd_len)
92                               / sizeof dir_name);
93       size_t d;
94       for (d = 0; d < desired_depth; d++)
95         {
96           if (mkdir (dir_name, S_IRWXU) < 0 || chdir (dir_name) < 0)
97             {
98               if (! (errno == ERANGE || errno == ENAMETOOLONG
99                      || errno == ENOENT))
100                 fail = 3; /* Unable to construct deep hierarchy.  */
101               break;
102             }
103         }
105       /* If libc has the bug in question, this invocation of getcwd
106          results in a failed assertion.  */
107       cwd = getcwd (NULL, 0);
108       if (cwd == NULL)
109         fail = 4; /* getcwd didn't assert, but it failed for a long name
110                      where the answer could have been learned.  */
111       free (cwd);
113       /* Call rmdir first, in case the above chdir failed.  */
114       rmdir (dir_name);
115       while (0 < d--)
116         {
117           if (chdir ("..") < 0)
118             {
119               fail = 5;
120               break;
121             }
122           rmdir (dir_name);
123         }
124     }
126   return fail;
128           ]])],
129        [gl_cv_func_getcwd_succeeds_beyond_4k=yes],
130        [dnl An abort will provoke an exit code of something like 134 (128 + 6).
131         dnl An exit code of 4 can also occur (for example in
132         dnl musl libc 1.2.2/powerpc64le, NetBSD 9.0, OpenBSD 6.7:
133         dnl getcwd (NULL, 0) fails rather than returning a string longer than
134         dnl PATH_MAX.  This may be POSIX compliant (in some interpretations of
135         dnl POSIX).  But gnulib's getcwd module wants to provide a non-NULL
136         dnl value in this case.
137         ret=$?
138         if test $ret -ge 128 || test $ret = 4; then
139           gl_cv_func_getcwd_succeeds_beyond_4k=no
140         else
141           gl_cv_func_getcwd_succeeds_beyond_4k=yes
142         fi
143        ],
144        [case "$host_os" in
145              # Guess no otherwise, even on glibc systems and musl systems.
146           *) gl_cv_func_getcwd_succeeds_beyond_4k="guessing no"
147         esac
148        ])
149     ])
150   case "$gl_cv_func_getcwd_succeeds_beyond_4k" in
151     *no)
152       $1
153       ;;
154     *)
155       $2
156       ;;
157   esac