[clang] [compiler-rt] [llvm] [dfsan] Add dataflow sanitizer support for SystemZ (PR #168991)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 20 19:07:34 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-driver
Author: None (anoopkg6)
<details>
<summary>Changes</summary>
Add SystemZ specific changes for dataflow sanitizer on top of following two common code changes
i) Fix Endianness issue [#<!-- -->162881](https://github.com/llvm/llvm-project/pull/162881)
ii) Fix ShadowAddress computation [#<!-- -->162864](https://github.com/llvm/llvm-project/pull/162864[](url))
See conversation in original pr#[#<!-- -->162195](https://github.com/llvm/llvm-project/pull/162195)
---
Full diff: https://github.com/llvm/llvm-project/pull/168991.diff
11 Files Affected:
- (modified) clang/lib/Driver/ToolChains/Linux.cpp (+1-1)
- (modified) compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake (+2-1)
- (modified) compiler-rt/lib/dfsan/dfsan_allocator.cpp (+16)
- (modified) compiler-rt/lib/dfsan/dfsan_custom.cpp (+13)
- (modified) compiler-rt/lib/dfsan/dfsan_platform.h (+14)
- (modified) compiler-rt/test/dfsan/custom.cpp (+1-1)
- (modified) compiler-rt/test/dfsan/lit.cfg.py (+6-1)
- (modified) compiler-rt/test/dfsan/origin_endianness.c (+2-2)
- (modified) compiler-rt/test/dfsan/pair.cpp (+24-12)
- (modified) compiler-rt/test/dfsan/struct.c (+6-6)
- (modified) llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp (+11)
``````````diff
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index 020e7465548fe..eb2330e35d003 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -914,7 +914,7 @@ SanitizerMask Linux::getSupportedSanitizers() const {
Res |= SanitizerKind::KernelAddress;
Res |= SanitizerKind::Vptr;
Res |= SanitizerKind::SafeStack;
- if (IsX86_64 || IsMIPS64 || IsAArch64 || IsLoongArch64)
+ if (IsX86_64 || IsMIPS64 || IsAArch64 || IsLoongArch64 || IsSystemZ)
Res |= SanitizerKind::DataFlow;
if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64 ||
IsRISCV64 || IsSystemZ || IsHexagon || IsLoongArch64)
diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
index ca45d7bd2af7f..2bc695922ef2d 100644
--- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
+++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
@@ -35,7 +35,8 @@ set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${RISCV64}
${MIPS32} ${MIPS64} ${PPC64} ${S390X} ${SPARC} ${SPARCV9} ${HEXAGON}
${LOONGARCH64})
set(ALL_ASAN_ABI_SUPPORTED_ARCH ${X86_64} ${ARM64} ${ARM64_32})
-set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${LOONGARCH64})
+set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${LOONGARCH64}
+ ${S390X})
set(ALL_RTSAN_SUPPORTED_ARCH ${X86_64} ${ARM64})
if(ANDROID)
diff --git a/compiler-rt/lib/dfsan/dfsan_allocator.cpp b/compiler-rt/lib/dfsan/dfsan_allocator.cpp
index 160b1a64d8f6f..700b2fccf9f6c 100644
--- a/compiler-rt/lib/dfsan/dfsan_allocator.cpp
+++ b/compiler-rt/lib/dfsan/dfsan_allocator.cpp
@@ -44,9 +44,24 @@ struct DFsanMapUnmapCallback {
// duplicated as MappingDesc::ALLOCATOR in dfsan_platform.h.
#if defined(__aarch64__)
const uptr kAllocatorSpace = 0xE00000000000ULL;
+#elif defined(__s390x__)
+const uptr kAllocatorSpace = 0x440000000000ULL;
#else
const uptr kAllocatorSpace = 0x700000000000ULL;
#endif
+#if defined(__s390x__)
+const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G
+
+struct AP64 { // Allocator64 parameters. Deliberately using a short name.
+ static const uptr kSpaceBeg = kAllocatorSpace;
+ static const uptr kSpaceSize = 0x020000000000; // 2T.
+ static const uptr kMetadataSize = sizeof(Metadata);
+ using SizeClassMap = DefaultSizeClassMap;
+ using MapUnmapCallback = DFsanMapUnmapCallback;
+ static const uptr kFlags = 0;
+ using AddressSpaceView = LocalAddressSpaceView;
+};
+#else
const uptr kMaxAllowedMallocSize = 1ULL << 40;
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
@@ -59,6 +74,7 @@ struct AP64 { // Allocator64 parameters. Deliberately using a short name.
using AddressSpaceView = LocalAddressSpaceView;
};
+#endif
typedef SizeClassAllocator64<AP64> PrimaryAllocator;
typedef CombinedAllocator<PrimaryAllocator> Allocator;
diff --git a/compiler-rt/lib/dfsan/dfsan_custom.cpp b/compiler-rt/lib/dfsan/dfsan_custom.cpp
index dbc00d7ac3ea3..b060e5c56edbe 100644
--- a/compiler-rt/lib/dfsan/dfsan_custom.cpp
+++ b/compiler-rt/lib/dfsan/dfsan_custom.cpp
@@ -2332,7 +2332,20 @@ static int format_buffer(char *str, size_t size, const char *fmt,
case 'g':
case 'G':
if (*(formatter.fmt_cur - 1) == 'L') {
+#if defined(__s390x__)
+ // SystemZ treats float128 argument as an aggregate type and copies
+ // shadow and Origin to passed argument temporary. But passed
+ // argument va_labels and va_origins are zero. Here. we get
+ // Shadow/Origin corresponding to in-memory argument and update
+ // va_labels and va_origins.
+ long double* arg = va_arg(ap, long double*);
+ *va_labels = *shadow_for(arg);
+ if (va_origins != nullptr)
+ *va_origins = *origin_for(arg);
+ retval = formatter.format(*arg);
+#else
retval = formatter.format(va_arg(ap, long double));
+#endif
} else {
retval = formatter.format(va_arg(ap, double));
}
diff --git a/compiler-rt/lib/dfsan/dfsan_platform.h b/compiler-rt/lib/dfsan/dfsan_platform.h
index 01f0de47d960d..7e6a1dafddb50 100644
--- a/compiler-rt/lib/dfsan/dfsan_platform.h
+++ b/compiler-rt/lib/dfsan/dfsan_platform.h
@@ -67,6 +67,20 @@ const MappingDesc kMemoryLayout[] = {
};
# define MEM_TO_SHADOW(mem) ((uptr)mem ^ 0xB00000000000ULL)
# define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x200000000000ULL)
+# elif SANITIZER_LINUX && SANITIZER_S390_64
+const MappingDesc kMemoryLayout[] = {
+ {0x000000000000ULL, 0x040000000000ULL, MappingDesc::APP, "low memory"},
+ {0x040000000000ULL, 0x080000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x080000000000ULL, 0x180000000000ULL, MappingDesc::SHADOW, "shadow"},
+ {0x180000000000ULL, 0x1C0000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x1C0000000000ULL, 0x2C0000000000ULL, MappingDesc::ORIGIN, "origin"},
+ {0x2C0000000000ULL, 0x440000000000ULL, MappingDesc::INVALID, "invalid"},
+ {0x440000000000ULL, 0x460000000000ULL, MappingDesc::ALLOCATOR, "allocator"},
+ {0x460000000000ULL, 0x500000000000ULL, MappingDesc::APP, "high memory"}};
+
+# define MEM_TO_SHADOW(mem) \
+ ((((uptr)(mem)) & ~0xC00000000000ULL) + 0x080000000000ULL)
+# define SHADOW_TO_ORIGIN(shadow) (((uptr)(shadow)) + 0x140000000000ULL)
# else
// All of the following configurations are supported.
diff --git a/compiler-rt/test/dfsan/custom.cpp b/compiler-rt/test/dfsan/custom.cpp
index 873af5cd934e2..b4d6b186cb61e 100644
--- a/compiler-rt/test/dfsan/custom.cpp
+++ b/compiler-rt/test/dfsan/custom.cpp
@@ -2240,7 +2240,7 @@ void test_sscanf() {
strcpy(input_buf, "-559038737");
test_sscanf_chunk(-559038737, "%d", input_ptr, 1);
strcpy(input_buf, "3735928559");
- test_sscanf_chunk(3735928559, "%u", input_ptr, 1);
+ test_sscanf_chunk(3735928559, "%lu", input_ptr, 1);
strcpy(input_buf, "12345");
test_sscanf_chunk(12345, "%i", input_ptr, 1);
strcpy(input_buf, "0751");
diff --git a/compiler-rt/test/dfsan/lit.cfg.py b/compiler-rt/test/dfsan/lit.cfg.py
index b26ff3e367942..1b4ca6a258bba 100644
--- a/compiler-rt/test/dfsan/lit.cfg.py
+++ b/compiler-rt/test/dfsan/lit.cfg.py
@@ -10,6 +10,8 @@
# Setup default compiler flags used with -fsanitize=dataflow option.
clang_dfsan_cflags = ["-fsanitize=dataflow"] + [config.target_cflags]
+if config.target_arch == "s390x":
+ clang_dfsan_cflags.append("-mbackchain")
clang_dfsan_cxxflags = config.cxx_mode_flags + clang_dfsan_cflags
@@ -25,5 +27,8 @@ def build_invocation(compile_flags):
config.suffixes = [".c", ".cpp"]
# DataFlowSanitizer tests are currently supported on Linux only.
-if not (config.target_os in ["Linux"] and config.target_arch in ["aarch64", "x86_64", "loongarch64"]):
+if not (
+ config.target_os in ["Linux"]
+ and config.target_arch in ["aarch64", "x86_64", "loongarch64", "s390x"]
+):
config.unsupported = True
diff --git a/compiler-rt/test/dfsan/origin_endianness.c b/compiler-rt/test/dfsan/origin_endianness.c
index a73dcda080e79..cd0b198017f57 100644
--- a/compiler-rt/test/dfsan/origin_endianness.c
+++ b/compiler-rt/test/dfsan/origin_endianness.c
@@ -16,10 +16,10 @@ __attribute__((noinline)) FULL_TYPE foo(FULL_TYPE a, FULL_TYPE b) {
int main(int argc, char *argv[]) {
FULL_TYPE a = 1;
FULL_TYPE b = 10;
- dfsan_set_label(4, (HALF_TYPE *)&a, sizeof(HALF_TYPE));
+ dfsan_set_label(4, (HALF_TYPE *)&a + 1, sizeof(HALF_TYPE));
FULL_TYPE c = foo(a, b);
dfsan_print_origin_trace(&c, NULL);
- dfsan_print_origin_trace((HALF_TYPE *)&c, NULL);
+ dfsan_print_origin_trace((HALF_TYPE *)&c + 1, NULL);
}
// CHECK: Taint value 0x4 {{.*}} origin tracking ()
diff --git a/compiler-rt/test/dfsan/pair.cpp b/compiler-rt/test/dfsan/pair.cpp
index 94bbfc72bc649..cb00339e81ec4 100644
--- a/compiler-rt/test/dfsan/pair.cpp
+++ b/compiler-rt/test/dfsan/pair.cpp
@@ -66,8 +66,10 @@ void test_simple_constructors() {
int *ptr1 = pair1.first;
#ifdef O0
- assert(dfsan_read_label(&i1, sizeof(i1)) == 10);
- assert(dfsan_read_label(&ptr1, sizeof(ptr1)) == 10);
+ assert(dfsan_read_label(&i1, sizeof(i1)) == 8 ||
+ dfsan_read_label(&i1, sizeof(i1)) == 10);
+ assert(dfsan_read_label(&ptr1, sizeof(ptr1)) == 2 ||
+ dfsan_read_label(&ptr1, sizeof(ptr1)) == 10);
#else
assert(dfsan_read_label(&i1, sizeof(i1)) == 8);
assert(dfsan_read_label(&ptr1, sizeof(ptr1)) == 2);
@@ -78,8 +80,10 @@ void test_simple_constructors() {
int *ptr2 = pair2.first;
#ifdef O0
- assert(dfsan_read_label(&i2, sizeof(i2)) == 10);
- assert(dfsan_read_label(&ptr2, sizeof(ptr2)) == 10);
+ assert(dfsan_read_label(&i2, sizeof(i2)) == 8 ||
+ dfsan_read_label(&i2, sizeof(i2)) == 10);
+ assert(dfsan_read_label(&ptr2, sizeof(ptr2)) == 2 ||
+ dfsan_read_label(&ptr2, sizeof(ptr2)) == 10);
#else
assert(dfsan_read_label(&i2, sizeof(i2)) == 8);
assert(dfsan_read_label(&ptr2, sizeof(ptr2)) == 2);
@@ -90,8 +94,10 @@ void test_simple_constructors() {
int *ptr3 = pair3.first;
#ifdef O0
- assert(dfsan_read_label(&i3, sizeof(i3)) == 10);
- assert(dfsan_read_label(&ptr3, sizeof(ptr3)) == 10);
+ assert(dfsan_read_label(&i3, sizeof(i3)) == 8 ||
+ dfsan_read_label(&i3, sizeof(i3)) == 10);
+ assert(dfsan_read_label(&ptr3, sizeof(ptr3)) == 2 ||
+ dfsan_read_label(&ptr3, sizeof(ptr3)) == 10);
#else
assert(dfsan_read_label(&i3, sizeof(i3)) == 8);
assert(dfsan_read_label(&ptr3, sizeof(ptr3)) == 2);
@@ -102,8 +108,10 @@ void test_simple_constructors() {
int *ptr4 = pair4.first;
#ifdef O0
- assert(dfsan_read_label(&i4, sizeof(i4)) == 10);
- assert(dfsan_read_label(&ptr4, sizeof(ptr4)) == 10);
+ assert(dfsan_read_label(&i4, sizeof(i4)) == 8 ||
+ dfsan_read_label(&i4, sizeof(i4)) == 10);
+ assert(dfsan_read_label(&ptr4, sizeof(ptr4)) == 2 ||
+ dfsan_read_label(&ptr4, sizeof(ptr4)) == 10);
#else
assert(dfsan_read_label(&i4, sizeof(i4)) == 8);
assert(dfsan_read_label(&ptr4, sizeof(ptr4)) == 2);
@@ -140,8 +148,10 @@ void test_branches() {
{
std::pair<const char *, uint32_t> r = return_ptr_and_i32(q, res);
#ifdef O0
- assert(dfsan_read_label(&r.first, sizeof(r.first)) == 10);
- assert(dfsan_read_label(&r.second, sizeof(r.second)) == 10);
+ assert(dfsan_read_label(&r.first, sizeof(r.first)) == 2 ||
+ dfsan_read_label(&r.first, sizeof(r.first)) == 10);
+ assert(dfsan_read_label(&r.second, sizeof(r.second)) == 8 ||
+ dfsan_read_label(&r.second, sizeof(r.second)) == 10);
#else
assert(dfsan_read_label(&r.first, sizeof(r.first)) == 2);
assert(dfsan_read_label(&r.second, sizeof(r.second)) == 8);
@@ -151,8 +161,10 @@ void test_branches() {
{
std::pair<const char *, uint64_t> r = return_ptr_and_i64(q, res);
#ifdef O0
- assert(dfsan_read_label(&r.first, sizeof(r.first)) == 10);
- assert(dfsan_read_label(&r.second, sizeof(r.second)) == 10);
+ assert(dfsan_read_label(&r.first, sizeof(r.first)) == 2 ||
+ dfsan_read_label(&r.first, sizeof(r.first)) == 10);
+ assert(dfsan_read_label(&r.second, sizeof(r.second)) == 8 ||
+ dfsan_read_label(&r.second, sizeof(r.second)) == 10);
#else
assert(dfsan_read_label(&r.first, sizeof(r.first)) == 2);
assert(dfsan_read_label(&r.second, sizeof(r.second)) == 8);
diff --git a/compiler-rt/test/dfsan/struct.c b/compiler-rt/test/dfsan/struct.c
index 7ba0016f7beee..48285e022a98a 100644
--- a/compiler-rt/test/dfsan/struct.c
+++ b/compiler-rt/test/dfsan/struct.c
@@ -48,8 +48,8 @@ int main(void) {
dfsan_label i1_label = dfsan_read_label(&i1, sizeof(i1));
dfsan_label ptr1_label = dfsan_read_label(&ptr1, sizeof(ptr1));
#if defined(O0)
- assert(i1_label == (i_label | ptr_label));
- assert(ptr1_label == (i_label | ptr_label));
+ assert(i1_label == i_label || i1_label == (i_label | ptr_label));
+ assert(ptr1_label == ptr_label || ptr1_label == (i_label | ptr_label));
#else
assert(i1_label == i_label);
assert(ptr1_label == ptr_label);
@@ -62,8 +62,8 @@ int main(void) {
dfsan_label i2_label = dfsan_read_label(&i2, sizeof(i2));
dfsan_label ptr2_label = dfsan_read_label(&ptr2, sizeof(ptr2));
#if defined(O0)
- assert(i2_label == (i_label | ptr_label));
- assert(ptr2_label == (i_label | ptr_label));
+ assert(i2_label == i_label || i2_label == (i_label | ptr_label));
+ assert(ptr2_label == ptr_label || ptr2_label == (i_label | ptr_label));
#else
assert(i2_label == i_label);
assert(ptr2_label == ptr_label);
@@ -76,8 +76,8 @@ int main(void) {
dfsan_label i3_label = dfsan_read_label(&i3, sizeof(i3));
dfsan_label ptr3_label = dfsan_read_label(&ptr3, sizeof(ptr3));
#if defined(O0)
- assert(i3_label == (i_label | ptr_label));
- assert(ptr3_label == (i_label | ptr_label));
+ assert(i3_label == i_label || i3_label == (i_label | ptr_label));
+ assert(ptr3_label == ptr_label || ptr3_label == (i_label | ptr_label));
#else
assert(i3_label == i_label);
assert(ptr3_label == ptr_label);
diff --git a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
index e984ac46fca4a..7f63bf6b4941f 100644
--- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
@@ -318,6 +318,14 @@ const MemoryMapParams Linux_LoongArch64_MemoryMapParams = {
0x100000000000, // OriginBase
};
+// s390x Linux
+const MemoryMapParams Linux_S390X_MemoryMapParams = {
+ 0xC00000000000, // AndMask
+ 0, // XorMask (not used)
+ 0x080000000000, // ShadowBase
+ 0x1C0000000000, // OriginBase
+};
+
namespace {
class DFSanABIList {
@@ -1146,6 +1154,9 @@ bool DataFlowSanitizer::initializeModule(Module &M) {
case Triple::loongarch64:
MapParams = &Linux_LoongArch64_MemoryMapParams;
break;
+ case Triple::systemz:
+ MapParams = &Linux_S390X_MemoryMapParams;
+ break;
default:
report_fatal_error("unsupported architecture");
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/168991
More information about the llvm-commits
mailing list