Skip to content

[sanitizer_common] Implement address sanitizer on AIX: process memory mapping #138537

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

jakeegan
Copy link
Member

@jakeegan jakeegan commented May 5, 2025

Implement process memory mapping on AIX using sys/procfs.h. We don't have direct access to the full path in the case of user libraries or executables, so we use the path /proc/<pid>/object/<object_id> for now.

#138916

@jakeegan jakeegan changed the title procmaps [sanitizer_common] Implement address sanitizer on AIX: process memory mapping May 5, 2025
Copy link

github-actions bot commented May 5, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@jakeegan jakeegan changed the title [sanitizer_common] Implement address sanitizer on AIX: process memory mapping [sanitizer_common] Implement address sanitizer on AIX: process memory mapping (7/n) May 7, 2025
@jakeegan jakeegan marked this pull request as ready for review May 7, 2025 17:36
@llvmbot
Copy link
Member

llvmbot commented May 7, 2025

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Jake Egan (jakeegan)

Changes

Implement process memory mapping on AIX using sys/procfs.h. We don't have direct access to the full path in the case of user libraries or executables, so we use the path /proc/&lt;pid&gt;/object/&lt;object_id&gt; for now.


Full diff: https://github.com/llvm/llvm-project/pull/138537.diff

4 Files Affected:

  • (modified) compiler-rt/lib/sanitizer_common/CMakeLists.txt (+2)
  • (added) compiler-rt/lib/sanitizer_common/sanitizer_aix.h (+43)
  • (modified) compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h (+9-8)
  • (added) compiler-rt/lib/sanitizer_common/sanitizer_procmaps_aix.cpp (+132)
diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
index 6e6dfd2f33ebf..c22df5948aca8 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
@@ -109,6 +110,7 @@ set(SANITIZER_IMPL_HEADERS
   sancov_flags.h
   sancov_flags.inc
   sanitizer_addrhashmap.h
+  sanitizer_aix.h
   sanitizer_allocator.h
   sanitizer_allocator_checks.h
   sanitizer_allocator_combined.h
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..0dcb8b1eb3046 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps.h
@@ -17,14 +17,15 @@
 
 #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
     SANITIZER_APPLE || SANITIZER_SOLARIS || SANITIZER_HAIKU ||  \
-    SANITIZER_FUCHSIA
-
-#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"
+    SANITIZER_FUCHSIA || SANITIZER_AIX
+
+#  include "sanitizer_aix.h"
+#  include "sanitizer_common.h"
+#  include "sanitizer_fuchsia.h"
+#  include "sanitizer_internal_defs.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
new file mode 100644
index 0000000000000..c291f6a608e07
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_aix.cpp
@@ -0,0 +1,132 @@
+//===-- 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

Copy link
Collaborator

@vitalybuka vitalybuka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but I didn't look into AIX specifics

Please (7/n) -> issue #

@vitalybuka vitalybuka changed the title [sanitizer_common] Implement address sanitizer on AIX: process memory mapping (7/n) [sanitizer_common] Implement address sanitizer on AIX: process memory mapping May 7, 2025
@vitalybuka
Copy link
Collaborator

LGTM, but I didn't look into AIX specifics

Please (7/n) -> issue #

Done for this one.
Is it OK?

@vitalybuka
Copy link
Collaborator

LGTM, but I didn't look into AIX specifics
Please (7/n) -> issue #

Done for this one. Is it OK?

I guess I don't mind if you continue counting, if you find it usefull,

Just drop #138916 into description.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants