[compiler-rt] [compiler-rt] [sanitizer_common] Fix SIGSEGV in ForEachMappedRegion for DSOs with custom image base (PR #209576)

Mike Kruskal via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 10:53:25 PDT 2026


https://github.com/mkruskal-google created https://github.com/llvm/llvm-project/pull/209576

Attempt 2 at #206299, fixing a linkage issue with gotsan on older versions of glibc.  Rather than forcing linkage of libdl (which may not be safe with go), this just disables the dladdr usage under go builds.  This bug only affected MSAN and DFSAN anyway, and the code should be unused by TSAN.

`ForEachMappedRegion` processes dynamic linker map entries to track loaded segments. However, it assumes map->l_addr is the address of the ELF header. For DSOs linked with a custom preferred image base offset (e.g. -Wl,--image-base=0x4000000), `map->l_addr` contains the relocation bias: `map->l_addr = actual_load_address - preferred_base`

In this case, map->l_addr points below the first loaded segment in unmapped or PROT_NONE memory. Doing a read dereference at this address triggers a SIGSEGV. Add a call to dladdr() on the dynamic section pointer map->l_ld to obtain the true ELF header base address.

Likely fixes https://github.com/llvm/llvm-project/issues/84482 - which looks like the exact same stacktrace I was debugging that led me to this fix

Also looks it may have shown up in https://github.com/llvm/llvm-project/issues/21068 - my case was also flaky, and it only shows up if you build the so with custom base address

Assisted-by: Gemini

>From b2bffe1c0b320abeeb7091f838f7b58e9f6e5197 Mon Sep 17 00:00:00 2001
From: Mike Kruskal <mkruskal at google.com>
Date: Sat, 27 Jun 2026 19:45:01 -0700
Subject: [PATCH 01/12] Add a testcase reproducing #84482 and #21068

---
 .../sanitizer_common/TestCases/Linux/dlopen_image_base.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/dlopen_image_base.c b/compiler-rt/test/sanitizer_common/TestCases/Linux/dlopen_image_base.c
index d4f3ad704388f..46d3544dc9380 100644
--- a/compiler-rt/test/sanitizer_common/TestCases/Linux/dlopen_image_base.c
+++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/dlopen_image_base.c
@@ -6,7 +6,6 @@
 // REQUIRES: glibc
 
 // Regression test for #84482 and #21068
-// XFAIL: msan, dfsan
 
 #ifndef BUILD_SO
 #  define _GNU_SOURCE
@@ -31,11 +30,7 @@ int main(int argc, char *argv[]) {
   dlinfo(handle, RTLD_DI_LINKMAP, &map);
   if (map) {
     printf("DSO link_map name: %s\n", map->l_name);
-    printf("DSO link_map l_addr: %p\n", (void *)map->l_addr);
-    int pipefd[2];
-    bool readable = false;
-    if (pipe(pipefd) == 0) {
-      if (write(pipefd[1], (void *)map->l_addr, 1) == 1) {
+
         readable = true;
       }
       close(pipefd[0]);
@@ -52,6 +47,6 @@ int main(int argc, char *argv[]) {
   return 0;
 }
 #else // BUILD_SO
-#  include <stdio.h>
+
 void fn() { printf("DSO function called successfully\n"); }
 #endif

>From e55ac51518139f823eb4c7c280b61fc558b967a7 Mon Sep 17 00:00:00 2001
From: Mike Kruskal <mkruskal at google.com>
Date: Wed, 8 Jul 2026 18:05:52 -0700
Subject: [PATCH 02/12] Fix formatting

---
 .../test/sanitizer_common/TestCases/Linux/dlopen_image_base.c   | 2 --
 1 file changed, 2 deletions(-)

diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/dlopen_image_base.c b/compiler-rt/test/sanitizer_common/TestCases/Linux/dlopen_image_base.c
index 46d3544dc9380..56ceef3eba2f9 100644
--- a/compiler-rt/test/sanitizer_common/TestCases/Linux/dlopen_image_base.c
+++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/dlopen_image_base.c
@@ -30,7 +30,6 @@ int main(int argc, char *argv[]) {
   dlinfo(handle, RTLD_DI_LINKMAP, &map);
   if (map) {
     printf("DSO link_map name: %s\n", map->l_name);
-
         readable = true;
       }
       close(pipefd[0]);
@@ -47,6 +46,5 @@ int main(int argc, char *argv[]) {
   return 0;
 }
 #else // BUILD_SO
-
 void fn() { printf("DSO function called successfully\n"); }
 #endif

>From beba2e2e0624cc0d29df8badf7bc62f7cb861cab Mon Sep 17 00:00:00 2001
From: Mike Kruskal <mkruskal at google.com>
Date: Sat, 27 Jun 2026 19:45:01 -0700
Subject: [PATCH 03/12] Fix SIGSEGV in ForEachMappedRegion for DSOs with custom
 image base

---
 .../lib/sanitizer_common/sanitizer_linux.cpp  |  4 ++
 compiler-rt/test/msan/dlopen_image_base.c     | 53 +++++++++++++++++++
 2 files changed, 57 insertions(+)
 create mode 100644 compiler-rt/test/msan/dlopen_image_base.c

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
index 6f0259f31dbf5..2f21a8d992e13 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
@@ -1404,6 +1404,10 @@ void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
   typedef ElfW(Ehdr) Elf_Ehdr;
 #    endif  // !SANITIZER_FREEBSD
   char *base = (char *)map->l_addr;
+  Dl_info info;
+  if (dladdr((void *)map->l_ld, &info) && info.dli_fbase) {
+    base = (char *)info.dli_fbase;
+  }
   Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
   char *phdrs = base + ehdr->e_phoff;
   char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;
diff --git a/compiler-rt/test/msan/dlopen_image_base.c b/compiler-rt/test/msan/dlopen_image_base.c
new file mode 100644
index 0000000000000..07121b02501e5
--- /dev/null
+++ b/compiler-rt/test/msan/dlopen_image_base.c
@@ -0,0 +1,53 @@
+/* RUN: %clang_msan -g %s -o %t
+   RUN: %clang_msan -g %s -DBUILD_SO -fPIC -o %t-so.so -shared -Wl,--image-base=0x4000000
+   RUN: %run %t 2>&1
+   REQUIRES: glibc
+*/
+
+#ifndef BUILD_SO
+#define _GNU_SOURCE
+#include <assert.h>
+#include <dlfcn.h>
+#include <link.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[]) {
+  char path[4096];
+  snprintf(path, sizeof(path), "%s-so.so", argv[0]);
+
+  void *handle = dlopen(path, RTLD_LAZY);
+  if (!handle) {
+    fprintf(stderr, "dlopen failed: %s\n", dlerror());
+    return 1;
+  }
+
+  struct link_map *map = NULL;
+  dlinfo(handle, RTLD_DI_LINKMAP, &map);
+  if (map) {
+    printf("DSO link_map name: %s\n", map->l_name);
+    printf("DSO link_map l_addr: %p\n", (void*)map->l_addr);
+    int pipefd[2];
+    bool readable = false;
+    if (pipe(pipefd) == 0) {
+      if (write(pipefd[1], (void*)map->l_addr, 1) == 1) {
+        readable = true;
+      }
+      close(pipefd[0]);
+      close(pipefd[1]);
+    }
+    printf("DSO l_addr readable: %d\n", readable);
+  }
+
+  void (*fn)() = (void (*)())dlsym(handle, "fn");
+  assert(fn != NULL);
+  fn();
+
+  dlclose(handle);
+  return 0;
+}
+#else // BUILD_SO
+#include <stdio.h>
+void fn() { printf("DSO function called successfully\n"); }
+#endif

>From ed118806597fead68d62c19f76b5f906394ab24e Mon Sep 17 00:00:00 2001
From: Mike Kruskal <mkruskal at google.com>
Date: Wed, 8 Jul 2026 17:48:08 -0700
Subject: [PATCH 04/12] Response to review comments

---
 .../lib/sanitizer_common/sanitizer_linux.cpp  |  2 +
 compiler-rt/test/msan/dlopen_image_base.c     | 53 -------------------
 2 files changed, 2 insertions(+), 53 deletions(-)
 delete mode 100644 compiler-rt/test/msan/dlopen_image_base.c

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
index 2f21a8d992e13..20e93c36338f6 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
@@ -1404,10 +1404,12 @@ void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
   typedef ElfW(Ehdr) Elf_Ehdr;
 #    endif  // !SANITIZER_FREEBSD
   char *base = (char *)map->l_addr;
+#    if SANITIZER_GLIBC
   Dl_info info;
   if (dladdr((void *)map->l_ld, &info) && info.dli_fbase) {
     base = (char *)info.dli_fbase;
   }
+#    endif  // SANITIZER_GLIBC
   Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
   char *phdrs = base + ehdr->e_phoff;
   char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;
diff --git a/compiler-rt/test/msan/dlopen_image_base.c b/compiler-rt/test/msan/dlopen_image_base.c
deleted file mode 100644
index 07121b02501e5..0000000000000
--- a/compiler-rt/test/msan/dlopen_image_base.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/* RUN: %clang_msan -g %s -o %t
-   RUN: %clang_msan -g %s -DBUILD_SO -fPIC -o %t-so.so -shared -Wl,--image-base=0x4000000
-   RUN: %run %t 2>&1
-   REQUIRES: glibc
-*/
-
-#ifndef BUILD_SO
-#define _GNU_SOURCE
-#include <assert.h>
-#include <dlfcn.h>
-#include <link.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <unistd.h>
-
-int main(int argc, char *argv[]) {
-  char path[4096];
-  snprintf(path, sizeof(path), "%s-so.so", argv[0]);
-
-  void *handle = dlopen(path, RTLD_LAZY);
-  if (!handle) {
-    fprintf(stderr, "dlopen failed: %s\n", dlerror());
-    return 1;
-  }
-
-  struct link_map *map = NULL;
-  dlinfo(handle, RTLD_DI_LINKMAP, &map);
-  if (map) {
-    printf("DSO link_map name: %s\n", map->l_name);
-    printf("DSO link_map l_addr: %p\n", (void*)map->l_addr);
-    int pipefd[2];
-    bool readable = false;
-    if (pipe(pipefd) == 0) {
-      if (write(pipefd[1], (void*)map->l_addr, 1) == 1) {
-        readable = true;
-      }
-      close(pipefd[0]);
-      close(pipefd[1]);
-    }
-    printf("DSO l_addr readable: %d\n", readable);
-  }
-
-  void (*fn)() = (void (*)())dlsym(handle, "fn");
-  assert(fn != NULL);
-  fn();
-
-  dlclose(handle);
-  return 0;
-}
-#else // BUILD_SO
-#include <stdio.h>
-void fn() { printf("DSO function called successfully\n"); }
-#endif

>From 85524a688977da9758607840e43dd8f3a461140b Mon Sep 17 00:00:00 2001
From: Mike Kruskal <mkruskal at google.com>
Date: Wed, 8 Jul 2026 20:24:36 -0700
Subject: [PATCH 05/12] Move ForEachMappedRegion to libcdep

---
 .../lib/sanitizer_common/sanitizer_linux.cpp  | 47 -------------------
 .../sanitizer_linux_libcdep.cpp               | 47 +++++++++++++++++++
 2 files changed, 47 insertions(+), 47 deletions(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
index 20e93c36338f6..ceff1717af7d7 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
@@ -1395,53 +1395,6 @@ bool LibraryNameIs(const char *full_name, const char *base_name) {
   return (name[base_name_length] == '-' || name[base_name_length] == '.');
 }
 
-#  if !SANITIZER_ANDROID && !SANITIZER_HAIKU
-// Call cb for each region mapped by map.
-void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
-  CHECK_NE(map, nullptr);
-#    if !SANITIZER_FREEBSD && !SANITIZER_HAIKU
-  typedef ElfW(Phdr) Elf_Phdr;
-  typedef ElfW(Ehdr) Elf_Ehdr;
-#    endif  // !SANITIZER_FREEBSD
-  char *base = (char *)map->l_addr;
-#    if SANITIZER_GLIBC
-  Dl_info info;
-  if (dladdr((void *)map->l_ld, &info) && info.dli_fbase) {
-    base = (char *)info.dli_fbase;
-  }
-#    endif  // SANITIZER_GLIBC
-  Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
-  char *phdrs = base + ehdr->e_phoff;
-  char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;
-
-  // Find the segment with the minimum base so we can "relocate" the p_vaddr
-  // fields.  Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC
-  // objects have a non-zero base.
-  uptr preferred_base = (uptr)-1;
-  for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
-    Elf_Phdr *phdr = (Elf_Phdr *)iter;
-    if (phdr->p_type == PT_LOAD && preferred_base > (uptr)phdr->p_vaddr)
-      preferred_base = (uptr)phdr->p_vaddr;
-  }
-
-  // Compute the delta from the real base to get a relocation delta.
-  sptr delta = (uptr)base - preferred_base;
-  // Now we can figure out what the loader really mapped.
-  for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
-    Elf_Phdr *phdr = (Elf_Phdr *)iter;
-    if (phdr->p_type == PT_LOAD) {
-      uptr seg_start = phdr->p_vaddr + delta;
-      uptr seg_end = seg_start + phdr->p_memsz;
-      // None of these values are aligned.  We consider the ragged edges of the
-      // load command as defined, since they are mapped from the file.
-      seg_start = RoundDownTo(seg_start, GetPageSizeCached());
-      seg_end = RoundUpTo(seg_end, GetPageSizeCached());
-      cb((void *)seg_start, seg_end - seg_start);
-    }
-  }
-}
-#  endif
-
 #  if SANITIZER_LINUX
 #    if defined(__x86_64__)
 // We cannot use glibc's clone wrapper, because it messes with the child
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp
index 2c78522a0fceb..f46705d3c8c9b 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp
@@ -1094,6 +1094,53 @@ void InitializePlatformCommonFlags(CommonFlags *cf) {
 #  endif
 }
 
+#  if !SANITIZER_ANDROID && !SANITIZER_HAIKU
+// Call cb for each region mapped by map.
+void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
+  CHECK_NE(map, nullptr);
+#    if !SANITIZER_FREEBSD && !SANITIZER_HAIKU
+  typedef ElfW(Phdr) Elf_Phdr;
+  typedef ElfW(Ehdr) Elf_Ehdr;
+#    endif  // !SANITIZER_FREEBSD
+  char *base = (char *)map->l_addr;
+#    if SANITIZER_GLIBC
+  Dl_info info;
+  if (dladdr((void *)map->l_ld, &info) && info.dli_fbase) {
+    base = (char *)info.dli_fbase;
+  }
+#    endif  // SANITIZER_GLIBC
+  Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
+  char *phdrs = base + ehdr->e_phoff;
+  char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;
+
+  // Find the segment with the minimum base so we can "relocate" the p_vaddr
+  // fields.  Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC
+  // objects have a non-zero base.
+  uptr preferred_base = (uptr)-1;
+  for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
+    Elf_Phdr *phdr = (Elf_Phdr *)iter;
+    if (phdr->p_type == PT_LOAD && preferred_base > (uptr)phdr->p_vaddr)
+      preferred_base = (uptr)phdr->p_vaddr;
+  }
+
+  // Compute the delta from the real base to get a relocation delta.
+  sptr delta = (uptr)base - preferred_base;
+  // Now we can figure out what the loader really mapped.
+  for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
+    Elf_Phdr *phdr = (Elf_Phdr *)iter;
+    if (phdr->p_type == PT_LOAD) {
+      uptr seg_start = phdr->p_vaddr + delta;
+      uptr seg_end = seg_start + phdr->p_memsz;
+      // None of these values are aligned.  We consider the ragged edges of the
+      // load command as defined, since they are mapped from the file.
+      seg_start = RoundDownTo(seg_start, GetPageSizeCached());
+      seg_end = RoundUpTo(seg_end, GetPageSizeCached());
+      cb((void *)seg_start, seg_end - seg_start);
+    }
+  }
+}
+#  endif
+
 }  // namespace __sanitizer
 
 #endif

