changeset 382:dd5d03483314

- dynload changes to support macos >= 11.0.1 "built-in dynamic linker cache of all system-provided libraries" (those dylibs are no longer present on the fs)" * dynload_plain test code changes to reflect this * note in doc - changed dynload_plain to not do inode-based tests on windows
author Tassilo Philipp
date Wed, 20 Jan 2021 13:49:43 +0100
parents fccbb45a2dae
children 268378d66610
files ChangeLog dynload/dynload.3 dynload/dynload.h dynload/dynload_syms_mach-o.c test/dynload_plain/dynload_plain.c
diffstat 5 files changed, 64 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Dec 29 13:30:59 2020 +0100
+++ b/ChangeLog	Wed Jan 20 13:49:43 2021 +0100
@@ -16,8 +16,11 @@
   o support clang's integrated as (didn't build on non-Darwin PPC32 platforms)
 dynload:
   o fix to build with musl libc
+  o support for loading macos >= 11.0.1 (Big Sur) dylibs provided by system's "built-in dynamic
+    linker cache of all system-provided libraries" (those dylibs are no longer present on the fs)
 doc:
   o manual now specifying calling convention signature chars
+  o dynload(3) note about macos >= 11.0.1 cached dylib support (see above)
 bindings:
   o python: Python 3 support, Python 2 unicode support, added get_path function, changing
     'Z' conversions to only immutable types and 'p' to mutable types (and handles), support
@@ -27,6 +30,9 @@
 tests:
   o extended callf testcode to test callconv mode switch signature chars (including syscalls)
   o robustness fixes (thanks Bernhard!)
+  o dynload_plain test fix on macos >= 11.0.1 (Big Sur)
+  o made inode testing of dynload_plain optional, depending on platform support or if macos
+    dylib not on fs but provided through system's cache
 buildsys:
   o cmake support of armasm64 on windows (thanks Bernhard!)
 
--- a/dynload/dynload.3	Tue Dec 29 13:30:59 2020 +0100
+++ b/dynload/dynload.3	Wed Jan 20 13:49:43 2021 +0100
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2007-2017 Daniel Adler <dadler AT uni-goettingen DOT de>, 
+.\" Copyright (c) 2007-2020 Daniel Adler <dadler AT uni-goettingen DOT de>,
 .\"                         Tassilo Philipp <tphilipp AT potion-studios DOT com>
 .\" 
 .\" Permission to use, copy, modify, and distribute this software for any
@@ -100,6 +100,9 @@
 are used to lookup symbol names using an index or symbol's address, respectively, returning a null pointer on error. The names are returned as they would appear in C source code (mangled if C++, etc.). The address passed to
 .Fn dlSymsNameFromValue
 must point to a loaded symbol.
+.Sh NOTES
+.Fn dlLoadLibrary
+does handle loading dylibs on macos >= 11.0.1 that aren't on the file system but are provided through the OS' "built-in dynamic linker cache of all system-provided libraries" (to load, use same "path" as one would with dlopen(3)).
 .Sh BUGS
 .Fn dlGetLibraryPath
 is not thread-safe on Darwin (macOS, iOS, ...) and OpenBSD.
--- a/dynload/dynload.h	Tue Dec 29 13:30:59 2020 +0100
+++ b/dynload/dynload.h	Wed Jan 20 13:49:43 2021 +0100
@@ -39,7 +39,7 @@
 
 /* shared library loading and explicit symbol resolving */
 /* dlLoadLibrary will search for specified lib (e.g. as leaf name, only), */
-/* to the platforms dynamic linking style */
+/* following platforms' dynamic linking style, returns NULL on error */
 
 typedef struct DLLib_ DLLib;
 
--- a/dynload/dynload_syms_mach-o.c	Tue Dec 29 13:30:59 2020 +0100
+++ b/dynload/dynload_syms_mach-o.c	Wed Jan 20 13:49:43 2021 +0100
@@ -39,7 +39,6 @@
 
 #include <mach-o/dyld.h>
 #include <mach-o/nlist.h>
-#include <sys/stat.h>
 #include <dlfcn.h>
 #include <string.h>
 
@@ -73,13 +72,9 @@
 	DLLib* pLib;
 	DLSyms* pSyms = NULL;
 	uint32_t i, n;
-	struct stat st0;
 	const struct MACH_HEADER_TYPE* pHeader = NULL;
 	const struct dysymtab_command* dysymtab_cmd = NULL;
 
-	if(stat(libPath, &st0) == -1)
-		return NULL;
-
 	pLib = dlLoadLibrary(libPath);
 	if(!pLib)
 		return NULL;
