[compiler-rt] [llvm] [msan] Add interceptors for fortified memory functions (__memcpy_chk, etc.) (PR #206702)
Austin Schuh via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 14 18:46:56 PDT 2026
https://github.com/AustinSchuh updated https://github.com/llvm/llvm-project/pull/206702
>From c9c1615265b586d2b19adb34fe442d02b929312a Mon Sep 17 00:00:00 2001
From: Austin Schuh <austin.linux at gmail.com>
Date: Tue, 30 Jun 2026 03:23:09 -0700
Subject: [PATCH 1/4] [msan] Add interceptors for fortified memory functions
(__memcpy_chk, etc.)
When compiled with glibc's source fortification enabled (e.g., -D_FORTIFY_SOURCE=2
along with compiler optimization), calls to standard memory functions like
memcpy, memmove, memset, and mempcpy are replaced with their fortified
variants: __memcpy_chk, __memmove_chk, __memset_chk, and __mempcpy_chk.
Clang's compile-time MemorySanitizer (MSan) pass does not lower these fortified
symbol calls to llvm.memcpy/memset intrinsics. Since compiler-rt lacked runtime
interceptors for these functions, shadow memory and origin state were not
propagated across fortified copy or fill operations. This led to false-positive
"use-of-uninitialized-value" warnings when memory copied via fortified functions
was subsequently accessed.
This patch adds MSan interceptors for:
- __memcpy_chk
- __memmove_chk
- __memset_chk
- __mempcpy_chk
Each interceptor updates the destination shadow and origin memory, and forwards
the execution to the underlying glibc implementation via REAL(...) to preserve
the original runtime buffer overflow checks. These interceptors are guarded
by `#if SANITIZER_GLIBC` as fortified _chk functions are a glibc extension.
We also add a new unit test suite (compiler-rt/test/msan/Linux/fortify.cpp)
to verify correct shadow propagation through these interceptors under both -O0
and -O2 compiler optimization levels.
Signed-off-by: Austin Schuh <austin.linux at gmail.com>
---
compiler-rt/lib/msan/msan_interceptors.cpp | 88 ++++++++++++++++++++++
compiler-rt/test/msan/Linux/fortify.cpp | 68 +++++++++++++++++
2 files changed, 156 insertions(+)
create mode 100644 compiler-rt/test/msan/Linux/fortify.cpp
diff --git a/compiler-rt/lib/msan/msan_interceptors.cpp b/compiler-rt/lib/msan/msan_interceptors.cpp
index ce2eae02d4179..862ecd60adcf0 100644
--- a/compiler-rt/lib/msan/msan_interceptors.cpp
+++ b/compiler-rt/lib/msan/msan_interceptors.cpp
@@ -63,6 +63,17 @@ DECLARE_REAL(SIZE_T, strnlen, const char *s, SIZE_T maxlen)
DECLARE_REAL(void *, memcpy, void *dest, const void *src, SIZE_T n)
DECLARE_REAL(void *, memset, void *dest, int c, SIZE_T n)
+#if SANITIZER_GLIBC
+DECLARE_REAL(void *, __memcpy_chk, void *dest, const void *src, SIZE_T n,
+ SIZE_T dest_size)
+DECLARE_REAL(void *, __memmove_chk, void *dest, const void *src, SIZE_T n,
+ SIZE_T dest_size)
+DECLARE_REAL(void *, __memset_chk, void *dest, int c, SIZE_T n,
+ SIZE_T dest_size)
+DECLARE_REAL(void *, __mempcpy_chk, void *dest, const void *src, SIZE_T n,
+ SIZE_T dest_size)
+#endif
+
// True if this is a nested interceptor.
static THREADLOCAL int in_interceptor_scope;
@@ -158,6 +169,79 @@ INTERCEPTOR(void *, bcopy, const void *src, void *dest, SIZE_T n) {
return __msan_memmove(dest, src, n);
}
+#if SANITIZER_GLIBC
+INTERCEPTOR(void *, __memcpy_chk, void *dest, const void *src, SIZE_T n,
+ SIZE_T dest_size) {
+ if (!msan_inited)
+ return internal_memcpy(dest, src, n);
+ if (msan_init_is_running || __msan::IsInSymbolizerOrUnwider())
+ return REAL(__memcpy_chk)(dest, src, n, dest_size);
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ void *res = REAL(__memcpy_chk)(dest, src, n, dest_size);
+ CopyShadowAndOrigin(dest, src, n, &stack);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___MEMCPY_CHK INTERCEPT_FUNCTION(__memcpy_chk)
+#else
+#define MSAN_MAYBE_INTERCEPT___MEMCPY_CHK
+#endif
+
+#if SANITIZER_GLIBC
+INTERCEPTOR(void *, __memmove_chk, void *dest, const void *src, SIZE_T n,
+ SIZE_T dest_size) {
+ if (!msan_inited)
+ return internal_memmove(dest, src, n);
+ if (msan_init_is_running || __msan::IsInSymbolizerOrUnwider())
+ return REAL(__memmove_chk)(dest, src, n, dest_size);
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ void *res = REAL(__memmove_chk)(dest, src, n, dest_size);
+ MoveShadowAndOrigin(dest, src, n, &stack);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___MEMMOVE_CHK INTERCEPT_FUNCTION(__memmove_chk)
+#else
+#define MSAN_MAYBE_INTERCEPT___MEMMOVE_CHK
+#endif
+
+#if SANITIZER_GLIBC
+INTERCEPTOR(void *, __memset_chk, void *dest, int c, SIZE_T n,
+ SIZE_T dest_size) {
+ if (!msan_inited)
+ return internal_memset(dest, c, n);
+ if (msan_init_is_running || __msan::IsInSymbolizerOrUnwider())
+ return REAL(__memset_chk)(dest, c, n, dest_size);
+ ENSURE_MSAN_INITED();
+ void *res = REAL(__memset_chk)(dest, c, n, dest_size);
+ __msan_unpoison(dest, n);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___MEMSET_CHK INTERCEPT_FUNCTION(__memset_chk)
+#else
+#define MSAN_MAYBE_INTERCEPT___MEMSET_CHK
+#endif
+
+#if SANITIZER_GLIBC
+INTERCEPTOR(void *, __mempcpy_chk, void *dest, const void *src, SIZE_T n,
+ SIZE_T dest_size) {
+ if (!msan_inited) {
+ internal_memcpy(dest, src, n);
+ return (char *)dest + n;
+ }
+ if (msan_init_is_running || __msan::IsInSymbolizerOrUnwider())
+ return REAL(__mempcpy_chk)(dest, src, n, dest_size);
+ ENSURE_MSAN_INITED();
+ GET_STORE_STACK_TRACE;
+ void *res = REAL(__mempcpy_chk)(dest, src, n, dest_size);
+ CopyShadowAndOrigin(dest, src, n, &stack);
+ return res;
+}
+#define MSAN_MAYBE_INTERCEPT___MEMPCPY_CHK INTERCEPT_FUNCTION(__mempcpy_chk)
+#else
+#define MSAN_MAYBE_INTERCEPT___MEMPCPY_CHK
+#endif
+
INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
GET_MALLOC_STACK_TRACE;
CHECK_NE(memptr, 0);
@@ -1822,6 +1906,10 @@ void InitializeInterceptors() {
MSAN_MAYBE_INTERCEPT_FREAD_UNLOCKED;
INTERCEPT_FUNCTION(memccpy);
MSAN_MAYBE_INTERCEPT_MEMPCPY;
+ MSAN_MAYBE_INTERCEPT___MEMCPY_CHK;
+ MSAN_MAYBE_INTERCEPT___MEMMOVE_CHK;
+ MSAN_MAYBE_INTERCEPT___MEMSET_CHK;
+ MSAN_MAYBE_INTERCEPT___MEMPCPY_CHK;
INTERCEPT_FUNCTION(bcopy);
INTERCEPT_FUNCTION(wmemset);
INTERCEPT_FUNCTION(wmemcpy);
diff --git a/compiler-rt/test/msan/Linux/fortify.cpp b/compiler-rt/test/msan/Linux/fortify.cpp
new file mode 100644
index 0000000000000..4568aa1827a94
--- /dev/null
+++ b/compiler-rt/test/msan/Linux/fortify.cpp
@@ -0,0 +1,68 @@
+// RUN: %clangxx_msan -O0 %s -o %t && %run %t
+// RUN: %clangxx_msan -O2 %s -o %t && %run %t
+
+// REQUIRES: glibc
+
+#include <assert.h>
+#include <string.h>
+#include <sanitizer/msan_interface.h>
+
+extern "C" void *__memcpy_chk(void *dest, const void *src, size_t len, size_t destlen);
+extern "C" void *__memmove_chk(void *dest, const void *src, size_t len, size_t destlen);
+extern "C" void *__memset_chk(void *dest, int c, size_t len, size_t destlen);
+extern "C" void *__mempcpy_chk(void *dest, const void *src, size_t len, size_t destlen);
+
+int main(int argc, char *argv[]) {
+ // Test __memcpy_chk shadow propagation
+ {
+ char src[10];
+ char dest[10];
+ __msan_unpoison(dest, sizeof(dest));
+ __msan_poison(src, sizeof(src));
+ src[1] = 1;
+ src[2] = 2;
+ __memcpy_chk(dest, src, 5, sizeof(dest));
+ assert(__msan_test_shadow(dest, 5) == 0); // dest[0] is uninitialized
+ assert(__msan_test_shadow(dest + 1, 4) == 2); // dest[1], dest[2] are initialized, dest[3..4] are uninitialized
+ assert(__msan_test_shadow(dest + 5, 5) == -1); // dest[5..9] remain initialized
+ }
+
+ // Test __memmove_chk shadow propagation
+ {
+ char src[10];
+ char dest[10];
+ __msan_unpoison(dest, sizeof(dest));
+ __msan_poison(src, sizeof(src));
+ src[1] = 1;
+ src[2] = 2;
+ __memmove_chk(dest, src, 5, sizeof(dest));
+ assert(__msan_test_shadow(dest, 5) == 0);
+ assert(__msan_test_shadow(dest + 1, 4) == 2);
+ assert(__msan_test_shadow(dest + 5, 5) == -1);
+ }
+
+ // Test __memset_chk shadow propagation
+ {
+ char dest[10];
+ __msan_poison(dest, sizeof(dest));
+ __memset_chk(dest, 42, 5, sizeof(dest));
+ assert(__msan_test_shadow(dest, 10) == 5); // first 5 bytes are initialized, remaining 5 are uninitialized
+ }
+
+ // Test __mempcpy_chk shadow propagation
+ {
+ char src[10];
+ char dest[10];
+ __msan_unpoison(dest, sizeof(dest));
+ __msan_poison(src, sizeof(src));
+ src[1] = 1;
+ src[2] = 2;
+ char *res = (char *)__mempcpy_chk(dest, src, 5, sizeof(dest));
+ assert(res == dest + 5);
+ assert(__msan_test_shadow(dest, 5) == 0);
+ assert(__msan_test_shadow(dest + 1, 4) == 2);
+ assert(__msan_test_shadow(dest + 5, 5) == -1);
+ }
+
+ return 0;
+}
>From 87907e7caa5efd8ec4988d6d70bd60f7f66607e8 Mon Sep 17 00:00:00 2001
From: Austin Schuh <austin.linux at gmail.com>
Date: Tue, 30 Jun 2026 12:33:18 -0700
Subject: [PATCH 2/4] Clang format
---
compiler-rt/lib/msan/msan_interceptors.cpp | 43 +++++++++++-----------
compiler-rt/test/msan/Linux/fortify.cpp | 23 ++++++++----
2 files changed, 36 insertions(+), 30 deletions(-)
diff --git a/compiler-rt/lib/msan/msan_interceptors.cpp b/compiler-rt/lib/msan/msan_interceptors.cpp
index 862ecd60adcf0..6a5565564bca7 100644
--- a/compiler-rt/lib/msan/msan_interceptors.cpp
+++ b/compiler-rt/lib/msan/msan_interceptors.cpp
@@ -64,13 +64,12 @@ DECLARE_REAL(void *, memcpy, void *dest, const void *src, SIZE_T n)
DECLARE_REAL(void *, memset, void *dest, int c, SIZE_T n)
#if SANITIZER_GLIBC
-DECLARE_REAL(void *, __memcpy_chk, void *dest, const void *src, SIZE_T n,
+DECLARE_REAL(void*, __memcpy_chk, void* dest, const void* src, SIZE_T n,
SIZE_T dest_size)
-DECLARE_REAL(void *, __memmove_chk, void *dest, const void *src, SIZE_T n,
+DECLARE_REAL(void*, __memmove_chk, void* dest, const void* src, SIZE_T n,
SIZE_T dest_size)
-DECLARE_REAL(void *, __memset_chk, void *dest, int c, SIZE_T n,
- SIZE_T dest_size)
-DECLARE_REAL(void *, __mempcpy_chk, void *dest, const void *src, SIZE_T n,
+DECLARE_REAL(void*, __memset_chk, void* dest, int c, SIZE_T n, SIZE_T dest_size)
+DECLARE_REAL(void*, __mempcpy_chk, void* dest, const void* src, SIZE_T n,
SIZE_T dest_size)
#endif
@@ -170,7 +169,7 @@ INTERCEPTOR(void *, bcopy, const void *src, void *dest, SIZE_T n) {
}
#if SANITIZER_GLIBC
-INTERCEPTOR(void *, __memcpy_chk, void *dest, const void *src, SIZE_T n,
+INTERCEPTOR(void*, __memcpy_chk, void* dest, const void* src, SIZE_T n,
SIZE_T dest_size) {
if (!msan_inited)
return internal_memcpy(dest, src, n);
@@ -178,17 +177,17 @@ INTERCEPTOR(void *, __memcpy_chk, void *dest, const void *src, SIZE_T n,
return REAL(__memcpy_chk)(dest, src, n, dest_size);
ENSURE_MSAN_INITED();
GET_STORE_STACK_TRACE;
- void *res = REAL(__memcpy_chk)(dest, src, n, dest_size);
+ void* res = REAL(__memcpy_chk)(dest, src, n, dest_size);
CopyShadowAndOrigin(dest, src, n, &stack);
return res;
}
-#define MSAN_MAYBE_INTERCEPT___MEMCPY_CHK INTERCEPT_FUNCTION(__memcpy_chk)
+# define MSAN_MAYBE_INTERCEPT___MEMCPY_CHK INTERCEPT_FUNCTION(__memcpy_chk)
#else
-#define MSAN_MAYBE_INTERCEPT___MEMCPY_CHK
+# define MSAN_MAYBE_INTERCEPT___MEMCPY_CHK
#endif
#if SANITIZER_GLIBC
-INTERCEPTOR(void *, __memmove_chk, void *dest, const void *src, SIZE_T n,
+INTERCEPTOR(void*, __memmove_chk, void* dest, const void* src, SIZE_T n,
SIZE_T dest_size) {
if (!msan_inited)
return internal_memmove(dest, src, n);
@@ -196,50 +195,50 @@ INTERCEPTOR(void *, __memmove_chk, void *dest, const void *src, SIZE_T n,
return REAL(__memmove_chk)(dest, src, n, dest_size);
ENSURE_MSAN_INITED();
GET_STORE_STACK_TRACE;
- void *res = REAL(__memmove_chk)(dest, src, n, dest_size);
+ void* res = REAL(__memmove_chk)(dest, src, n, dest_size);
MoveShadowAndOrigin(dest, src, n, &stack);
return res;
}
-#define MSAN_MAYBE_INTERCEPT___MEMMOVE_CHK INTERCEPT_FUNCTION(__memmove_chk)
+# define MSAN_MAYBE_INTERCEPT___MEMMOVE_CHK INTERCEPT_FUNCTION(__memmove_chk)
#else
-#define MSAN_MAYBE_INTERCEPT___MEMMOVE_CHK
+# define MSAN_MAYBE_INTERCEPT___MEMMOVE_CHK
#endif
#if SANITIZER_GLIBC
-INTERCEPTOR(void *, __memset_chk, void *dest, int c, SIZE_T n,
+INTERCEPTOR(void*, __memset_chk, void* dest, int c, SIZE_T n,
SIZE_T dest_size) {
if (!msan_inited)
return internal_memset(dest, c, n);
if (msan_init_is_running || __msan::IsInSymbolizerOrUnwider())
return REAL(__memset_chk)(dest, c, n, dest_size);
ENSURE_MSAN_INITED();
- void *res = REAL(__memset_chk)(dest, c, n, dest_size);
+ void* res = REAL(__memset_chk)(dest, c, n, dest_size);
__msan_unpoison(dest, n);
return res;
}
-#define MSAN_MAYBE_INTERCEPT___MEMSET_CHK INTERCEPT_FUNCTION(__memset_chk)
+# define MSAN_MAYBE_INTERCEPT___MEMSET_CHK INTERCEPT_FUNCTION(__memset_chk)
#else
-#define MSAN_MAYBE_INTERCEPT___MEMSET_CHK
+# define MSAN_MAYBE_INTERCEPT___MEMSET_CHK
#endif
#if SANITIZER_GLIBC
-INTERCEPTOR(void *, __mempcpy_chk, void *dest, const void *src, SIZE_T n,
+INTERCEPTOR(void*, __mempcpy_chk, void* dest, const void* src, SIZE_T n,
SIZE_T dest_size) {
if (!msan_inited) {
internal_memcpy(dest, src, n);
- return (char *)dest + n;
+ return (char*)dest + n;
}
if (msan_init_is_running || __msan::IsInSymbolizerOrUnwider())
return REAL(__mempcpy_chk)(dest, src, n, dest_size);
ENSURE_MSAN_INITED();
GET_STORE_STACK_TRACE;
- void *res = REAL(__mempcpy_chk)(dest, src, n, dest_size);
+ void* res = REAL(__mempcpy_chk)(dest, src, n, dest_size);
CopyShadowAndOrigin(dest, src, n, &stack);
return res;
}
-#define MSAN_MAYBE_INTERCEPT___MEMPCPY_CHK INTERCEPT_FUNCTION(__mempcpy_chk)
+# define MSAN_MAYBE_INTERCEPT___MEMPCPY_CHK INTERCEPT_FUNCTION(__mempcpy_chk)
#else
-#define MSAN_MAYBE_INTERCEPT___MEMPCPY_CHK
+# define MSAN_MAYBE_INTERCEPT___MEMPCPY_CHK
#endif
INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) {
diff --git a/compiler-rt/test/msan/Linux/fortify.cpp b/compiler-rt/test/msan/Linux/fortify.cpp
index 4568aa1827a94..041428655d847 100644
--- a/compiler-rt/test/msan/Linux/fortify.cpp
+++ b/compiler-rt/test/msan/Linux/fortify.cpp
@@ -4,13 +4,16 @@
// REQUIRES: glibc
#include <assert.h>
-#include <string.h>
#include <sanitizer/msan_interface.h>
+#include <string.h>
-extern "C" void *__memcpy_chk(void *dest, const void *src, size_t len, size_t destlen);
-extern "C" void *__memmove_chk(void *dest, const void *src, size_t len, size_t destlen);
+extern "C" void *__memcpy_chk(void *dest, const void *src, size_t len,
+ size_t destlen);
+extern "C" void *__memmove_chk(void *dest, const void *src, size_t len,
+ size_t destlen);
extern "C" void *__memset_chk(void *dest, int c, size_t len, size_t destlen);
-extern "C" void *__mempcpy_chk(void *dest, const void *src, size_t len, size_t destlen);
+extern "C" void *__mempcpy_chk(void *dest, const void *src, size_t len,
+ size_t destlen);
int main(int argc, char *argv[]) {
// Test __memcpy_chk shadow propagation
@@ -22,9 +25,12 @@ int main(int argc, char *argv[]) {
src[1] = 1;
src[2] = 2;
__memcpy_chk(dest, src, 5, sizeof(dest));
- assert(__msan_test_shadow(dest, 5) == 0); // dest[0] is uninitialized
- assert(__msan_test_shadow(dest + 1, 4) == 2); // dest[1], dest[2] are initialized, dest[3..4] are uninitialized
- assert(__msan_test_shadow(dest + 5, 5) == -1); // dest[5..9] remain initialized
+ // dest[0] is uninitialized
+ assert(__msan_test_shadow(dest, 5) == 0);
+ // dest[1], dest[2] are initialized, dest[3..4] are uninitialized
+ assert(__msan_test_shadow(dest + 1, 4) == 2);
+ // dest[5..9] remain initialized
+ assert(__msan_test_shadow(dest + 5, 5) == -1);
}
// Test __memmove_chk shadow propagation
@@ -46,7 +52,8 @@ int main(int argc, char *argv[]) {
char dest[10];
__msan_poison(dest, sizeof(dest));
__memset_chk(dest, 42, 5, sizeof(dest));
- assert(__msan_test_shadow(dest, 10) == 5); // first 5 bytes are initialized, remaining 5 are uninitialized
+ // first 5 bytes are initialized, remaining 5 are uninitialized
+ assert(__msan_test_shadow(dest, 10) == 5);
}
// Test __mempcpy_chk shadow propagation
>From 23a328703506f3b81d724989478d48e2bc83e5b2 Mon Sep 17 00:00:00 2001
From: Austin Schuh <austin.linux at gmail.com>
Date: Wed, 1 Jul 2026 15:46:55 -0700
Subject: [PATCH 3/4] Addressed comments
---
.../TestCases}/Linux/fortify.cpp | 44 ++++++++++++++++---
llvm/runtimes/CMakeLists.txt | 5 ++-
2 files changed, 41 insertions(+), 8 deletions(-)
rename compiler-rt/test/{msan => sanitizer_common/TestCases}/Linux/fortify.cpp (67%)
diff --git a/compiler-rt/test/msan/Linux/fortify.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/fortify.cpp
similarity index 67%
rename from compiler-rt/test/msan/Linux/fortify.cpp
rename to compiler-rt/test/sanitizer_common/TestCases/Linux/fortify.cpp
index 041428655d847..381697f74cf98 100644
--- a/compiler-rt/test/msan/Linux/fortify.cpp
+++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/fortify.cpp
@@ -1,12 +1,13 @@
-// RUN: %clangxx_msan -O0 %s -o %t && %run %t
-// RUN: %clangxx_msan -O2 %s -o %t && %run %t
+// RUN: %clangxx -O0 %s -o %t && %run %t
+// RUN: %clangxx -O2 %s -o %t && %run %t
// REQUIRES: glibc
#include <assert.h>
-#include <sanitizer/msan_interface.h>
#include <string.h>
+#include "sanitizer_common/sanitizer_specific.h"
+
extern "C" void *__memcpy_chk(void *dest, const void *src, size_t len,
size_t destlen);
extern "C" void *__memmove_chk(void *dest, const void *src, size_t len,
@@ -16,59 +17,88 @@ extern "C" void *__mempcpy_chk(void *dest, const void *src, size_t len,
size_t destlen);
int main(int argc, char *argv[]) {
- // Test __memcpy_chk shadow propagation
+ // Test __memcpy_chk basic behavior & shadow propagation
{
char src[10];
char dest[10];
+#if __has_feature(memory_sanitizer)
__msan_unpoison(dest, sizeof(dest));
__msan_poison(src, sizeof(src));
+#endif
src[1] = 1;
src[2] = 2;
__memcpy_chk(dest, src, 5, sizeof(dest));
+#if __has_feature(memory_sanitizer)
// dest[0] is uninitialized
assert(__msan_test_shadow(dest, 5) == 0);
// dest[1], dest[2] are initialized, dest[3..4] are uninitialized
assert(__msan_test_shadow(dest + 1, 4) == 2);
// dest[5..9] remain initialized
assert(__msan_test_shadow(dest + 5, 5) == -1);
+#else
+ assert(dest[1] == 1);
+ assert(dest[2] == 2);
+#endif
}
- // Test __memmove_chk shadow propagation
+ // Test __memmove_chk basic behavior & shadow propagation
{
char src[10];
char dest[10];
+#if __has_feature(memory_sanitizer)
__msan_unpoison(dest, sizeof(dest));
__msan_poison(src, sizeof(src));
+#endif
src[1] = 1;
src[2] = 2;
__memmove_chk(dest, src, 5, sizeof(dest));
+#if __has_feature(memory_sanitizer)
assert(__msan_test_shadow(dest, 5) == 0);
assert(__msan_test_shadow(dest + 1, 4) == 2);
assert(__msan_test_shadow(dest + 5, 5) == -1);
+#else
+ assert(dest[1] == 1);
+ assert(dest[2] == 2);
+#endif
}
- // Test __memset_chk shadow propagation
+ // Test __memset_chk basic behavior & shadow propagation
{
char dest[10];
+#if __has_feature(memory_sanitizer)
__msan_poison(dest, sizeof(dest));
+#endif
__memset_chk(dest, 42, 5, sizeof(dest));
+#if __has_feature(memory_sanitizer)
// first 5 bytes are initialized, remaining 5 are uninitialized
assert(__msan_test_shadow(dest, 10) == 5);
+#else
+ for (int i = 0; i < 5; ++i) {
+ assert(dest[i] == 42);
+ }
+#endif
}
- // Test __mempcpy_chk shadow propagation
+ // Test __mempcpy_chk basic behavior & shadow propagation
{
char src[10];
char dest[10];
+#if __has_feature(memory_sanitizer)
__msan_unpoison(dest, sizeof(dest));
__msan_poison(src, sizeof(src));
+#endif
src[1] = 1;
src[2] = 2;
char *res = (char *)__mempcpy_chk(dest, src, 5, sizeof(dest));
assert(res == dest + 5);
+#if __has_feature(memory_sanitizer)
assert(__msan_test_shadow(dest, 5) == 0);
assert(__msan_test_shadow(dest + 1, 4) == 2);
assert(__msan_test_shadow(dest + 5, 5) == -1);
+#else
+ assert(dest[1] == 1);
+ assert(dest[2] == 2);
+#endif
}
return 0;
diff --git a/llvm/runtimes/CMakeLists.txt b/llvm/runtimes/CMakeLists.txt
index 501ea55a327c7..529253542785a 100644
--- a/llvm/runtimes/CMakeLists.txt
+++ b/llvm/runtimes/CMakeLists.txt
@@ -327,7 +327,10 @@ function(runtime_default_target)
if(LLVM_INCLUDE_TESTS)
set_property(GLOBAL APPEND PROPERTY LLVM_ALL_LIT_TESTSUITES "@${LLVM_BINARY_DIR}/runtimes/runtimes-bins/lit.tests")
- list(APPEND test_targets runtimes-test-depends check-runtimes check-builtins)
+ list(APPEND test_targets runtimes-test-depends check-runtimes)
+ if(NOT "compiler-rt" IN_LIST LLVM_ENABLE_PROJECTS)
+ list(APPEND test_targets check-builtins)
+ endif()
list(APPEND ARG_CMAKE_ARGS "-DCOMPILER_RT_TEST_EXTERNAL_BUILTINS=ON")
endif()
>From a1e0d6f30a73a4d3ec265436becdd02ae5b56185 Mon Sep 17 00:00:00 2001
From: Austin Schuh <austin.linux at gmail.com>
Date: Tue, 14 Jul 2026 18:38:59 -0700
Subject: [PATCH 4/4] Revert CMakeLists change
---
llvm/runtimes/CMakeLists.txt | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/llvm/runtimes/CMakeLists.txt b/llvm/runtimes/CMakeLists.txt
index 529253542785a..501ea55a327c7 100644
--- a/llvm/runtimes/CMakeLists.txt
+++ b/llvm/runtimes/CMakeLists.txt
@@ -327,10 +327,7 @@ function(runtime_default_target)
if(LLVM_INCLUDE_TESTS)
set_property(GLOBAL APPEND PROPERTY LLVM_ALL_LIT_TESTSUITES "@${LLVM_BINARY_DIR}/runtimes/runtimes-bins/lit.tests")
- list(APPEND test_targets runtimes-test-depends check-runtimes)
- if(NOT "compiler-rt" IN_LIST LLVM_ENABLE_PROJECTS)
- list(APPEND test_targets check-builtins)
- endif()
+ list(APPEND test_targets runtimes-test-depends check-runtimes check-builtins)
list(APPEND ARG_CMAKE_ARGS "-DCOMPILER_RT_TEST_EXTERNAL_BUILTINS=ON")
endif()
More information about the llvm-commits
mailing list