From 46a30685834f0f680cc90dda87dc7933d7c17c49 Mon Sep 17 00:00:00 2001
From: Fred Wright <fw@fwright.net>
Date: Thu, 7 Nov 2024 15:16:24 -0800
Subject: [PATCH] realpath: Fix 10.6 non-POSIX version.

This adds our allocating wrapper to the 10.6 non-POSIX case, which
returns an unsafe buffer pointer when supplied with a nonexistent path
and no buffer.  Providing our own malloc()ed buffer avoids the
problem.  This only affects 32-bit builds, since 64-bit non-POSIX is
nonexistent.

The original flag is renamed in the process, with the original name
now reflecting the combined need for the wrapper.

Some whitespace cleanup is also applied to the other composite flag
definitions.

Updates README to reflect the fix.

TESTED:
Tests pass on all platforms, including newly added test case (next
commit).
---
 README.md                       | 13 ++++++++++---
 include/MacportsLegacySupport.h | 24 +++++++++++++++++++-----
 src/add_symbols.c               |  2 +-
 src/realpath.c                  | 21 +++++++++++++++++++--
 test/test_realpath_compat.c     |  6 +++---
 5 files changed, 52 insertions(+), 14 deletions(-)

diff --git a/README.md b/README.md
index 29e6b7b..6b50981 100644
--- a/README.md
+++ b/README.md
@@ -75,11 +75,18 @@ Wrapped headers and replaced functions are:
     <td>OSX10.6, OSX10.12 (open_memstream)</td>
   </tr>
   <tr>
-    <td rowspan="2"><code>stdlib.h</code></td>
-    <td>Adds <code>posix_memalign</code> functional replacement, and wraps <code>realpath</code>
-        to accept a <code>NULL</code> buffer argument</td>
+    <td rowspan="4"><code>stdlib.h</code></td>
+    <td>Adds <code>posix_memalign</code> functional replacement</td>
     <td>OSX10.5</td>
   </tr>
+  <tr>
+    <td>Wraps <code>realpath</code> to accept a <code>NULL</code> buffer argument</td>
+    <td>OSX10.5</td>
+  </tr>
+  <tr>
+    <td>Fixes non-POSIX <code>realpath</code> in 10.6</td>
+    <td>OSX10.6</td>
+  </tr>
   <tr>
     <td>Adds <code>arc4random_uniform</code> and <code>arc4random_buf</code> functions</td>
     <td>OSX10.6</td>
diff --git a/include/MacportsLegacySupport.h b/include/MacportsLegacySupport.h
index 9ac8b2e..cdb6c50 100644
--- a/include/MacportsLegacySupport.h
+++ b/include/MacportsLegacySupport.h
@@ -230,7 +230,13 @@
 /* The addition uses an #ifndef, so no feature flag is necessary */
 
 /*  realpath() on < 10.6 does not support modern NULL buffer usage */
-#define __MPLS_LIB_SUPPORT_REALPATH_WRAP__    (__MPLS_TARGET_OSVER < 1060)
+#define __MPLS_LIB_SUPPORT_REALPATH_ALLOC__   (__MPLS_TARGET_OSVER < 1060)
+
+/* Also, 10.6 non-POSIX realpath() (32-bit only) with a nonexistent path and
+ * a NULL buffer returns an unsafe pointer to an internal buffer. */
+#define __MPLS_LIB_SUPPORT_REALPATH_NONEX_FIX__ (__MPLS_TARGET_OSVER >= 1060 \
+                                                 && __MPLS_TARGET_OSVER < 1070 \
+                                                 && !__MPLS_64BIT)
 
 /* fsetattrlistat, fgetattrlistat */
 #define __MPLS_SDK_SUPPORT_FSETATTRLIST__     (__MPLS_SDK_MAJOR < 1060)
@@ -316,10 +322,18 @@
 #define __MPLS_LIB_SUPPORT_PTHREAD_SETNAME_NP__   (__MPLS_TARGET_OSVER < 1060)
 
 /* Compound macros, bundling functionality needed by multiple single features. */
-#define __MPLS_SDK_NEED_ATCALL_MACROS__  (__MPLS_SDK_SUPPORT_ATCALLS__ || __MPLS_SDK_SUPPORT_SETATTRLISTAT__)
-
-#define __MPLS_SDK_NEED_BEST_FCHDIR__    (__MPLS_SDK_SUPPORT_FDOPENDIR__ || __MPLS_SDK_SUPPORT_ATCALLS__ || __MPLS_SDK_SUPPORT_SETATTRLISTAT__)
-#define __MPLS_LIB_NEED_BEST_FCHDIR__    (__MPLS_LIB_SUPPORT_FDOPENDIR__ || __MPLS_LIB_SUPPORT_ATCALLS__ || __MPLS_LIB_SUPPORT_SETATTRLISTAT__)
+#define __MPLS_SDK_NEED_ATCALL_MACROS__  (__MPLS_SDK_SUPPORT_ATCALLS__ \
+                                          || __MPLS_SDK_SUPPORT_SETATTRLISTAT__)
+
+#define __MPLS_SDK_NEED_BEST_FCHDIR__    (__MPLS_SDK_SUPPORT_FDOPENDIR__ \
+                                          || __MPLS_SDK_SUPPORT_ATCALLS__ \
+                                          || __MPLS_SDK_SUPPORT_SETATTRLISTAT__)
+#define __MPLS_LIB_NEED_BEST_FCHDIR__    (__MPLS_LIB_SUPPORT_FDOPENDIR__ \
+                                          || __MPLS_LIB_SUPPORT_ATCALLS__ \
+                                          || __MPLS_LIB_SUPPORT_SETATTRLISTAT__)
+
+#define __MPLS_LIB_SUPPORT_REALPATH_WRAP__ (__MPLS_LIB_SUPPORT_REALPATH_ALLOC__ \
+                                            || __MPLS_LIB_SUPPORT_REALPATH_NONEX_FIX__)
 
 /* UUIDs - for now, just add missing typedef statements */
 #define __MPLS_SDK_SUPPORT_UUID__  (__MPLS_SDK_MAJOR < 1060)
