<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>