>From fa85b0f27fcb7079512e5ce0da2bc45dde3ada1b Mon Sep 17 00:00:00 2001
From: Mike Kruskal <mkruskal at google.com>
Date: Fri, 10 Jul 2026 16:11:22 -0700
Subject: [PATCH 06/12] Move to sanitizer_dl

---
 .../sanitizer_common_nolibc.cpp               |  2 +
 .../lib/sanitizer_common/sanitizer_dl.cpp     | 10 ++++
 .../lib/sanitizer_common/sanitizer_dl.h       |  4 ++
 .../lib/sanitizer_common/sanitizer_linux.cpp  | 42 +++++++++++++++++
 .../sanitizer_linux_libcdep.cpp               | 47 -------------------
 compiler-rt/lib/tsan/go/buildgo.sh            |  3 ++
 6 files changed, 61 insertions(+), 47 deletions(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp
index e49285f22dff9..92f87625e21a5 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_nolibc.cpp
@@ -34,4 +34,6 @@ void ListOfModules::init() {}
 void InitializePlatformCommonFlags(CommonFlags *cf) {}
 #endif
 
+char* DladdrElfHeaderBase(void* ld, char* addr) { return addr; }
+
 }  // namespace __sanitizer
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp
index e957d529c2fe1..8be66f9bb5fd9 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp
@@ -34,4 +34,14 @@ const char *DladdrSelfFName(void) {
   return nullptr;
 }
 