diff --git a/src/add_symbols.c b/src/add_symbols.c
index 2243728..7f132fe 100644
--- a/src/add_symbols.c
+++ b/src/add_symbols.c
@@ -5,7 +5,7 @@ extern const char posix_memalign_tmp4 __asm("$ld$add$os10.4$_posix_memalign"); _
 extern const char posix_memalign_tmp5 __asm("$ld$add$os10.5$_posix_memalign"); __attribute__((visibility("default"))) const char posix_memalign_tmp5 = 0;
 #endif
 
-#if !(__MPLS_LIB_SUPPORT_REALPATH_WRAP__)
+#if !(__MPLS_LIB_SUPPORT_REALPATH_ALLOC__)
 extern const char realpath_tmp4 __asm("$ld$add$os10.4$_realpath"); __attribute__((visibility("default"))) const char realpath_tmp4 = 0;
 extern const char realpath_tmp5 __asm("$ld$add$os10.5$_realpath$DARWIN_EXTSN"); __attribute__((visibility("default"))) const char realpath_tmp5 = 0;
 #endif
diff --git a/src/realpath.c b/src/realpath.c
index dc48fa0..3e79005 100644
--- a/src/realpath.c
+++ b/src/realpath.c
@@ -54,8 +54,13 @@
 /* Function type for realpath() */
 typedef char *rp_func_t(const char * __restrict, char * __restrict);
 
-/* Macro defining all versions */
-/* Note that the UNIX2003 version never exists in 64-bit builds. */
+/*
+ * Macro defining all versions
+ * Note that the UNIX2003 version never exists in 64-bit builds.
+ * Also note that the 10.6 "nonext" fix only needs the basic version.
+ */
+
+# if __MPLS_LIB_SUPPORT_REALPATH_ALLOC__
 
 #if !__MPLS_64BIT
 
@@ -72,6 +77,14 @@ typedef char *rp_func_t(const char * __restrict, char * __restrict);
 
 #endif /* 64-bit */
 
+#endif /* __MPLS_LIB_SUPPORT_REALPATH_ALLOC__ */
+
+#if __MPLS_LIB_SUPPORT_REALPATH_NONEX_FIX__
+
+#define RP_ALL RP_ENT(,,basic)
+
+#endif /* __MPLS_LIB_SUPPORT_REALPATH_NONEX_FIX__ */
+
 /* Table of indices of versions */
 #define RP_ENT(d,x,t) rp_##t,
 typedef enum {
@@ -140,6 +153,8 @@ realpath##d##x(const char * __restrict file_name, \
 RP_ALL
 #undef RP_ENT
 
+# if __MPLS_LIB_SUPPORT_REALPATH_ALLOC__
+
 /*
  * Compatibility function to avoid the need to rebuild existing binaries
  * built with the old wrapper-macro implementation (between Jan-2019 and
@@ -162,4 +177,6 @@ macports_legacy_realpath(const char * __restrict file_name,
   return realpath_internal(file_name, resolved_name, RP_DEFAULT);
 }
 
+#endif /* __MPLS_LIB_SUPPORT_REALPATH_ALLOC__ */
+
 #endif /*__MPLS_LIB_SUPPORT_REALPATH_WRAP__*/
diff --git a/test/test_realpath_compat.c b/test/test_realpath_compat.c
index 8158758..d9a890f 100644
--- a/test/test_realpath_compat.c
+++ b/test/test_realpath_compat.c
@@ -12,14 +12,14 @@
 
 /* MP support header */
 #include "MacportsLegacySupport.h"
-#if __MPLS_LIB_SUPPORT_REALPATH_WRAP__
+#if __MPLS_LIB_SUPPORT_REALPATH_ALLOC__
 
 #define TEST_MACPORTS_LEGACY_REALPATH
 
 #include "test_realpath.c"
 
-#else /* !__MPLS_LIB_SUPPORT_REALPATH_WRAP__ */
+#else /* !__MPLS_LIB_SUPPORT_REALPATH_ALLOC__ */
 
 int main(){ return 0; }
 
-#endif /* !__MPLS_LIB_SUPPORT_REALPATH_WRAP__ */
+#endif /* !__MPLS_LIB_SUPPORT_REALPATH_ALLOC__ */
-- 
GitLab