[compiler-rt] [llvm] [compiler-rt][msan] Add MSan support for RISC-V 64-bit Linux (PR #206674)

Meng Zhuo via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 30 01:09:08 PDT 2026


https://github.com/mengzhuo created https://github.com/llvm/llvm-project/pull/206674

RISC-V uses a 5-bit address compression via
AndMask=0x3C00000000 to fold the 39-bit virtual address space (SV39, 256GB) into a ≤48GB compressed region, enabling MSan to fit within the constrained VMA. The layout accommodates the RISC-V Linux memory map where the dynamic linker and shared libraries load near the top of user space.

Memory layout (SV39-compatible, fits within 256GB):
    0x0000001000 - 0x001000000000  APP-lo     (64GB, program segments)
    0x001000000000 - 0x001c00000000  SHADOW     (48GB)
    0x001c00000000 - 0x002c00000000  APP-mid    (64GB, PIE / mmap)
    0x002c00000000 - 0x003000000000  ALLOCATOR  (16GB)
    0x003000000000 - 0x003c00000000  ORIGIN     (48GB)
    0x003c00000000 - 0x004000000000  APP-hi     (16GB, libraries / stack)

MEM_TO_SHADOW folds bits 34-37 via (addr & ~0x3C00000000) ^ 0x0800000000 then adds ShadowBase 0x1000000000. SHADOW_TO_ORIGIN adds 0x2000000000. The allocator uses SizeClassAllocator64 with a 16GB region at 0x2C00000000, and kMaxAllowedMallocSize is set to 8GB consistent with other 64-bit RISC targets.

>From 65e6d0d2952b70a2274d2393887241809e09f561 Mon Sep 17 00:00:00 2001
From: Meng Zhuo <mengzhuo at iscas.ac.cn>
Date: Tue, 30 Jun 2026 09:47:58 +0800
Subject: [PATCH] [compiler-rt][msan] Add MSan support for RISC-V 64-bit Linux
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

RISC-V uses a 5-bit address compression via
AndMask=0x3C00000000 to fold the 39-bit virtual address space (SV39,
256GB) into a ≤48GB compressed region, enabling MSan to fit within the
constrained VMA. The layout accommodates the RISC-V Linux memory map where
the dynamic linker and shared libraries load near the top of user space.

Memory layout (SV39-compatible, fits within 256GB):
    0x0000001000 - 0x001000000000  APP-lo     (64GB, program segments)
    0x001000000000 - 0x001c00000000  SHADOW     (48GB)
    0x001c00000000 - 0x002c00000000  APP-mid    (64GB, PIE / mmap)
    0x002c00000000 - 0x003000000000  ALLOCATOR  (16GB)
    0x003000000000 - 0x003c00000000  ORIGIN     (48GB)
    0x003c00000000 - 0x004000000000  APP-hi     (16GB, libraries / stack)

MEM_TO_SHADOW folds bits 34-37 via (addr & ~0x3C00000000) ^ 0x0800000000
then adds ShadowBase 0x1000000000. SHADOW_TO_ORIGIN adds 0x2000000000.
The allocator uses SizeClassAllocator64 with a 16GB region at 0x2C00000000,
and kMaxAllowedMallocSize is set to 8GB consistent with other 64-bit RISC
targets.
---
 .../cmake/Modules/AllSupportedArchDefs.cmake     |  2 +-
 compiler-rt/lib/msan/msan.h                      | 14 ++++++++++++++
 compiler-rt/lib/msan/msan_allocator.cpp          | 15 +++++++++++++++
 .../Instrumentation/MemorySanitizer.cpp          | 16 ++++++++++++++++
 4 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
index 9c03892dffe5a..4389df8d3fece 100644
--- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
+++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
@@ -89,7 +89,7 @@ if (OS_NAME MATCHES "FreeBSD")
   set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${ARM64})
 else()
   set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64} ${S390X}
-      ${LOONGARCH64} ${HEXAGON})
+      ${LOONGARCH64} ${HEXAGON} ${RISCV64})
 endif()
 set(ALL_NSAN_SUPPORTED_ARCH ${X86_64})
 set(ALL_HWASAN_SUPPORTED_ARCH ${X86_64} ${ARM64} ${RISCV64})