+char* DladdrElfHeaderBase(void* ld, char* addr) {
+#if SANITIZER_GLIBC
+  Dl_info info;
+  if (dladdr(ld, &info) && info.dli_fbase) {
+    addr = (char *)info.dli_fbase;
+  }
+#endif  // SANITIZER_GLIBC
+  return addr;
+}
+
 }  // namespace __sanitizer
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_dl.h b/compiler-rt/lib/sanitizer_common/sanitizer_dl.h
index ecde0664eb049..b98e4dfe48409 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_dl.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_dl.h
@@ -21,6 +21,10 @@ namespace __sanitizer {
 // - the main program itself, that contains the sanitizer.
 const char* DladdrSelfFName(void);
 
+// Returns the base address of the ELF header, taking custom base offsets
+// into account.
+char* DladdrElfHeaderBase(void* ld, char* addr);
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_DL_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
index ceff1717af7d7..f694ea0153495 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
@@ -17,6 +17,7 @@
     SANITIZER_SOLARIS || SANITIZER_HAIKU
 
 #  include "sanitizer_common.h"
+#  include "sanitizer_dl.h"
 #  include "sanitizer_flags.h"
 #  include "sanitizer_getauxval.h"
 #  include "sanitizer_internal_defs.h"
@@ -1395,6 +1396,47 @@ bool LibraryNameIs(const char *full_name, const char *base_name) {
   return (name[base_name_length] == '-' || name[base_name_length] == '.');
 }
 
+#  if !SANITIZER_ANDROID && !SANITIZER_HAIKU
+// Call cb for each region mapped by map.
+void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
+  CHECK_NE(map, nullptr);
+#    if !SANITIZER_FREEBSD && !SANITIZER_HAIKU
+  typedef ElfW(Phdr) Elf_Phdr;
+  typedef ElfW(Ehdr) Elf_Ehdr;
+#    endif  // !SANITIZER_FREEBSD
+  char *base = DladdrElfHeaderBase((void *)map->l_ld, (char *)map->l_ld);
+  Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
+  char *phdrs = base + ehdr->e_phoff;
+  char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;
+
+  // Find the segment with the minimum base so we can "relocate" the p_vaddr
+  // fields.  Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC
+  // objects have a non-zero base.
+  uptr preferred_base = (uptr)-1;
+  for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
+    Elf_Phdr *phdr = (Elf_Phdr *)iter;
+    if (phdr->p_type == PT_LOAD && preferred_base > (uptr)phdr->p_vaddr)
+      preferred_base = (uptr)phdr->p_vaddr;
+  }
+
+  // Compute the delta from the real base to get a relocation delta.
+  sptr delta = (uptr)base - preferred_base;
+  // Now we can figure out what the loader really mapped.
+  for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
+    Elf_Phdr *phdr = (Elf_Phdr *)iter;
+    if (phdr->p_type == PT_LOAD) {
+      uptr seg_start = phdr->p_vaddr + delta;
+      uptr seg_end = seg_start + phdr->p_memsz;
+      // None of these values are aligned.  We consider the ragged edges of the
+      // load command as defined, since they are mapped from the file.
+      seg_start = RoundDownTo(seg_start, GetPageSizeCached());
+      seg_end = RoundUpTo(seg_end, GetPageSizeCached());
+      cb((void *)seg_start, seg_end - seg_start);
+    }
+  }
+}
+#  endif
+
 #  if SANITIZER_LINUX
 #    if defined(__x86_64__)
 // We cannot use glibc's clone wrapper, because it messes with the child
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp
index f46705d3c8c9b..2c78522a0fceb 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp
@@ -1094,53 +1094,6 @@ void InitializePlatformCommonFlags(CommonFlags *cf) {
 #  endif
 }
 