@@ -87,18 +82,26 @@
 	/* Loop over all dynamically linked images to find ours. */
 	for(i = 0, n = _dyld_image_count(); i < n; ++i)
 	{
-		struct stat st1;
 		const char* name = _dyld_get_image_name(i);
 
-		if(name && (stat(name, &st1) != -1))
+		if(name)
 		{
 			/* Don't rely on name comparison alone, as libPath might be relative, symlink, differently */
-			/* cased, etc., but compare inode number with the one of the mapped dyld image. */
-			if(st0.st_ino == st1.st_ino/*!strcmp(name, libPath)*/)
+			/* cased, use weird osx path placeholders, etc., but compare inode number with the one of the mapped dyld image. */
+
+			/* reload already loaded lib to get handle to compare with, should be lightweight and only increase ref count */
+			DLLib* pLib_ = dlLoadLibrary(name);
+			if(pLib_)
 			{
-				pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(i);
+				/* free / refcount-- */
+				dlFreeLibrary(pLib_);
+
+				if(pLib == pLib_)
+				{
+					pHeader = (const struct MACH_HEADER_TYPE*) _dyld_get_image_header(i);
 //@@@ slide = _dyld_get_image_vmaddr_slide(i);
-				break; /* found header */
+					break; /* found header */
+				}
 			}
 		}
 	}
--- a/test/dynload_plain/dynload_plain.c	Tue Dec 29 13:30:59 2020 +0100
+++ b/test/dynload_plain/dynload_plain.c	Wed Jan 20 13:49:43 2021 +0100
@@ -67,6 +67,8 @@
   DLLib* pLib;
   DLSyms* pSyms;
   const char* path = NULL;
+  int cmp_inode = 1;
+
   /* hacky/lazy list of some clib paths per platform - more/others, like version-suffixed ones */
   /* can be specified in Makefile; this avoids trying to write portable directory traversal stuff */
   const char* clibs[] = {
@@ -78,7 +80,7 @@
     "/lib32/libc.so",
     "/lib64/libc.so",
     "/usr/lib/libc.so",
-    "/usr/lib/system/libsystem_c.dylib", /* macos */
+    "/usr/lib/system/libsystem_c.dylib", /* macos - note: not on fs w/ macos >= 11.0.1 */
     "/usr/lib/libc.dylib",
     "/boot/system/lib/libroot.so",       /* Haiku */
     "\\ReactOS\\system32\\msvcrt.dll",   /* ReactOS */
@@ -93,6 +95,15 @@
       path = clibs[i];
       break;
     }
+#if defined(DC__OS_Darwin)
+    /* macos >= 11.0.1 (Big Sur) dylibs might not be on disk but in a sys cache, so dlopen works but not fs checks */
+    else if((pLib = dlLoadLibrary(clibs[i]))) {
+      cmp_inode = 0; /* not dealing with files but dylib sys cache */
+      dlFreeLibrary(pLib);
+      path = clibs[i];
+      break;
+    }
+#endif
   }
 
   if(path) {
@@ -115,14 +126,36 @@
 
       bs = dlGetLibraryPath(pLib, queriedPath, 200);
       if(bs && bs <= 200) {
-        struct stat st0, st1; /* to check if same file */
         int b, bs_;
         printf("path of lib looked up via handle: %s\n", queriedPath);
-        b = (stat(path, &st0) != -1) && (stat(queriedPath, &st1) != -1);
-        printf("lib (inode:%d) and looked up lib (inode:%d) are same: %d\n", b?st0.st_ino:-1, b?st1.st_ino:-1, b && (st0.st_ino == st1.st_ino)); //@@@ on windows, inode numbers returned here are always 0
-        r += b && (st0.st_ino == st1.st_ino); /* compare if same lib using inode */
+
 /*@@@ check if resolved path is absolute*/
 
+#if defined(DC_WINDOWS)
+        /* on windows, inode numbers returned by stat(2) tests below are always 0, so don't use those */
+        cmp_inode = 0;
+#endif
+
+        /* path based check if same lib */
+        if(cmp_inode)
+        {
+          struct stat st0, st1; /* to check if same file */
+          b = (stat(path, &st0) != -1) && (stat(queriedPath, &st1) != -1);
+          printf("lib (inode:%d) and looked up lib (inode:%d) are same: %d\n", b?(int)st0.st_ino:-1, b?(int)st1.st_ino:-1, b && (st0.st_ino == st1.st_ino));
+          r += b && (st0.st_ino == st1.st_ino); /* compare if same lib using inode */
+        }
+        else
+          printf("-- skipping inode based check (doesn't apply to this platform or we are dealing with macos dylib that isn't on fs) --\n");
+
+        /* just load lib with queried path and compare handle */
+        {
+          DLLib* pLib_ = dlLoadLibrary(queriedPath);
+          b = (pLib == pLib_); /* pLib guaranteed to not be NULL, here, so no explicit !pLib_ check */
+          printf("lib (handle:%p) and looked up lib (handle:%p) are same: %d\n", pLib, pLib_, b);
+          r += b;
+          dlFreeLibrary(pLib_); /* dec ref count */
+        }
+
         /* check correct bufsize retval */
         b = (bs == strlen(queriedPath) + 1);
         printf("looked up path's needed buffer size (%d) computed correctly 1/2: %d\n", bs, b);
@@ -245,7 +278,7 @@
   }
 
   /* Check final score of right ones to see if all worked */
-  r = (r == 16);
+  r = (r == 16 + cmp_inode);
   printf("result: dynload_plain: %d\n", r);
   return !r;
 }