[compiler-rt] [sanitizer_common] Implement address sanitizer on AIX: process memory mapping (PR #138537)

Jake Egan via llvm-commits llvm-commits at lists.llvm.org
Mon May 5 07:58:21 PDT 2025


https://github.com/jakeegan updated https://github.com/llvm/llvm-project/pull/138537

>From 6e6cf2e214f029697e45caa5303d36afc41c0e4c Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Mon, 5 May 2025 10:37:17 -0400
Subject: [PATCH 1/3] procmaps

---
 .../lib/sanitizer_common/CMakeLists.txt       |   1 +
 .../lib/sanitizer_common/sanitizer_aix.h      |  43 ++++++
 .../lib/sanitizer_common/sanitizer_procmaps.h |   2 +-
 .../sanitizer_procmaps_aix.cpp                | 131 ++++++++++++++++++
 4 files changed, 176 insertions(+), 1 deletion(-)
 create mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_aix.h
 create mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_procmaps_aix.cpp

diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
index 6e6dfd2f33ebf..2a62c79f38f08 100644
--- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt
+++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
@@ -26,6 +26,7 @@ set(SANITIZER_SOURCES_NOTERMINATION
   sanitizer_platform_limits_solaris.cpp
   sanitizer_posix.cpp
   sanitizer_printf.cpp
+  sanitizer_procmaps_aix.cpp
   sanitizer_procmaps_common.cpp
   sanitizer_procmaps_bsd.cpp
   sanitizer_procmaps_fuchsia.cpp
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_aix.h b/compiler-rt/lib/sanitizer_common/sanitizer_aix.h
new file mode 100644
index 0000000000000..80c4dd53db7c0
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_aix.h
@@ -0,0 +1,43 @@
+//===-- sanitizer_aix.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between various sanitizers' runtime libraries and
+// provides definitions for AIX-specific functions.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_AIX_H
+#define SANITIZER_AIX_H
+
+#include "sanitizer_platform.h"
+
+#if SANITIZER_AIX
+#  include "sanitizer_common.h"
+#  include "sanitizer_posix.h"
+
+struct prmap;
+typedef struct prmap prmap_t;
+
+namespace __sanitizer {
+
+struct ProcSelfMapsBuff {
+  char *data;
+  uptr mmaped_size;
+  uptr len;
+  prmap_t *mapEnd;
+};
+
+struct MemoryMappingLayoutData {
+  ProcSelfMapsBuff proc_self_maps;
+  const char *current;
+};
+
+void ReadProcMaps(ProcSelfMapsBuff *proc_maps);
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_AIX
+#endif  // SANITIZER_AIX_H
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
index d713ddf847dfb..c04e275f54570 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
@@ -17,7 +17,7 @@
 
 #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
     SANITIZER_APPLE || SANITIZER_SOLARIS || SANITIZER_HAIKU ||  \
-    SANITIZER_FUCHSIA
+    SANITIZER_FUCHSIA || SANITIZER_AIX
 
 #include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_aix.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_aix.cpp
new file mode 100644
index 0000000000000..d156a9ebecd84
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_aix.cpp
@@ -0,0 +1,131 @@
+//===-- sanitizer_procmaps_aix.cpp ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Information about the process mappings (AIX-specific parts).
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#if SANITIZER_AIX
+#  include <assert.h>
+#  include <stdio.h>
+#  include <stdlib.h>
+#  include <sys/procfs.h>
+
+#  include "sanitizer_common.h"
+#  include "sanitizer_file.h"
+#  include "sanitizer_procmaps.h"
+
+namespace __sanitizer {
+
+static int qsort_comp(const void *va, const void *vb) {
+  const prmap_t *a = (const prmap_t *)va;
+  const prmap_t *b = (const prmap_t *)vb;
+
+  if (a->pr_vaddr < b->pr_vaddr)
+    return -1;
+
+  if (a->pr_vaddr > b->pr_vaddr)
+    return 1;
+
+  return 0;
+}
+
+static prmap_t *SortProcMapEntries(char *buffer) {
+  prmap_t *begin = (prmap_t *)buffer;
+  prmap_t *mapIter = begin;
+  // The AIX procmap utility detects the end of the array of `prmap`s by finding
+  // an entry where pr_size and pr_vaddr are both zero.
+  while (mapIter->pr_size != 0 || mapIter->pr_vaddr != 0) ++mapIter;
+  prmap_t *end = mapIter;
+
+  size_t count = end - begin;
+  size_t elemSize = sizeof(prmap_t);
+  qsort(begin, count, elemSize, qsort_comp);
+
+  return end;
+}
+
+void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
+  uptr pid = internal_getpid();
+  constexpr unsigned BUFFER_SIZE = 128;
+  char filenameBuf[BUFFER_SIZE] = {};
+  internal_snprintf(filenameBuf, BUFFER_SIZE, "/proc/%d/map", pid);
+  if (!ReadFileToBuffer(filenameBuf, &proc_maps->data, &proc_maps->mmaped_size,
+                        &proc_maps->len)) {
+    proc_maps->data = nullptr;
+    proc_maps->mmaped_size = 0;
+    proc_maps->len = 0;
+    proc_maps->mapEnd = nullptr;
+    return;
+  }
+
+  proc_maps->mapEnd = SortProcMapEntries(proc_maps->data);
+}
+
+bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
+  if (Error())
+    return false;  // simulate empty maps
+
+  const prmap_t *mapIter = (const prmap_t *)data_.current;
+
+  if (mapIter >= data_.proc_self_maps.mapEnd)
+    return false;
+
+  // Skip the kernel segment.
+  if ((mapIter->pr_mflags & MA_TYPE_MASK) == MA_KERNTEXT)
+    ++mapIter;
+
+  if (mapIter >= data_.proc_self_maps.mapEnd)
+    return false;
+
+  segment->start = (uptr)mapIter->pr_vaddr;
+  segment->end = segment->start + mapIter->pr_size;
+
+  segment->protection = 0;
+  uint32_t flags = mapIter->pr_mflags;
+  if (flags & MA_READ)
+    segment->protection |= kProtectionRead;
+  if (flags & MA_WRITE)
+    segment->protection |= kProtectionWrite;
+  if (flags & MA_EXEC)
+    segment->protection |= kProtectionExecute;
+
+  uint32_t type = mapIter->pr_mflags & MA_TYPE_MASK;
+  if (type == MA_SLIBTEXT || type == MA_PLIBDATA)
+    segment->protection |= kProtectionShared;
+
+  if (segment->filename && mapIter->pr_pathoff) {
+    uptr len;
+    constexpr unsigned BUFFER_SIZE = 128;
+    char objPath[BUFFER_SIZE] = {};
+    // Use path /proc/<pid>/object/<object_id> 
+    // TODO: Pass a separate path from mapIter->pr_pathoff to display to the user.
+    // TODO: Append the archive member name if it exists.
+    internal_snprintf(objPath, BUFFER_SIZE, "/proc/%d/object/%s",
+                      internal_getpid(), mapIter->pr_mapname);
+    len = Min((uptr)internal_strlen(objPath), segment->filename_size - 1);
+    internal_strncpy(segment->filename, objPath, len);
+    segment->filename[len] = 0;
+
+  } else if (segment->filename) {
+    segment->filename[0] = 0;
+  }
+
+  assert(mapIter->pr_off == 0 && "expect a zero offset into module.");
+  segment->offset = 0;
+
+  ++mapIter;
+  data_.current = (const char *)mapIter;
+
+  return true;
+}
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_AIX

>From 01e0013194228ca387a6f2828fa9c7dda0305d21 Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Mon, 5 May 2025 10:45:26 -0400
Subject: [PATCH 2/3] Fix formatting

---
 .../lib/sanitizer_common/sanitizer_procmaps.h        | 12 ++++++------
 .../lib/sanitizer_common/sanitizer_procmaps_aix.cpp  |  5 +++--
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
index c04e275f54570..9cc10e9ed0f26 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
@@ -19,12 +19,12 @@
     SANITIZER_APPLE || SANITIZER_SOLARIS || SANITIZER_HAIKU ||  \
     SANITIZER_FUCHSIA || SANITIZER_AIX
 
-#include "sanitizer_common.h"
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_fuchsia.h"
-#include "sanitizer_linux.h"
-#include "sanitizer_mac.h"
-#include "sanitizer_mutex.h"
+#  include "sanitizer_common.h"
+#  include "sanitizer_internal_defs.h"
+#  include "sanitizer_fuchsia.h"
+#  include "sanitizer_linux.h"
+#  include "sanitizer_mac.h"
+#  include "sanitizer_mutex.h"
 
 namespace __sanitizer {
 
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_aix.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_aix.cpp
index d156a9ebecd84..c291f6a608e07 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_aix.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_aix.cpp
@@ -104,8 +104,9 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
     uptr len;
     constexpr unsigned BUFFER_SIZE = 128;
     char objPath[BUFFER_SIZE] = {};
-    // Use path /proc/<pid>/object/<object_id> 
-    // TODO: Pass a separate path from mapIter->pr_pathoff to display to the user.
+    // Use path /proc/<pid>/object/<object_id>
+    // TODO: Pass a separate path from mapIter->pr_pathoff to display to the
+    // user.
     // TODO: Append the archive member name if it exists.
     internal_snprintf(objPath, BUFFER_SIZE, "/proc/%d/object/%s",
                       internal_getpid(), mapIter->pr_mapname);

>From a34b5cde640c6d861a87ffbc66d1633ba5995d50 Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Mon, 5 May 2025 10:58:08 -0400
Subject: [PATCH 3/3] Fix formatting

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

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
index 9cc10e9ed0f26..0b633d92f6065 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
@@ -20,8 +20,8 @@
     SANITIZER_FUCHSIA || SANITIZER_AIX
 
 #  include "sanitizer_common.h"
-#  include "sanitizer_internal_defs.h"
 #  include "sanitizer_fuchsia.h"
+#  include "sanitizer_internal_defs.h"
 #  include "sanitizer_linux.h"
 #  include "sanitizer_mac.h"
 #  include "sanitizer_mutex.h"



More information about the llvm-commits mailing list