-#  if !SANITIZER_ANDROID && !SANITIZER_HAIKU
-// Call cb for each region mapped by map.
-void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
-  CHECK_NE(map, nullptr);
-#    if !SANITIZER_FREEBSD && !SANITIZER_HAIKU
-  typedef ElfW(Phdr) Elf_Phdr;
-  typedef ElfW(Ehdr) Elf_Ehdr;
-#    endif  // !SANITIZER_FREEBSD
-  char *base = (char *)map->l_addr;
-#    if SANITIZER_GLIBC
-  Dl_info info;
-  if (dladdr((void *)map->l_ld, &info) && info.dli_fbase) {
-    base = (char *)info.dli_fbase;
-  }
-#    endif  // SANITIZER_GLIBC
-  Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
-  char *phdrs = base + ehdr->e_phoff;
-  char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;
-
-  // Find the segment with the minimum base so we can "relocate" the p_vaddr
-  // fields.  Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC
-  // objects have a non-zero base.
-  uptr preferred_base = (uptr)-1;
-  for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
-    Elf_Phdr *phdr = (Elf_Phdr *)iter;
-    if (phdr->p_type == PT_LOAD && preferred_base > (uptr)phdr->p_vaddr)
-      preferred_base = (uptr)phdr->p_vaddr;
-  }
-
-  // Compute the delta from the real base to get a relocation delta.
-  sptr delta = (uptr)base - preferred_base;
-  // Now we can figure out what the loader really mapped.
-  for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
-    Elf_Phdr *phdr = (Elf_Phdr *)iter;
-    if (phdr->p_type == PT_LOAD) {
-      uptr seg_start = phdr->p_vaddr + delta;
-      uptr seg_end = seg_start + phdr->p_memsz;
-      // None of these values are aligned.  We consider the ragged edges of the
-      // load command as defined, since they are mapped from the file.
-      seg_start = RoundDownTo(seg_start, GetPageSizeCached());
-      seg_end = RoundUpTo(seg_end, GetPageSizeCached());
-      cb((void *)seg_start, seg_end - seg_start);
-    }
-  }
-}
-#  endif
-
 }  // namespace __sanitizer
 
 #endif
diff --git a/compiler-rt/lib/tsan/go/buildgo.sh b/compiler-rt/lib/tsan/go/buildgo.sh
index 1340071819fcb..33adb26cb5afd 100755
--- a/compiler-rt/lib/tsan/go/buildgo.sh
+++ b/compiler-rt/lib/tsan/go/buildgo.sh
@@ -88,6 +88,7 @@ if [ "$GOOS" = "linux" ]; then
 	SRCS="
 		$SRCS
 		../rtl/tsan_platform_linux.cpp
+		../../sanitizer_common/sanitizer_dl.cpp
 		../../sanitizer_common/sanitizer_posix.cpp
 		../../sanitizer_common/sanitizer_posix_libcdep.cpp
 		../../sanitizer_common/sanitizer_procmaps_common.cpp
@@ -133,6 +134,7 @@ elif [ "$GOOS" = "freebsd" ]; then
 	SRCS="
 		$SRCS
 		../rtl/tsan_platform_linux.cpp
+		../../sanitizer_common/sanitizer_dl.cpp
 		../../sanitizer_common/sanitizer_posix.cpp
 		../../sanitizer_common/sanitizer_posix_libcdep.cpp
 		../../sanitizer_common/sanitizer_procmaps_bsd.cpp
@@ -153,6 +155,7 @@ elif [ "$GOOS" = "netbsd" ]; then
 	SRCS="
 		$SRCS
 		../rtl/tsan_platform_linux.cpp
