<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/88f2d1b77dd2cb5dcbb90408fa284f344d4671ae">https://github.com/macports/macports-legacy-support/commit/88f2d1b77dd2cb5dcbb90408fa284f344d4671ae</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit 88f2d1b77dd2cb5dcbb90408fa284f344d4671ae
</span>Author: Fred Wright <fw@fwright.net>
AuthorDate: Wed Nov 6 16:10:53 2024 -0800
<span style='display:block; white-space:pre;color:#404040;'> Add realpath_test tool.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> This provides a tool for investigating the behavior of the different
</span><span style='display:block; white-space:pre;color:#404040;'> versions of realpath() with specified paths.
</span>---
tools/.gitignore | 6 ++
tools/realpath_test.c | 294 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 300 insertions(+)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/tools/.gitignore b/tools/.gitignore
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..09ec20c
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/tools/.gitignore
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,6 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+!.gitignore
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+!*.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+!*.cc
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+!*.cpp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+!*.sh
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/tools/realpath_test.c b/tools/realpath_test.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..0753dab
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/tools/realpath_test.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,294 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2024 Frederick H. G. Wright II <fw@fwright.net>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Permission to use, copy, modify, and distribute this software for any
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * purpose with or without fee is hereby granted, provided that the above
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * copyright notice and this permission notice appear in all copies.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</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;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This provides a purely manual realpath test, for investigative purposes.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * It reports the results for a given input, for all available versions,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * with and without a supplied output buffer. It always reports the results
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * of the unadulterated OS functions, and optionally reports the results of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the functions provided by a specified library.
</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;'>+#include <dlfcn.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <libgen.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <limits.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <setjmp.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <signal.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 <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/wait.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <malloc/malloc.h> /* For malloc_size() */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* RTLD_FIRST is unavailable on 10.4. It's probably unimportant, anyway. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifndef RTLD_FIRST
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define RTLD_FIRST 0
</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;'>+/* 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;'>+typedef struct rp_entry_s {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int local;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *name;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ rp_func_t *func;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} rp_entry_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static rp_entry_t funcs[] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {0, "realpath", NULL},
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {0, "realpath$UNIX2003", NULL},
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {0, "realpath$DARWIN_EXTSN", NULL},
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {1, "realpath", NULL},
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {1, "realpath$UNIX2003", NULL},
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {1, "realpath$DARWIN_EXTSN", NULL},
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NUM_FUNCS (sizeof(funcs) / sizeof(funcs[0]))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct sig_entry_s {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int sig;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *name;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} sig_entry_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static sig_entry_t sigs[] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {SIGBUS, "Bus error"},
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {SIGSEGV, "Segmentation violation"},
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NUM_SIGS (sizeof(sigs) / sizeof(sigs[0]))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void *lib_handle = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+load_lib(const char *path, int verbose)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ lib_handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL | RTLD_FIRST);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!lib_handle) return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (verbose) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" Loaded %s at handle 0x%0lX\n", path, (unsigned long) lib_handle);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 0;
</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;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+unload_lib(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!lib_handle) return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (dlclose(lib_handle)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "Can't close library: %s\n", dlerror());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ lib_handle = NULL;
</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;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+find_sym(rp_entry_t *ent, int verbose)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ void *handle = ent->local ? lib_handle : RTLD_NEXT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *type = ent->local ? "lib" : "OS ";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!handle) return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ent->func = (rp_func_t *) dlsym(handle, ent->name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (verbose) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (ent->func) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" Found: %s %s at 0x%0lX\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ type, ent->name, (unsigned long) ent->func);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" Not found: %s %s\n", type, ent->name);
</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;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+find_syms(int verbose)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for (i = 0; i < NUM_FUNCS; ++i) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ find_sym(&funcs[i], verbose);
</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;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const char *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+get_signame(int sig)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for (i = 0; i < NUM_SIGS; ++i) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (sigs[i].sig == sig) return sigs[i].name;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return NULL;
</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;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Some cases we test may crash with bad memory accesses. We want to catch
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * those without crashing the entire program. The straightforward way
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * to do that would be with a signal handler, but merely returning from
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the signal handler (after recording the signal) repeats the bad access,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ad infinitum, and bailing from the handler via longjmp() isn't safe in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * this context. So our simplest alternative is to run the test call in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * a subprocess, which then abnormally exits in any crash case.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * If we were to perform the test "for real" in a subprocess, we'd need
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * to set up a shared communication page to capture the result for the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * main process. In lieu of that, we use the subprocess for a "dry run",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * and then repeat the test in the main process if the dry run didn't crash.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+try_case(rp_entry_t *ent, const char *path, int no_buf)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *type = ent->local ? "lib" : "OS ";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char *result;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ pid_t child, done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int status;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *signame;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char buf[PATH_MAX];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!ent->func) return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" %s %s (buf%s supplied) for '%s':\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ type, ent->name, no_buf ? " not" : "", path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* First a "dry run" in a subprocess, in case it crashes. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fflush(stdout); /* Forking with unflushed buffers may cause trouble. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ child = fork();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (child < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ perror("fork() failed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (child == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ result = (*ent->func)(path, no_buf ? NULL : buf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Leave any allocated buffer for the process exit to clean up. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ exit(0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ done = wait(&status);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (done != child) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "***** Unexpected wait() pid, %d != %d\n", done, child);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (status) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if(!(signame = get_signame(status))) signame = "(unknown)";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" ***** crashed with exit status %d (%s)\n", status, signame);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return;
</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;'>+ /* Now do it for real */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ errno = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ result = (*ent->func)(path, no_buf ? NULL : buf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (result) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (errno) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" ***** 'success' with errno = %d (%s)\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ errno, strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!no_buf && result != buf) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" ***** returned buffer adr 0x%0lX != supplied adr 0x%0lx\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (unsigned long) result, (unsigned long) buf);
</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;'>+ printf(" '%s'\n", result);
</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;'>+ * There is a bug in the 32-bit 10.6 non-POSIX realpath(), where some
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * cases that would normally be errors instead "succeed" with a pointer
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * to an internal buffer (if one wasn't supplied by the caller), rather
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * than one from malloc(). This buffer is probably unsafe to reference
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * in general (though we do it above, apparently successfully), and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * cannot be freed with free(), thereby violating the API.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * We check for and report this case here.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (no_buf) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!malloc_size(result)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" ***** returned buffer adr 0x%0lX is not from malloc()\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (unsigned long) result);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ free(result);
</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;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" failed, errno = %d (%s)\n", errno, strerror(errno));
</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;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+try_all(const char *path)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for (i = 0; i < NUM_FUNCS; ++i) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ try_case(&funcs[i], path, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for (i = 0; i < NUM_FUNCS; ++i) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ try_case(&funcs[i], path, 1);
</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;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+main(int argc, char *argv[])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int argn = 1, verbose = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *lib_path = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (argn < argc) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!strcmp(argv[argn], "-h")) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("Usage is: %s [-v] [-l <library path>] <test path>...\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ basename(argv[0]));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!strcmp(argv[argn], "-v")) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ verbose = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ++argn;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!strcmp(argv[argn], "-l")) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ++argn;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (argn < argc) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ lib_path = argv[argn];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ++argn;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "-l needs library path arg\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 10;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ break;
</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 (lib_path && load_lib(lib_path, verbose)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, "Can't open library %s: %s\n", lib_path, dlerror());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 20;
</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;'>+ find_syms(verbose);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (argn >= argc) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" Defaulting test case to '.'\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ try_all(".");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (argn < argc) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ try_all(argv[argn]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ++argn;
</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;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ unload_lib();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span></pre><pre style='margin:0'>
</pre>