commit 60c096eb0433f7573c768a2c8523abd3c11e0720
parent b35761a1a8378e068fead72f828f2400a20682a8
Author: jvoisin <julien.voisin@dustri.org>
Date: Wed, 1 Apr 2026 20:37:02 +0200
Make do even if PATH_MAX isn't defined
As explained in `man realpath(3)`:
> The POSIX.1-2001 standard version of this function is broken by design,
> since it is impossible to determine a suitable size for the output
> buffer, resolved_path. According to POSIX.1-2001 a buffer of size PATH_MAX
> suffices, but PATH_MAX need not be a defined constant, and may have to be
> obtained using pathconf(3). And asking pathconf(3) does not really help,
> since, on the one hand POSIX warns that the result of pathconf(3) may be huge
> and unsuitable for mallocing memory, and on the other hand pathconf(3) may
> return -1 to signify that PATH_MAX is not bounded. The re‐ solved_path
> == NULL feature, not standardized in POSIX.1-2001, but standardized in
> POSIX.1-2008, allows this design problem to be avoided.
So we can either not compile, or be pragmatic, and define PATH_MAX to a sane
value, like 4096, which is the one used on Linux and some/most BSD.
This commit also adds two tests to ensure that things aren't catastrophically
broken by this change.
Diffstat:
4 files changed, 27 insertions(+), 3 deletions(-)
diff --git a/include/stdlib.h b/include/stdlib.h
@@ -43,8 +43,9 @@ __fortify_warning_if(__p == NULL, "'realpath' called with path set to `NULL`; di
_FORTIFY_FN(realpath) char *realpath(const char *__p, char *__r)
{
#ifndef PATH_MAX
-#error PATH_MAX unset. A fortified realpath will not work.
-#else
+/* see man realpath(3) */
+#define PATH_MAX 4096
+#endif
if (__r && PATH_MAX > __bos(__r, 2)) {
char __buf[PATH_MAX], *__ret;
size_t __l;
@@ -59,7 +60,6 @@ _FORTIFY_FN(realpath) char *realpath(const char *__p, char *__r)
return __r;
}
return __orig_realpath(__p, __r);
-#endif
}
#endif
diff --git a/tests/Makefile b/tests/Makefile
@@ -61,6 +61,8 @@ RUNTIME_TARGETS= \
test_read_static \
test_readlink_dynamic \
test_readlink_static \
+ test_realpath_null \
+ test_realpath \
test_recv_dynamic \
test_recv_static \
test_recvfrom_dynamic \
diff --git a/tests/test_realpath.c b/tests/test_realpath.c
@@ -0,0 +1,11 @@
+#include "common.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(int argc, char** argv) {
+ char buf[PATH_MAX];
+ char* rpath = realpath("/root/../", buf);
+ printf("%s\n", rpath);
+ return 0;
+}
diff --git a/tests/test_realpath_null.c b/tests/test_realpath_null.c
@@ -0,0 +1,11 @@
+#include "common.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(int argc, char** argv) {
+ char* rpath = realpath("/root/../", NULL);
+ printf("%s\n", rpath);
+ free(rpath);
+ return 0;
+}