Tested on x86_64-darwin17,18,19,20,21,23,24, powerpc64le-linux
pushed to trunk, thanks
Iain
--- 8< ---
This replaces the Darwin-specific changes previously applied
in b53f7de3e6205f76a794e159a282193e2afaad16 and addresses the
FIXME there.
1. The upstream sources do not, in general, support the range
of Darwin versions covered by GCC.
In order to support versions back to Darwin17, at least we
provide definitions for missing macro values and ensure that
headers are only conditionally included where they apply.
2. GCC does not support the clang __builtin_os_log_format and
therefore must fall back to older reporting methods.
3. Finally, we address a FIXME (for missing Blocks support)
used implement the search for dyld on macOS >= 13 with the
dyld_shared_cache_iterate_text() interface which requires an
(Apple) Block closure as a parameter.
If the compiler supports blocks (__BLOCKS__ is defined) then we
use the upstream implementation. If not, then we synthesize the
equivalent code-gen manually.
---
.../sanitizer_common/sanitizer_mac.cpp | 28 +++-
libsanitizer/sanitizer_common/sanitizer_mac.h | 20 +++
.../sanitizer_procmaps_mac.cpp | 129 ++++++++++++++++--
3 files changed, 163 insertions(+), 14 deletions(-)
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cpp
b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
index a6f75717372..ea8b3c7e522 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mac.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
@@ -71,7 +71,15 @@ extern char ***_NSGetArgv(void);
# include <mach/mach_time.h>
# include <mach/vm_statistics.h>
# include <malloc/malloc.h>
-# include <os/log.h>
+# if defined(__has_builtin) && __has_builtin(__builtin_os_log_format)
+# include <os/log.h>
+# else
+ /* Without support for __builtin_os_log_format, fall back to the older
+ method. */
+# define OS_LOG_DEFAULT 0
+# define os_log_error(A,B,C) \
+ asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", (C))
+# endif
# include <pthread.h>
# include <pthread/introspection.h>
# include <sched.h>
@@ -869,19 +877,23 @@ void LogFullErrorReport(const char *buffer) {
// When logging with os_log_error this will make it into the crash log.
if (internal_strncmp(SanitizerToolName, "AddressSanitizer",
sizeof("AddressSanitizer") - 1) == 0)
- SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Address Sanitizer reported a failure.");
+ SANITIZER_OS_LOG(OS_LOG_DEFAULT, "%{public}s",
+ "Address Sanitizer reported a failure.");
else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer",
sizeof("UndefinedBehaviorSanitizer") - 1) == 0)
- SANITIZER_OS_LOG(OS_LOG_DEFAULT,
+ SANITIZER_OS_LOG(OS_LOG_DEFAULT, "%{public}s",
"Undefined Behavior Sanitizer reported a failure.");
else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer",
sizeof("ThreadSanitizer") - 1) == 0)
- SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Thread Sanitizer reported a failure.");
+ SANITIZER_OS_LOG(OS_LOG_DEFAULT, "%{public}s",
+ "Thread Sanitizer reported a failure.");
else
- SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Sanitizer tool reported a failure.");
+ SANITIZER_OS_LOG(OS_LOG_DEFAULT, "%{public}s",
+ "Sanitizer tool reported a failure.");
if (common_flags()->log_to_syslog)
- SANITIZER_OS_LOG(OS_LOG_DEFAULT, "Consult syslog for more information.");
+ SANITIZER_OS_LOG(OS_LOG_DEFAULT, "%{public}s",
+ "Consult syslog for more information.");
// Log to syslog.
// The logging on OS X may call pthread_create so we need the threading
@@ -952,6 +964,10 @@ void SignalContext::InitPcSpBp() {
GetPcSpBp(context, &pc, &sp, &bp);
}
+#ifndef KERN_DENIED
+#define KERN_DENIED 53
+#endif
+
// ASan/TSan use mmap in a way that creates “deallocation gaps” which triggers
// EXC_GUARD exceptions on macOS 10.15+ (XNU 19.0+).
static void DisableMmapExcGuardExceptions() {
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.h
b/libsanitizer/sanitizer_common/sanitizer_mac.h
index b0e4ac7f407..d4a36137be0 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mac.h
+++ b/libsanitizer/sanitizer_common/sanitizer_mac.h
@@ -14,6 +14,26 @@
#include "sanitizer_common.h"
#include "sanitizer_platform.h"
+
+/* TARGET_OS_OSX is not present in SDKs before Darwin16 (macOS 10.12) use
+ TARGET_OS_MAC (we have no support for iOS in any form for these versions,
+ so there's no ambiguity). */
+#if !defined(TARGET_OS_OSX) && TARGET_OS_MAC
+# define TARGET_OS_OSX 1
+#endif
+
+/* Other TARGET_OS_xxx are not present on earlier versions, define them to
+ 0 (we have no support for them; they are not valid targets anyway). */
+#ifndef TARGET_OS_IOS
+#define TARGET_OS_IOS 0
+#endif
+#ifndef TARGET_OS_TV
+#define TARGET_OS_TV 0
+#endif
+#ifndef TARGET_OS_WATCH
+#define TARGET_OS_WATCH 0
+#endif
+
#if SANITIZER_APPLE
#include "sanitizer_posix.h"
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
index f40fba6bf71..ca5c71ae966 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
@@ -239,19 +239,18 @@ typedef struct dyld_shared_cache_dylib_text_info
extern bool _dyld_get_shared_cache_uuid(uuid_t uuid);
extern const void *_dyld_get_shared_cache_range(size_t *length);
extern intptr_t _dyld_get_image_slide(const struct mach_header* mh);
+} // extern "C"
+
+#ifdef __BLOCKS__
+extern "C" {
extern int dyld_shared_cache_iterate_text(
const uuid_t cacheUuid,
void (^callback)(const dyld_shared_cache_dylib_text_info *info));
} // extern "C"
-static mach_header *GetDyldImageHeaderViaSharedCache() {
- uuid_t uuid;
- bool hasCache = _dyld_get_shared_cache_uuid(uuid);
- if (!hasCache)
- return nullptr;
-
+static mach_header *GetDyldImageHeaderViaSharedCache(uuid_t uuid) {
size_t cacheLength;
- __block uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength);
+ const uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength);
CHECK(cacheStart && cacheLength);
__block mach_header *dyldHdr = nullptr;
@@ -268,12 +267,126 @@ static mach_header *GetDyldImageHeaderViaSharedCache() {
return dyldHdr;
}
+#else
+
+/* Here we implement a manual emulation of the Blocks closure and callback
+ that is needed by dyld_shared_cache_iterate_text (). In the compiler-
+ generated code, the [local] names are mangled differently, but that
+ should not matter to the function (since all the entities are TU-local). */
+
+extern "C" {
+/* Some descriptions of the blocks interfaces/runtime that we need. */
+extern void *_NSConcreteStackBlock;
+extern void _Block_object_assign(void *, void *, int);
+extern void _Block_object_dispose(void *, int);
+enum {
+ BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)),
block, ... */
+ BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */
+ BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the __block
variable */
+ BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy
helpers */
+ BLOCK_BYREF_CALLER = 128 /* called from __block (byref) copy/dispose
support routines. */
+};
+
+/* 1. __block mach_header *dyldHdr; Uses this on-stack object. */
+typedef struct __block_byref_dyldHdr {
+ void *__isa;
+ struct __block_byref_dyldHdr *forwarding;
+ int flags; // 1<<25 iff we need copy helper;
+ int size;
+ mach_header *dyldHdr_cp;
+} dyldHdr_type;
+
+/* The closure, support functions and the actuall callback code. */
+/* 1. closure descriptor. A constant instance of this will be created. */
+struct Block_descriptor_cb {
+ unsigned long int reserved; // NULL
+ unsigned long int size; // sizeof(struct Block_literal_cb)
+ // optional helper functions
+ void (*copy_helper)(struct Block_literal_cb *dst, struct Block_literal_cb
*src); // IFF (1<<25)
+ void (*dispose_helper)(struct Block_literal_cb *src); // IFF
(1<<25)
+ // required ABI.2010.3.16
+ const char *signature; // IFF (1<<30)
+ void *no_idea; // not documented in the current ABI
+};
+
+/* 2. This is the closure object. In this case, it will be allocated on the
+ stack and does not need to be moved (since the closure never escapes
+ from its enclosing scope). However, the infrastructure still provides
+ support for moving it to the heap if required. */
+typedef struct Block_literal_cb {
+ void *__isa;
+ int flags;
+ int reserved;
+ void (*invoke) (Block_literal_cb*, const dyld_shared_cache_dylib_text_info
*info);
+ const struct Block_descriptor_cb *descriptor;
+ dyldHdr_type *h_holder;
+ uptr cache_start;
+} CallbackBlk;
+
+/* 3. Supporting functions to allow for the closure to be copied to the heap on
+ demand. */
+static void
+__block_copy_cb (struct Block_literal_cb *dst, struct Block_literal_cb *src)
+{
+ //_Block_byref_assign_copy(&dst->captured_i, src->captured_i);
+ _Block_object_assign(&dst->h_holder, src->h_holder, BLOCK_FIELD_IS_BYREF);
+}
+
+static void
+__block_dispose_cb (struct Block_literal_cb *src) {
+ //_Block_byref_release(src->captured_i);
+ _Block_object_dispose(src->h_holder, BLOCK_FIELD_IS_BYREF);
+}
+
+/* 4. Here is the actual code implementing the callback. */
+static void
+__block_invoke_cb (struct Block_literal_cb *_block,
+ const dyld_shared_cache_dylib_text_info *info)
+{
+ mach_header *hdr = (mach_header *)(_block->cache_start +
info->textSegmentOffset);
+ if (IsDyldHdr(hdr))
+ _block->h_holder->forwarding->dyldHdr_cp = hdr;
+}
+
+/* 6. The constant instance of the descriptor mentioned in 1 above. */
+static const struct Block_descriptor_cb cb_descr = {
+ 0, sizeof (struct Block_literal_cb), __block_copy_cb, __block_dispose_cb,
+ "v16@?0r^{dyld_shared_cache_dylib_text_info=QQQ[16C]*Q}8", nullptr
+};
+
+/* Declare dyld_shared_cache_iterate_text () as taking a regular pointer to
+ the closure; we cannot use the ^ syntax yet in GCC. */
+extern int dyld_shared_cache_iterate_text(const uuid_t cacheUuid,
CallbackBlk*);
+} // extern "C"
+
+/* The non-blocks version of GetDyldImageHeaderViaSharedCache (). */
+static mach_header *GetDyldImageHeaderViaSharedCache(uuid_t uuid) {
+ size_t cacheLength;
+ const uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength);
+ CHECK(cacheStart && cacheLength);
+ /* __block mach_header *dyldHdr = nullptr; */
+ dyldHdr_type dyldHdr
+ = { nullptr, &dyldHdr, 0, sizeof (struct __block_byref_dyldHdr), nullptr };
+ /* Callback cb = ^(const dyld_shared_cache_dylib_text_info *info... */
+ CallbackBlk cb
+ = { _NSConcreteStackBlock, 0x42000000, 0, __block_invoke_cb,
+ &cb_descr, &dyldHdr, cacheStart };
+ int res = dyld_shared_cache_iterate_text ( uuid, &cb );
+ CHECK_EQ(res, 0);
+ return dyldHdr.forwarding->dyldHdr_cp;
+}
+#endif
+
const mach_header *get_dyld_hdr() {
if (!dyld_hdr) {
// On macOS 13+, dyld itself has moved into the shared cache. Looking it
up
// via vm_region_recurse_64() causes spins/hangs/crashes.
if (GetMacosAlignedVersion() >= MacosVersion(13, 0)) {
- dyld_hdr = GetDyldImageHeaderViaSharedCache();
+ uuid_t uuid;
+ if (!_dyld_get_shared_cache_uuid(uuid))
+ VReport(1, "Failed get the shared cache on macOS 13+\n");
+ else
+ dyld_hdr = GetDyldImageHeaderViaSharedCache(uuid);
if (!dyld_hdr) {
VReport(1,
"Failed to lookup the dyld image header in the shared cache on
"
--
2.39.5 (Apple Git-154)