-
Notifications
You must be signed in to change notification settings - Fork 15.2k
Dataflow Sanitizer support for SystemZ. #162195
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
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-compiler-rt-sanitizer @llvm/pr-subscribers-llvm-transforms Author: None (anoopkg6) ChangesAdd Dataflow Sanitizer support for SystemZ. Full diff: https://github.com/llvm/llvm-project/pull/162195.diff 10 Files Affected:
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index 8ac8d4eb91812..6c04b36354dcf 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -819,7 +819,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 e947c51f99a5b..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.host_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/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 61fef1387d82a..64b3f5c812b3b 100644
--- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
@@ -313,6 +313,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 {
@@ -1141,6 +1149,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");
}
@@ -1951,8 +1962,12 @@ Value *DataFlowSanitizer::getShadowAddress(Value *Addr,
Value *DataFlowSanitizer::getShadowAddress(Value *Addr,
BasicBlock::iterator Pos) {
IRBuilder<> IRB(Pos->getParent(), Pos);
- Value *ShadowOffset = getShadowOffset(Addr, IRB);
- return getShadowAddress(Addr, Pos, ShadowOffset);
+ Value *ShadowAddr = getShadowOffset(Addr, IRB);
+ uint64_t ShadowBase = MapParams->ShadowBase;
+ if (ShadowBase != 0)
+ ShadowAddr =
+ IRB.CreateAdd(ShadowAddr, ConstantInt::get(IntptrTy, ShadowBase));
+ return getShadowAddress(Addr, Pos, ShadowAddr);
}
Value *DFSanFunction::combineShadowsThenConvert(Type *T, Value *V1, Value *V2,
@@ -2181,8 +2196,14 @@ std::pair<Value *, Value *> DFSanFunction::loadShadowFast(
// and then the entire shadow for the second origin pointer (which will be
// chosen by combineOrigins() iff the least-significant half of the wide
// shadow was empty but the other half was not).
- Value *WideShadowLo = IRB.CreateShl(
- WideShadow, ConstantInt::get(WideShadowTy, WideShadowBitWidth / 2));
+ Value *WideShadowLo =
+ F->getParent()->getDataLayout().isLittleEndian()
+ ? IRB.CreateShl(
+ WideShadow,
+ ConstantInt::get(WideShadowTy, WideShadowBitWidth / 2))
+ : IRB.CreateAnd(
+ WideShadow,
+ ConstantInt::get(WideShadowTy, 0xFFFFFFFF00000000ULL));
Shadows.push_back(WideShadow);
Origins.push_back(DFS.loadNextOrigin(Pos, OriginAlign, &OriginAddr));
|
@llvm/pr-subscribers-clang Author: None (anoopkg6) ChangesAdd Dataflow Sanitizer support for SystemZ. Full diff: https://github.com/llvm/llvm-project/pull/162195.diff 10 Files Affected:
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index 8ac8d4eb91812..6c04b36354dcf 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -819,7 +819,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 e947c51f99a5b..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.host_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/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 61fef1387d82a..64b3f5c812b3b 100644
--- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
@@ -313,6 +313,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 {
@@ -1141,6 +1149,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");
}
@@ -1951,8 +1962,12 @@ Value *DataFlowSanitizer::getShadowAddress(Value *Addr,
Value *DataFlowSanitizer::getShadowAddress(Value *Addr,
BasicBlock::iterator Pos) {
IRBuilder<> IRB(Pos->getParent(), Pos);
- Value *ShadowOffset = getShadowOffset(Addr, IRB);
- return getShadowAddress(Addr, Pos, ShadowOffset);
+ Value *ShadowAddr = getShadowOffset(Addr, IRB);
+ uint64_t ShadowBase = MapParams->ShadowBase;
+ if (ShadowBase != 0)
+ ShadowAddr =
+ IRB.CreateAdd(ShadowAddr, ConstantInt::get(IntptrTy, ShadowBase));
+ return getShadowAddress(Addr, Pos, ShadowAddr);
}
Value *DFSanFunction::combineShadowsThenConvert(Type *T, Value *V1, Value *V2,
@@ -2181,8 +2196,14 @@ std::pair<Value *, Value *> DFSanFunction::loadShadowFast(
// and then the entire shadow for the second origin pointer (which will be
// chosen by combineOrigins() iff the least-significant half of the wide
// shadow was empty but the other half was not).
- Value *WideShadowLo = IRB.CreateShl(
- WideShadow, ConstantInt::get(WideShadowTy, WideShadowBitWidth / 2));
+ Value *WideShadowLo =
+ F->getParent()->getDataLayout().isLittleEndian()
+ ? IRB.CreateShl(
+ WideShadow,
+ ConstantInt::get(WideShadowTy, WideShadowBitWidth / 2))
+ : IRB.CreateAnd(
+ WideShadow,
+ ConstantInt::get(WideShadowTy, 0xFFFFFFFF00000000ULL));
Shadows.push_back(WideShadow);
Origins.push_back(DFS.loadNextOrigin(Pos, OriginAlign, &OriginAddr));
|
@llvm/pr-subscribers-clang-driver Author: None (anoopkg6) ChangesAdd Dataflow Sanitizer support for SystemZ. Full diff: https://github.com/llvm/llvm-project/pull/162195.diff 10 Files Affected:
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index 8ac8d4eb91812..6c04b36354dcf 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -819,7 +819,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 e947c51f99a5b..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.host_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/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 61fef1387d82a..64b3f5c812b3b 100644
--- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
@@ -313,6 +313,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 {
@@ -1141,6 +1149,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");
}
@@ -1951,8 +1962,12 @@ Value *DataFlowSanitizer::getShadowAddress(Value *Addr,
Value *DataFlowSanitizer::getShadowAddress(Value *Addr,
BasicBlock::iterator Pos) {
IRBuilder<> IRB(Pos->getParent(), Pos);
- Value *ShadowOffset = getShadowOffset(Addr, IRB);
- return getShadowAddress(Addr, Pos, ShadowOffset);
+ Value *ShadowAddr = getShadowOffset(Addr, IRB);
+ uint64_t ShadowBase = MapParams->ShadowBase;
+ if (ShadowBase != 0)
+ ShadowAddr =
+ IRB.CreateAdd(ShadowAddr, ConstantInt::get(IntptrTy, ShadowBase));
+ return getShadowAddress(Addr, Pos, ShadowAddr);
}
Value *DFSanFunction::combineShadowsThenConvert(Type *T, Value *V1, Value *V2,
@@ -2181,8 +2196,14 @@ std::pair<Value *, Value *> DFSanFunction::loadShadowFast(
// and then the entire shadow for the second origin pointer (which will be
// chosen by combineOrigins() iff the least-significant half of the wide
// shadow was empty but the other half was not).
- Value *WideShadowLo = IRB.CreateShl(
- WideShadow, ConstantInt::get(WideShadowTy, WideShadowBitWidth / 2));
+ Value *WideShadowLo =
+ F->getParent()->getDataLayout().isLittleEndian()
+ ? IRB.CreateShl(
+ WideShadow,
+ ConstantInt::get(WideShadowTy, WideShadowBitWidth / 2))
+ : IRB.CreateAnd(
+ WideShadow,
+ ConstantInt::get(WideShadowTy, 0xFFFFFFFF00000000ULL));
Shadows.push_back(WideShadow);
Origins.push_back(DFS.loadNextOrigin(Pos, OriginAlign, &OriginAddr));
|
static const uptr kFlags = 0; | ||
using AddressSpaceView = LocalAddressSpaceView; | ||
}; | ||
#else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the allocator and shadow constants are the tried-and-tested constants from MSan (i.e. those don't need thorough review)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right. All memory map parameters are taken from tested MSan.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to land these two improvements in separate patch(es):
- Add support for non-zero shadow base in getShadowAddress()
- Big-endian support for wide shadows in loadShadowFast()
since they are general fixes, used for but not specific to SystemZ support.
Add Dataflow Sanitizer support for SystemZ.