<pre style='margin:0'>
Christopher Nielsen (mascguy) pushed a commit to branch master
in repository macports-legacy-support.
</pre>
<p><a href="https://github.com/macports/macports-legacy-support/commit/b3de412fec8c4ad6c8c825130aa46087cefc8352">https://github.com/macports/macports-legacy-support/commit/b3de412fec8c4ad6c8c825130aa46087cefc8352</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit b3de412fec8c4ad6c8c825130aa46087cefc8352
</span>Author: Fred Wright <fw@fwright.net>
AuthorDate: Fri Oct 25 09:42:53 2024 -0700
<span style='display:block; white-space:pre;color:#404040;'> Rewrite realpath() wrapper.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> The former implementation didn't necessarily provide all versions of
</span><span style='display:block; white-space:pre;color:#404040;'> realpath() that might be invoked, and didn't necessarily invoke the
</span><span style='display:block; white-space:pre;color:#404040;'> proper version. That led to possible crashes and possible unnecessary
</span><span style='display:block; white-space:pre;color:#404040;'> semantic differences. This fixes all that, though it doesn't retrofit
</span><span style='display:block; white-space:pre;color:#404040;'> the 10.5+ semantic changes to 10.4 (and neither did the earlier
</span><span style='display:block; white-space:pre;color:#404040;'> implementation).
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> The former implementation also failed to return any internally
</span><span style='display:block; white-space:pre;color:#404040;'> allocated buffer on failures, causing a memory leak. That is now
</span><span style='display:block; white-space:pre;color:#404040;'> fixed as well.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> TESTED:
</span><span style='display:block; white-space:pre;color:#404040;'> Builds and passes all tests (including expanded tests) on all
</span><span style='display:block; white-space:pre;color:#404040;'> platforms, with all applicable SDKs.
</span>---
src/realpath.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 136 insertions(+), 25 deletions(-)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/realpath.c b/src/realpath.c
</span><span style='display:block; white-space:pre;color:#808080;'>index 744ac2f..dc48fa0 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/realpath.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/realpath.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -1,5 +1,5 @@
</span> /*
<span style='display:block; white-space:pre;background:#ffe0e0;'>- * Copyright (c) 2019
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2024 Frederick H. G. Wright II <fw@fwright.net>
</span> *
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -17,38 +17,149 @@
</span> /* MP support header */
#include "MacportsLegacySupport.h"
<span style='display:block; white-space:pre;background:#ffe0e0;'>-/* realpath wrap */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* realpath wrapper */
</span> #if __MPLS_LIB_SUPPORT_REALPATH_WRAP__
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#include <limits.h>
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Keep stdlib from defining any version of realpath */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define realpath __MPLS_hide_realpath
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> #include <dlfcn.h>
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stddef.h> /* For NULL */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/syslimits.h> /* For PATH_MAX */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Now undo our macro kludge */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef realpath
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This provides a wrapper for realpath() in order to make the 10.6+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * optional buffer allocation available in <10.6. At present, it does not
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * make the optional 10.5+ semantic improvements available in 10.4.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * It provides wrappers for all versions of realpath(), even when targeting
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 10.4, since the client may be built with a later SDK. It attempts to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * pass through to the same version as the one invoked (thereby maintaining
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the semantics), but falls back to the basic version if that fails (normally
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * only on 10.4). If that fails, it bails with an abort(), since that should
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * be impossible with an uncorrupted system library.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The address of the OS realpath() is cached, to avoid repeating the dlsym()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * lookup on every call. In a fallback case, the address of the basic
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * version is cached as if it were the address of the intended version, since
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the intended version isn't going to magically appear later.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Function type for realpath() */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef char *rp_func_t(const char * __restrict, char * __restrict);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Macro defining all versions */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Note that the UNIX2003 version never exists in 64-bit builds. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if !__MPLS_64BIT
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define RP_ALL \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ RP_ENT(,,basic) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ RP_ENT($,UNIX2003,posix) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ RP_ENT($,DARWIN_EXTSN,darwin)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else /* 64-bit */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define RP_ALL \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ RP_ENT(,,basic) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ RP_ENT($,DARWIN_EXTSN,darwin)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif /* 64-bit */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Table of indices of versions */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define RP_ENT(d,x,t) rp_##t,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef enum {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ RP_ALL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} rp_idx_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef RP_ENT
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>-char *realpath(const char * __restrict stringsearch, char * __restrict buffer)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Table of names */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define RP_STR(x) #x
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define RP_ENT(d,x,t) RP_STR(realpath##d##x),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const char *rp_name[] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ RP_ALL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef RP_ENT
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Table of cached addresses */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define RP_ENT(d,x,t) NULL,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static rp_func_t *rp_adr[] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ RP_ALL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef RP_ENT
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Internal realpath(), with version as a parameter */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static char *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+realpath_internal(const char * __restrict file_name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char * __restrict resolved_name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ rp_idx_t version)
</span> {
<span style='display:block; white-space:pre;background:#ffe0e0;'>- char *(*real_realpath)(const char * __restrict, char * __restrict);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-#if (__DARWIN_UNIX03 && !defined(_POSIX_C_SOURCE)) || defined(_DARWIN_C_SOURCE) || defined(_DARWIN_BETTER_REALPATH)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- real_realpath = dlsym(RTLD_NEXT, "realpath$DARWIN_EXTSN");
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-# else
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- real_realpath = dlsym(RTLD_NEXT, "realpath");
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-#endif
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (real_realpath == NULL) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ rp_func_t *os_realpath;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char *buf, *result;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int saved_errno;
</span>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- if (buffer == NULL) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- char *myrealpathbuf = malloc(PATH_MAX);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- if (myrealpathbuf != NULL) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- return(real_realpath(stringsearch, myrealpathbuf));
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- return(NULL);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- return(real_realpath(stringsearch, buffer));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Locate proper OS realpath(), with fallback if needed */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!(os_realpath = rp_adr[version])) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ os_realpath = rp_adr[version] = dlsym(RTLD_NEXT, rp_name[version]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!os_realpath && version != rp_basic) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ os_realpath = rp_adr[version] = dlsym(RTLD_NEXT, rp_name[rp_basic]);
</span> }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!os_realpath) abort();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Just pass through the call if a buffer was supplied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (resolved_name) return (*os_realpath)(file_name, resolved_name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Otherwise allocate a buffer and invoke it with that */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!(buf = malloc(PATH_MAX))) return NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((result = (*os_realpath)(file_name, buf))) return result;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* On failure, free the allocated buffer */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Although free() shouldn't touch errno, we preserve it just in case */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ saved_errno = errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(buf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ errno = saved_errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return NULL;
</span> }
<span style='display:block; white-space:pre;background:#ffe0e0;'>-/* compatibility function so code does not have to be recompiled */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-char *macports_legacy_realpath(const char * __restrict stringsearch, char * __restrict buffer) { return realpath(stringsearch, buffer); }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Now the various public realpath() versions */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define RP_ENT(d,x,t) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+char * \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+realpath##d##x(const char * __restrict file_name, \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char * __restrict resolved_name) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{ \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return realpath_internal(file_name, resolved_name, rp_##t); \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+RP_ALL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef RP_ENT
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Compatibility function to avoid the need to rebuild existing binaries
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * built with the old wrapper-macro implementation (between Jan-2019 and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Apr-2022). We have no way to determine which realpath version was
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * used in such a build (since that information was destroyed by the wrapper
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * macro), so we assume the usual default for the SDK matching the target
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * OS for *this* build. That's the best we can do under the circumstances.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if __MPLS_TARGET_OSVER < 1050
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define RP_DEFAULT rp_basic
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define RP_DEFAULT rp_darwin
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+char *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+macports_legacy_realpath(const char * __restrict file_name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char * __restrict resolved_name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return realpath_internal(file_name, resolved_name, RP_DEFAULT);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span>
#endif /*__MPLS_LIB_SUPPORT_REALPATH_WRAP__*/
</pre><pre style='margin:0'>
</pre>