release/22.x: [sanitizer_common] [Darwin] Adopt _dyld_get_dyld_header (#182943) - #188913
Conversation
|
@DanBlackwell What do you think about merging this PR to the release branch? |
|
@llvm/pr-subscribers-compiler-rt-sanitizer Author: llvmbot ChangesBackport 2e7d07a Requested by: @ndrewh Full diff: https://github.com/llvm/llvm-project/pull/188913.diff 3 Files Affected:
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp
index 979729f15aa16..93d3929033a86 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp
@@ -176,7 +176,7 @@ void MemoryMappingLayout::Reset() {
// The dyld load address should be unchanged throughout process execution,
// and it is expensive to compute once many libraries have been loaded,
// so cache it here and do not reset.
-static mach_header *dyld_hdr = 0;
+static const mach_header* dyld_hdr = 0;
static const char kDyldPath[] = "/usr/lib/dyld";
static const int kDyldImageIdx = -1;
@@ -244,14 +244,18 @@ extern intptr_t _dyld_get_image_slide(const struct mach_header* mh);
extern int dyld_shared_cache_iterate_text(
const uuid_t cacheUuid,
void (^callback)(const dyld_shared_cache_dylib_text_info *info));
+SANITIZER_WEAK_IMPORT const struct mach_header* _dyld_get_dyld_header(void);
} // extern "C"
-static mach_header *GetDyldImageHeaderViaSharedCache() {
+static const mach_header* GetDyldImageHeaderViaSharedCache() {
uuid_t uuid;
bool hasCache = _dyld_get_shared_cache_uuid(uuid);
if (!hasCache)
return nullptr;
+ if (&_dyld_get_dyld_header != nullptr)
+ return _dyld_get_dyld_header();
+
size_t cacheLength;
__block uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength);
CHECK(cacheStart && cacheLength);
diff --git a/compiler-rt/lib/sanitizer_common/weak_symbols.txt b/compiler-rt/lib/sanitizer_common/weak_symbols.txt
index 77e7b5d9f702e..600ab8a7c649c 100644
--- a/compiler-rt/lib/sanitizer_common/weak_symbols.txt
+++ b/compiler-rt/lib/sanitizer_common/weak_symbols.txt
@@ -10,3 +10,4 @@ ___sanitizer_symbolize_demangle
___sanitizer_symbolize_flush
___sanitizer_symbolize_set_demangle
___sanitizer_symbolize_set_inline_frames
+__dyld_get_dyld_header
diff --git a/compiler-rt/lib/tsan/go/buildgo.sh b/compiler-rt/lib/tsan/go/buildgo.sh
index d9e56402ad48f..1340071819fcb 100755
--- a/compiler-rt/lib/tsan/go/buildgo.sh
+++ b/compiler-rt/lib/tsan/go/buildgo.sh
@@ -165,7 +165,7 @@ elif [ "$GOOS" = "netbsd" ]; then
"
elif [ "$GOOS" = "darwin" ]; then
OSCFLAGS="-fPIC -Wno-unused-const-variable -Wno-unknown-warning-option -mmacosx-version-min=10.7"
- OSLDFLAGS="-lpthread -fPIC -fpie -mmacosx-version-min=10.7"
+ OSLDFLAGS="-lpthread -fPIC -fpie -mmacosx-version-min=10.7 -Wl,-U,__dyld_get_dyld_header"
SRCS="
$SRCS
../rtl/tsan_platform_mac.cpp
|
|
I think we should cherry-pick this to make sure that clang 22 supports ASAN on macOS 26.4. |
|
Is this a regression? If so, when was the regression introduced? |
This is a regression caused by an OS change in macOS 26.4; any runtimes without this change will not run on macOS 26.4+. Any runtimes built with this patch can run on both pre- and post-macOS 26.4 OSes. |
|
@DanBlackwell sounds reasonable, please accept if you're happy. Also adding sanitizer maintainer for visibility. |
(cherry picked from commit 2e7d07a)
…macOS (#34508) ## Problem `bun bd` aborts at startup on macOS releases older than 26.4 (seen on 15.6.1, Homebrew llvm@21): ``` AddressSanitizer: CHECK failed: sanitizer_procmaps_mac.cpp:214 "((res)) == ((0))" (0xffffffffffffffff, 0x0) <empty stack> Abort trap: 6 ``` The post-link `bun-debug --revision` smoke test dies with this, so the debug build never completes. Workaround has been `bun run build --asan=off`. ## Cause `scripts/build/shims/asan-dyld-shim.c` interposes `dyld_shared_cache_iterate_text` to keep ASAN init from deadlocking on macOS 26.4 (llvm/llvm-project#182943). It looks up the private `_dyld_get_dyld_header` via `dlsym` to synthesize the one cache entry ASAN needs. Apple's own `dyld_priv.h` marks that symbol ["Added in macOS/iOS 26.4"](https://github.com/apple-oss-distributions/dyld/blob/dyld-1376.6/include/mach-o/dyld_priv.h) (first appears in dyld-1376.6; absent from dyld-1340 and every earlier tag). On any macOS < 26.4, `dlsym` returns `NULL`, the shim returns `-1`, and compiler-rt's `CHECK_EQ(res, 0)` aborts. The shim is linked into every `cfg.darwin && cfg.asan` build with no runtime check, so it breaks every debug build on macOS hosts that predate 26.4. ## Fix When the shim can't synthesize the entry (`dlsym` returned `NULL`, or no shared cache), delegate to the real `dyld_shared_cache_iterate_text` instead of returning `-1`. The deadlock and the getter were introduced together in 26.4, so "getter absent" is exactly "real iterate is safe". This is the same shape as the upstream compiler-rt fix (llvm/llvm-project#188913): weak-import `_dyld_get_dyld_header`, use it when present, otherwise fall through to the existing iterate path. Calling the original by name from inside the interposer does not recurse. dyld explicitly adds an identity-mapping tuple for the defining image; from [DyldRuntimeState.cpp](https://github.com/apple-oss-distributions/dyld/blob/dyld-1378/dyld/DyldRuntimeState.cpp): > `// now add specific interpose so that the generic is not applied to the interposing dylib, so it can call through to old impl` (This is also how Apple's own `DYLD_INTERPOSE` wrapper example in [dyld-interposing.h](https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/dyld-interposing.h) works.) ## Verification Shim is only compiled for `darwin && asan` (no CI lane exists for that combination); verified the change compiles clean with `-Wall -Wextra -fblocks` against stubbed darwin headers. Behaviour on 26.4+ is unchanged: `dlsym` finds the symbol there and the same synthesize path runs as before. ## Why this is the right fix The alternative is gating shim emission on host macOS version in `shims.ts`, but the runtime check is strictly better: one binary works on both, and it matches upstream exactly. The shim is temporary regardless (self-obsoletes via `workarounds.ts` once LLVM 22.1.4+ is the floor; #34299 deletes it as part of the LLVM 22 bump), so the goal here is just to stop breaking pre-26.4 macOS until that lands. <!-- robobun:evidence:begin --> --- **no test proof** · iteration 0 · build/CI scripts only; test-proof not applicable <!-- robobun:evidence:end -->
Conflict: scripts/build/shims/asan-dyld-shim.c was modified on main and deleted on this branch. Keep the delete: LLVM 22.1.8 carries the upstream fix (llvm/llvm-project#188913).
…macOS (#34508)
## Problem
`bun bd` aborts at startup on macOS releases older than 26.4 (seen on
15.6.1, Homebrew llvm@21):
```
AddressSanitizer: CHECK failed: sanitizer_procmaps_mac.cpp:214 "((res)) == ((0))" (0xffffffffffffffff, 0x0)
<empty stack>
Abort trap: 6
```
The post-link `bun-debug --revision` smoke test dies with this, so the
debug build never completes. Workaround has been `bun run build
--asan=off`.
## Cause
`scripts/build/shims/asan-dyld-shim.c` interposes
`dyld_shared_cache_iterate_text` to keep ASAN init from deadlocking on
macOS 26.4 (llvm/llvm-project#182943). It looks up the private
`_dyld_get_dyld_header` via `dlsym` to synthesize the one cache entry
ASAN needs.
Apple's own `dyld_priv.h` marks that symbol ["Added in macOS/iOS
26.4"](https://github.com/apple-oss-distributions/dyld/blob/dyld-1376.6/include/mach-o/dyld_priv.h)
(first appears in dyld-1376.6; absent from dyld-1340 and every earlier
tag). On any macOS < 26.4, `dlsym` returns `NULL`, the shim returns
`-1`, and compiler-rt's `CHECK_EQ(res, 0)` aborts.
The shim is linked into every `cfg.darwin && cfg.asan` build with no
runtime check, so it breaks every debug build on macOS hosts that
predate 26.4.
## Fix
When the shim can't synthesize the entry (`dlsym` returned `NULL`, or no
shared cache), delegate to the real `dyld_shared_cache_iterate_text`
instead of returning `-1`. The deadlock and the getter were introduced
together in 26.4, so "getter absent" is exactly "real iterate is safe".
This is the same shape as the upstream compiler-rt fix
(llvm/llvm-project#188913): weak-import `_dyld_get_dyld_header`, use it
when present, otherwise fall through to the existing iterate path.
Calling the original by name from inside the interposer does not
recurse. dyld explicitly adds an identity-mapping tuple for the defining
image; from
[DyldRuntimeState.cpp](https://github.com/apple-oss-distributions/dyld/blob/dyld-1378/dyld/DyldRuntimeState.cpp):
> `// now add specific interpose so that the generic is not applied to
the interposing dylib, so it can call through to old impl`
(This is also how Apple's own `DYLD_INTERPOSE` wrapper example in
[dyld-interposing.h](https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/dyld-interposing.h)
works.)
## Verification
Shim is only compiled for `darwin && asan` (no CI lane exists for that
combination); verified the change compiles clean with `-Wall -Wextra
-fblocks` against stubbed darwin headers. Behaviour on 26.4+ is
unchanged: `dlsym` finds the symbol there and the same synthesize path
runs as before.
## Why this is the right fix
The alternative is gating shim emission on host macOS version in
`shims.ts`, but the runtime check is strictly better: one binary works
on both, and it matches upstream exactly. The shim is temporary
regardless (self-obsoletes via `workarounds.ts` once LLVM 22.1.4+ is the
floor; #34299 deletes it as part of the LLVM 22 bump), so the goal here
is just to stop breaking pre-26.4 macOS until that lands.
<!-- robobun:evidence:begin -->
---
**no test proof** · iteration 0 · build/CI scripts only; test-proof not
applicable
<!-- robobun:evidence:end -->
Backport 2e7d07a
Requested by: @ndrewh