diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index 16e35b08cfbd6..0a11f9605b755 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 PrimaryAllocator; typedef CombinedAllocator 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/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 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 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 480ff4a8c3cb9..c2e4178d2c33e 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 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));