[compiler-rt] [compiler-rt][TySan] Use pointer-width types for shadow memory ops (PR #191602)
Brian Cain via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 10 21:57:33 PDT 2026
https://github.com/androm3da created https://github.com/llvm/llvm-project/pull/191602
The TySan runtime used uint64_t/int64_t casts for shadow memory pointer arithmetic and interior-byte marker values. These are incorrect on 32-bit targets where pointers are 4 bytes: the shadow entries are pointer-sized, so the offsets and marker values must also be pointer-sized.
Replace uint64_t/int64_t with uptr/sptr (sanitizer_common's pointer-width typedefs) throughout SetShadowType, GetNotAllBadTD, GetNotAllUnkTD, and __tysan_instrument_mem_inst. This is a no-op on 64-bit targets (where uptr == uint64_t) and fixes shadow corruption on 32-bit targets.
>From 4bbe6faef7b029ebab4e85ea27a4fc6485e3a582 Mon Sep 17 00:00:00 2001
From: Brian Cain <brian.cain at oss.qualcomm.com>
Date: Fri, 10 Apr 2026 21:42:56 -0700
Subject: [PATCH] [compiler-rt][TySan] Use pointer-width types for shadow
memory operations
The TySan runtime used uint64_t/int64_t casts for shadow memory pointer
arithmetic and interior-byte marker values. These are incorrect on
32-bit targets where pointers are 4 bytes: the shadow entries are
pointer-sized, so the offsets and marker values must also be
pointer-sized.
Replace uint64_t/int64_t with uptr/sptr (sanitizer_common's
pointer-width typedefs) throughout SetShadowType, GetNotAllBadTD,
GetNotAllUnkTD, and __tysan_instrument_mem_inst. This is a no-op on
64-bit targets (where uptr == uint64_t) and fixes shadow corruption
on 32-bit targets.
---
compiler-rt/lib/tysan/tysan.cpp | 29 ++++++++++++++---------------
1 file changed, 14 insertions(+), 15 deletions(-)
diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp
index 52f941180b8eb..7c1cf193d3cb6 100644
--- a/compiler-rt/lib/tysan/tysan.cpp
+++ b/compiler-rt/lib/tysan/tysan.cpp
@@ -265,33 +265,33 @@ static void SetShadowType(tysan_type_descriptor *td,
tysan_type_descriptor **shadowData,
uint64_t AccessSize) {
*shadowData = td;
- uint64_t shadowDataInt = (uint64_t)shadowData;
+ uptr shadowDataInt = (uptr)shadowData;
for (uint64_t i = 1; i < AccessSize; ++i) {
- int64_t dataOffset = i << PtrShift();
- int64_t *badShadowData = (int64_t *)(shadowDataInt + dataOffset);
- int64_t badTD = int64_t(i) * -1;
+ uptr dataOffset = i << PtrShift();
+ sptr *badShadowData = (sptr *)(shadowDataInt + dataOffset);
+ sptr badTD = sptr(i) * -1;
*badShadowData = badTD;
}
}
ALWAYS_INLINE
-static bool GetNotAllBadTD(uint64_t ShadowDataInt, uint64_t AccessSize) {
+static bool GetNotAllBadTD(uptr ShadowDataInt, uint64_t AccessSize) {
bool notAllBadTD = false;
for (uint64_t i = 1; i < AccessSize; ++i) {
- int64_t **unkShadowData = (int64_t **)(ShadowDataInt + (i << PtrShift()));
- int64_t *ILdTD = *unkShadowData;
+ sptr **unkShadowData = (sptr **)(ShadowDataInt + (i << PtrShift()));
+ sptr *ILdTD = *unkShadowData;
notAllBadTD = notAllBadTD || (ILdTD != nullptr);
}
return notAllBadTD;
}
ALWAYS_INLINE
-static bool GetNotAllUnkTD(uint64_t ShadowDataInt, uint64_t AccessSize) {
+static bool GetNotAllUnkTD(uptr ShadowDataInt, uint64_t AccessSize) {
bool notAllBadTD = false;
for (uint64_t i = 1; i < AccessSize; ++i) {
- int64_t *badShadowData = (int64_t *)(ShadowDataInt + (i << PtrShift()));
- int64_t ILdTD = *badShadowData;
+ sptr *badShadowData = (sptr *)(ShadowDataInt + (i << PtrShift()));
+ sptr ILdTD = *badShadowData;
notAllBadTD = notAllBadTD || (ILdTD >= 0);
}
return notAllBadTD;
@@ -307,9 +307,8 @@ __tysan_instrument_mem_inst(char *dest, char *src, uint64_t size,
return;
}
- uint64_t srcInt = (uint64_t)src;
- uint64_t srcShadowInt = ((srcInt & AppMask()) << PtrShift()) + ShadowAddr();
- uint64_t *srcShadow = (uint64_t *)srcShadowInt;
+ uptr srcShadowInt = ((((uptr)src) & AppMask()) << PtrShift()) + ShadowAddr();
+ void *srcShadow = (void *)srcShadowInt;
if (needsMemMove) {
internal_memmove((char *)destShadowDataPtr, srcShadow, size << PtrShift());
@@ -389,7 +388,7 @@ __tysan_instrument_with_shadow_update(void *ptr, tysan_type_descriptor *td,
if (shadowIsNull) {
// We're about to set the type. Make sure that all bytes in the value
// are also of unknown type.
- bool isAllUnknownTD = GetNotAllUnkTD((uint64_t)shadowData, accessSize);
+ bool isAllUnknownTD = GetNotAllUnkTD((uptr)shadowData, accessSize);
if (isAllUnknownTD) {
GET_CALLER_PC_BP_SP;
__tysan_check_internal(ptr, accessSize, td, flags, pc, bp, sp);
@@ -402,7 +401,7 @@ __tysan_instrument_with_shadow_update(void *ptr, tysan_type_descriptor *td,
} else {
// We appear to have the right type. Make sure that all other bytes in
// the type are still marked as interior bytes. If not, call the runtime.
- bool isNotAllBadTD = GetNotAllBadTD((uint64_t)shadowData, accessSize);
+ bool isNotAllBadTD = GetNotAllBadTD((uptr)shadowData, accessSize);
if (isNotAllBadTD) {
GET_CALLER_PC_BP_SP;
__tysan_check_internal(ptr, accessSize, td, flags, pc, bp, sp);
More information about the llvm-commits
mailing list