diff --git a/compiler-rt/lib/msan/msan.h b/compiler-rt/lib/msan/msan.h
index 8e2dc075cb79c..f51518966c6c0 100644
--- a/compiler-rt/lib/msan/msan.h
+++ b/compiler-rt/lib/msan/msan.h
@@ -142,6 +142,20 @@ const MappingDesc kMemoryLayout[] = {
 #define MEM_TO_SHADOW(mem) (LINEARIZE_MEM((mem)) + 0x080000000000ULL)
 #define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x140000000000ULL)
 
+#elif SANITIZER_LINUX && SANITIZER_RISCV64
+// RISC-V 64 SV39 layout (256GB VMA).
+const MappingDesc kMemoryLayout[] = {
+    {0x000000000000ULL, 0x000000001000ULL, MappingDesc::INVALID, "null"},
+    {0x000000001000ULL, 0x001000000000ULL, MappingDesc::APP, "app-lo"},
+    {0x001000000000ULL, 0x001c00000000ULL, MappingDesc::SHADOW, "shadow"},
+    {0x001c00000000ULL, 0x002c00000000ULL, MappingDesc::APP, "app-mid"},
+    {0x002c00000000ULL, 0x003000000000ULL, MappingDesc::ALLOCATOR, "alloc"},
+    {0x003000000000ULL, 0x003c00000000ULL, MappingDesc::ORIGIN, "origin"},
+    {0x003c00000000ULL, 0x004000000000ULL, MappingDesc::APP, "app-hi"},
+};
+#  define MEM_TO_SHADOW(mem) ((((uptr)(mem) & ~0x3c00000000ULL) ^ 0x0800000000ULL) + 0x1000000000ULL)
+#  define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x2000000000ULL)
+
 #elif SANITIZER_LINUX && SANITIZER_S390_64
 const MappingDesc kMemoryLayout[] = {
     {0x000000000000ULL, 0x040000000000ULL, MappingDesc::APP, "low memory"},
diff --git a/compiler-rt/lib/msan/msan_allocator.cpp b/compiler-rt/lib/msan/msan_allocator.cpp
index 532657f73590a..20c49307c4d59 100644
--- a/compiler-rt/lib/msan/msan_allocator.cpp
+++ b/compiler-rt/lib/msan/msan_allocator.cpp
@@ -129,6 +129,21 @@ struct AP64 {  // Allocator64 parameters. Deliberately using a short name.
   using AddressSpaceView = LocalAddressSpaceView;
 };
 
+using PrimaryAllocator = SizeClassAllocator64<AP64>;
+#elif defined(__riscv) && __riscv_xlen == 64
+const uptr kAllocatorSpace = 0x2c00000000ULL;
+const uptr kMaxAllowedMallocSize = 8UL << 30;
+
+struct AP64 {
+  static const uptr kSpaceBeg = kAllocatorSpace;
+  static const uptr kSpaceSize = 0x0400000000;  // 16GB.
+  static const uptr kMetadataSize = sizeof(Metadata);
+  using SizeClassMap = DefaultSizeClassMap;
+  using MapUnmapCallback = MsanMapUnmapCallback;
+  static const uptr kFlags = 0;
+  using AddressSpaceView = LocalAddressSpaceView;
+};
+
 using PrimaryAllocator = SizeClassAllocator64<AP64>;
 #elif SANITIZER_LINUX && defined(__hexagon__)
 const uptr kMaxAllowedMallocSize = 1UL << 30;  // 1G
diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
index cdce2e039154f..3779d8c1c55ee 100644
--- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
@@ -520,6 +520,14 @@ static const MemoryMapParams Linux_Hexagon_MemoryMapParams = {
 // FIXME: Remove -msan-origin-base -msan-and-mask added by PR #109284 to tests
 // after picking good constants
 
+// riscv64 Linux — SV39 (256GB)
+static const MemoryMapParams Linux_RISCV64_MemoryMapParams = {
+    0x3C00000000,   // AndMask (fold bits 34-37)
+    0x0800000000,   // XorMask (flip bit 35)
+    0x1000000000,   // ShadowBase (shadow at 64GB)
+    0x3000000000,   // OriginBase (origin at 192GB)
+};
+
 // aarch64 FreeBSD
 static const MemoryMapParams FreeBSD_AArch64_MemoryMapParams = {
     0x1800000000000, // AndMask
@@ -587,6 +595,11 @@ static const PlatformMemoryMapParams Linux_Hexagon_MemoryMapParams_P = {
     nullptr,
 };
 
+static const PlatformMemoryMapParams Linux_RISCV_MemoryMapParams = {
+    nullptr,
+    &Linux_RISCV64_MemoryMapParams,
+};
+
 static const PlatformMemoryMapParams FreeBSD_ARM_MemoryMapParams = {
     nullptr,
     &FreeBSD_AArch64_MemoryMapParams,
@@ -1117,6 +1130,9 @@ void MemorySanitizer::initializeModule(Module &M) {
       case Triple::hexagon:
         MapParams = Linux_Hexagon_MemoryMapParams_P.bits32;
         break;
+      case Triple::riscv64:
+        MapParams = Linux_RISCV_MemoryMapParams.bits64;
+        break;
       default:
         report_fatal_error("unsupported architecture");
       }



More information about the llvm-commits mailing list