+		../../sanitizer_common/sanitizer_dl.cpp
 		../../sanitizer_common/sanitizer_posix.cpp
 		../../sanitizer_common/sanitizer_posix_libcdep.cpp
 		../../sanitizer_common/sanitizer_procmaps_bsd.cpp

>From 0f39d8eaaad7062d612e3d2b12fc5f377fbf35b4 Mon Sep 17 00:00:00 2001
From: Mike Kruskal <mkruskal at google.com>
Date: Fri, 10 Jul 2026 16:19:30 -0700
Subject: [PATCH 07/12] Fix bad merge of test file

---
 .../sanitizer_common/TestCases/Linux/dlopen_image_base.c    | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/dlopen_image_base.c b/compiler-rt/test/sanitizer_common/TestCases/Linux/dlopen_image_base.c
index 56ceef3eba2f9..8fe4dff86d503 100644
--- a/compiler-rt/test/sanitizer_common/TestCases/Linux/dlopen_image_base.c
+++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/dlopen_image_base.c
@@ -30,6 +30,11 @@ int main(int argc, char *argv[]) {
   dlinfo(handle, RTLD_DI_LINKMAP, &map);
   if (map) {
     printf("DSO link_map name: %s\n", map->l_name);
+    printf("DSO link_map l_addr: %p\n", (void *)map->l_addr);
+    int pipefd[2];
+    bool readable = false;
+    if (pipe(pipefd) == 0) {
+      if (write(pipefd[1], (void *)map->l_addr, 1) == 1) {
         readable = true;
       }
       close(pipefd[0]);
@@ -46,5 +51,6 @@ int main(int argc, char *argv[]) {
   return 0;
 }
 #else // BUILD_SO
+#  include <stdio.h>
 void fn() { printf("DSO function called successfully\n"); }
 #endif

>From a5d8a0b05c3745e494cf58b244784ee1f4d9b2ec Mon Sep 17 00:00:00 2001
From: Mike Kruskal <mkruskal at google.com>
Date: Fri, 10 Jul 2026 16:20:47 -0700
Subject: [PATCH 08/12] Fix typo from previous commit

---
 compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
index f694ea0153495..109a43b9a7713 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
@@ -1404,7 +1404,7 @@ void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
   typedef ElfW(Phdr) Elf_Phdr;
   typedef ElfW(Ehdr) Elf_Ehdr;
 #    endif  // !SANITIZER_FREEBSD
-  char *base = DladdrElfHeaderBase((void *)map->l_ld, (char *)map->l_ld);
+  char *base = DladdrElfHeaderBase((void *)map->l_ld, (char *)map->l_addr);
   Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
   char *phdrs = base + ehdr->e_phoff;
   char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;

>From ff46ef10aa9e2c03cb6488ab65dccb6047c6b8bc Mon Sep 17 00:00:00 2001
From: Mike Kruskal <mkruskal at google.com>
Date: Fri, 10 Jul 2026 16:22:02 -0700
Subject: [PATCH 09/12] Remove braces

---
 compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp
index 8be66f9bb5fd9..3850a55ec6570 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp
@@ -37,9 +37,8 @@ const char *DladdrSelfFName(void) {
 char* DladdrElfHeaderBase(void* ld, char* addr) {
 #if SANITIZER_GLIBC
   Dl_info info;
-  if (dladdr(ld, &info) && info.dli_fbase) {
+  if (dladdr(ld, &info) && info.dli_fbase)
     addr = (char *)info.dli_fbase;
-  }
 #endif  // SANITIZER_GLIBC
   return addr;
 }

>From 834bdaa9b5fbbb018b4a209f9a6b7bde9945b0b1 Mon Sep 17 00:00:00 2001
From: Mike Kruskal <mkruskal at google.com>
Date: Fri, 10 Jul 2026 16:25:21 -0700
Subject: [PATCH 10/12] Fix formatting

---
 compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp    | 2 +-
 compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp
index 3850a55ec6570..3a33c85faf767 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp
@@ -38,7 +38,7 @@ char* DladdrElfHeaderBase(void* ld, char* addr) {
 #if SANITIZER_GLIBC
   Dl_info info;
   if (dladdr(ld, &info) && info.dli_fbase)
-    addr = (char *)info.dli_fbase;
+    addr = (char*)info.dli_fbase;
 #endif  // SANITIZER_GLIBC
   return addr;
 }
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
index 109a43b9a7713..f265f01919840 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
@@ -1404,7 +1404,7 @@ void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
   typedef ElfW(Phdr) Elf_Phdr;
   typedef ElfW(Ehdr) Elf_Ehdr;
 #    endif  // !SANITIZER_FREEBSD
-  char *base = DladdrElfHeaderBase((void *)map->l_ld, (char *)map->l_addr);
+  char *base = DladdrElfHeaderBase((void*)map->l_ld, (char*)map->l_addr);
   Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
   char *phdrs = base + ehdr->e_phoff;
   char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;

>From 864e88f5a60011a64046425ff8121ac1f58f03aa Mon Sep 17 00:00:00 2001
From: Mike Kruskal <mkruskal at google.com>
Date: Fri, 10 Jul 2026 16:28:46 -0700
Subject: [PATCH 11/12] Fix formatting

---
 compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
index f265f01919840..82915880503a8 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
@@ -1404,7 +1404,7 @@ void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
   typedef ElfW(Phdr) Elf_Phdr;
   typedef ElfW(Ehdr) Elf_Ehdr;
 #    endif  // !SANITIZER_FREEBSD
-  char *base = DladdrElfHeaderBase((void*)map->l_ld, (char*)map->l_addr);
+  char* base = DladdrElfHeaderBase((void*)map->l_ld, (char*)map->l_addr);
   Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
   char *phdrs = base + ehdr->e_phoff;
   char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;

>From df1bf496ee4e6cefe2d5207cdafcd16d32634c25 Mon Sep 17 00:00:00 2001
From: Mike Kruskal <mkruskal at google.com>
Date: Tue, 14 Jul 2026 10:48:39 -0700
Subject: [PATCH 12/12] Disable dladdr usage for go-tsan to avoid linkage
 problems with old glibc

---
 compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp
index 3a33c85faf767..0621e3bcad6f0 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp
@@ -23,7 +23,7 @@ namespace __sanitizer {
 extern const char *SanitizerToolName;
 
 const char *DladdrSelfFName(void) {
-#if SANITIZER_GLIBC
+#if SANITIZER_GLIBC && !SANITIZER_GO
   Dl_info info;
   int ret = dladdr((void *)&SanitizerToolName, &info);
   if (ret) {
@@ -35,7 +35,7 @@ const char *DladdrSelfFName(void) {
 }
 
 char* DladdrElfHeaderBase(void* ld, char* addr) {
-#if SANITIZER_GLIBC
+#if SANITIZER_GLIBC && !SANITIZER_GO
   Dl_info info;
   if (dladdr(ld, &info) && info.dli_fbase)
     addr = (char*)info.dli_fbase;



More information about the llvm-commits mailing list