Index: include/clang/Basic/Sanitizers.def =================================================================== --- include/clang/Basic/Sanitizers.def +++ include/clang/Basic/Sanitizers.def @@ -40,6 +40,12 @@ // AddressSanitizer SANITIZER("address", Address) +// Requires AddressSanitizer +SANITIZER("pointer-compare", PointerCompare) + +// Requires AddressSanitizer +SANITIZER("pointer-subtract", PointerSubtract) + // Kernel AddressSanitizer (KASan) SANITIZER("kernel-address", KernelAddress) Index: lib/CodeGen/BackendUtil.cpp =================================================================== --- lib/CodeGen/BackendUtil.cpp +++ lib/CodeGen/BackendUtil.cpp @@ -238,12 +238,17 @@ static_cast(Builder); const Triple &T = BuilderWrapper.getTargetTriple(); const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts(); + const clang::LangOptions &LangOpts = BuilderWrapper.getLangOpts(); bool Recover = CGOpts.SanitizeRecover.has(SanitizerKind::Address); bool UseAfterScope = CGOpts.SanitizeAddressUseAfterScope; bool UseOdrIndicator = CGOpts.SanitizeAddressUseOdrIndicator; + bool InvalidPointerCmp = LangOpts.Sanitize.has(SanitizerKind::PointerCompare); + bool InvalidPointerSub = + LangOpts.Sanitize.has(SanitizerKind::PointerSubtract); bool UseGlobalsGC = asanUseGlobalsGC(T, CGOpts); PM.add(createAddressSanitizerFunctionPass(/*CompileKernel*/ false, Recover, - UseAfterScope)); + UseAfterScope, InvalidPointerCmp, + InvalidPointerSub)); PM.add(createModuleAddressSanitizerLegacyPassPass( /*CompileKernel*/ false, Recover, UseGlobalsGC, UseOdrIndicator)); } @@ -940,9 +945,11 @@ if (LangOpts.Sanitize.has(SanitizerKind::Address)) { MPM.addPass(RequireAnalysisPass()); bool Recover = CodeGenOpts.SanitizeRecover.has(SanitizerKind::Address); - MPM.addPass(createModuleToFunctionPassAdaptor( - AddressSanitizerPass(/*CompileKernel=*/false, Recover, - CodeGenOpts.SanitizeAddressUseAfterScope))); + MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass( + /*CompileKernel=*/false, Recover, + CodeGenOpts.SanitizeAddressUseAfterScope, + LangOpts.Sanitize.has(SanitizerKind::PointerCompare), + LangOpts.Sanitize.has(SanitizerKind::PointerSubtract)))); bool ModuleUseAfterScope = asanUseGlobalsGC(TargetTriple, CodeGenOpts); MPM.addPass(ModuleAddressSanitizerPass( /*CompileKernel=*/false, Recover, ModuleUseAfterScope, @@ -1118,11 +1125,18 @@ }); bool Recover = CodeGenOpts.SanitizeRecover.has(SanitizerKind::Address); bool UseAfterScope = CodeGenOpts.SanitizeAddressUseAfterScope; + bool InvalidPointerCmp = + LangOpts.Sanitize.has(SanitizerKind::PointerCompare); + bool InvalidPointerSub = + LangOpts.Sanitize.has(SanitizerKind::PointerSubtract); + PB.registerOptimizerLastEPCallback( - [Recover, UseAfterScope](FunctionPassManager &FPM, - PassBuilder::OptimizationLevel Level) { + [Recover, UseAfterScope, InvalidPointerCmp, + InvalidPointerSub](FunctionPassManager &FPM, + PassBuilder::OptimizationLevel Level) { FPM.addPass(AddressSanitizerPass( - /*CompileKernel=*/false, Recover, UseAfterScope)); + /*CompileKernel=*/false, Recover, UseAfterScope, + InvalidPointerCmp, InvalidPointerSub)); }); bool ModuleUseAfterScope = asanUseGlobalsGC(TargetTriple, CodeGenOpts); bool UseOdrIndicator = CodeGenOpts.SanitizeAddressUseOdrIndicator; Index: lib/Driver/SanitizerArgs.cpp =================================================================== --- lib/Driver/SanitizerArgs.cpp +++ lib/Driver/SanitizerArgs.cpp @@ -783,6 +783,16 @@ AsanUseOdrIndicator); } else { AsanUseAfterScope = false; + // -fsanitize=pointer-compare/pointer-subtract requires -fsanitize=address. + SanitizerMask DetectInvalidPointerPairs = + SanitizerKind::PointerCompare | SanitizerKind::PointerSubtract; + if (AllAddedKinds & DetectInvalidPointerPairs & ~AllRemove) { + TC.getDriver().Diag(clang::diag::err_drv_argument_only_allowed_with) + << lastArgumentForMask(D, Args, + SanitizerKind::PointerCompare | + SanitizerKind::PointerSubtract) + << "-fsanitize=address"; + } } if (AllAddedKinds & SanitizerKind::HWAddress) { Index: lib/Driver/ToolChains/CrossWindows.cpp =================================================================== --- lib/Driver/ToolChains/CrossWindows.cpp +++ lib/Driver/ToolChains/CrossWindows.cpp @@ -277,6 +277,8 @@ clang::SanitizerMask CrossWindowsToolChain::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; + Res |= SanitizerKind::PointerCompare; + Res |= SanitizerKind::PointerSubtract; return Res; } Index: lib/Driver/ToolChains/Darwin.cpp =================================================================== --- lib/Driver/ToolChains/Darwin.cpp +++ lib/Driver/ToolChains/Darwin.cpp @@ -2360,6 +2360,8 @@ const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; + Res |= SanitizerKind::PointerCompare; + Res |= SanitizerKind::PointerSubtract; Res |= SanitizerKind::Leak; Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::FuzzerNoLink; Index: lib/Driver/ToolChains/FreeBSD.cpp =================================================================== --- lib/Driver/ToolChains/FreeBSD.cpp +++ lib/Driver/ToolChains/FreeBSD.cpp @@ -410,6 +410,8 @@ const bool IsMIPS64 = getTriple().isMIPS64(); SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; + Res |= SanitizerKind::PointerCompare; + Res |= SanitizerKind::PointerSubtract; Res |= SanitizerKind::Vptr; if (IsX86_64 || IsMIPS64) { Res |= SanitizerKind::Leak; Index: lib/Driver/ToolChains/Fuchsia.cpp =================================================================== --- lib/Driver/ToolChains/Fuchsia.cpp +++ lib/Driver/ToolChains/Fuchsia.cpp @@ -283,6 +283,8 @@ SanitizerMask Fuchsia::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; + Res |= SanitizerKind::PointerCompare; + Res |= SanitizerKind::PointerSubtract; Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::FuzzerNoLink; Res |= SanitizerKind::SafeStack; Index: lib/Driver/ToolChains/Linux.cpp =================================================================== --- lib/Driver/ToolChains/Linux.cpp +++ lib/Driver/ToolChains/Linux.cpp @@ -992,6 +992,8 @@ getTriple().getArch() == llvm::Triple::thumbeb; SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; + Res |= SanitizerKind::PointerCompare; + Res |= SanitizerKind::PointerSubtract; Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::FuzzerNoLink; Res |= SanitizerKind::KernelAddress; Index: lib/Driver/ToolChains/MSVC.cpp =================================================================== --- lib/Driver/ToolChains/MSVC.cpp +++ lib/Driver/ToolChains/MSVC.cpp @@ -1317,6 +1317,8 @@ SanitizerMask MSVCToolChain::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; + Res |= SanitizerKind::PointerCompare; + Res |= SanitizerKind::PointerSubtract; Res |= SanitizerKind::Fuzzer; Res |= SanitizerKind::FuzzerNoLink; Res &= ~SanitizerKind::CFIMFCall; Index: lib/Driver/ToolChains/MinGW.cpp =================================================================== --- lib/Driver/ToolChains/MinGW.cpp +++ lib/Driver/ToolChains/MinGW.cpp @@ -459,6 +459,8 @@ SanitizerMask toolchains::MinGW::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; + Res |= SanitizerKind::PointerCompare; + Res |= SanitizerKind::PointerSubtract; return Res; } Index: lib/Driver/ToolChains/NetBSD.cpp =================================================================== --- lib/Driver/ToolChains/NetBSD.cpp +++ lib/Driver/ToolChains/NetBSD.cpp @@ -463,6 +463,8 @@ SanitizerMask Res = ToolChain::getSupportedSanitizers(); if (IsX86 || IsX86_64) { Res |= SanitizerKind::Address; + Res |= SanitizerKind::PointerCompare; + Res |= SanitizerKind::PointerSubtract; Res |= SanitizerKind::Function; Res |= SanitizerKind::Leak; Res |= SanitizerKind::SafeStack; Index: lib/Driver/ToolChains/PS4CPU.cpp =================================================================== --- lib/Driver/ToolChains/PS4CPU.cpp +++ lib/Driver/ToolChains/PS4CPU.cpp @@ -425,6 +425,8 @@ SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; + Res |= SanitizerKind::PointerCompare; + Res |= SanitizerKind::PointerSubtract; Res |= SanitizerKind::Vptr; return Res; } Index: lib/Driver/ToolChains/Solaris.cpp =================================================================== --- lib/Driver/ToolChains/Solaris.cpp +++ lib/Driver/ToolChains/Solaris.cpp @@ -199,6 +199,8 @@ // FIXME: Omit X86_64 until 64-bit support is figured out. if (IsX86) { Res |= SanitizerKind::Address; + Res |= SanitizerKind::PointerCompare; + Res |= SanitizerKind::PointerSubtract; } Res |= SanitizerKind::Vptr; return Res; Index: test/Driver/fsanitize.c =================================================================== --- test/Driver/fsanitize.c +++ test/Driver/fsanitize.c @@ -884,3 +884,14 @@ // CHECK-HWASAN-INTERCEPTOR-ABI: "-default-function-attr" "hwasan-abi=interceptor" // CHECK-HWASAN-PLATFORM-ABI: "-default-function-attr" "hwasan-abi=platform" // CHECK-HWASAN-FOO-ABI: error: invalid value 'foo' in '-fsanitize-hwaddress-abi=foo' + +// RUN: %clang -target x86_64-linux-gnu -fsanitize=address,pointer-compare,pointer-subtract %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-POINTER-ALL +// RUN: %clang -target x86_64-linux-gnu -fsanitize=pointer-compare %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-POINTER-CMP-NEEDS-ADDRESS +// RUN: %clang -target x86_64-linux-gnu -fsanitize=pointer-subtract %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-POINTER-SUB-NEEDS-ADDRESS +// RUN: %clang -target x86_64-linux-gnu -fsanitize=pointer-subtract -fno-sanitize=pointer-subtract %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-POINTER-SUB +// RUN: %clang -target x86_64-linux-gnu -fsanitize=pointer-compare -fno-sanitize=pointer-compare %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-POINTER-CMP +// CHECK-POINTER-ALL: "-cc1{{.*}}-fsanitize={{.*}}pointer-compare,pointer-subtract{{.*}}" +// CHECK-POINTER-CMP-NEEDS-ADDRESS: error: invalid argument '-fsanitize=pointer-compare' only allowed with '-fsanitize=address' +// CHECK-POINTER-SUB-NEEDS-ADDRESS: error: invalid argument '-fsanitize=pointer-subtract' only allowed with '-fsanitize=address' +// CHECK-NO-POINTER-SUB-NOT: "{{.*}}-fsanitize{{.*}}" +// CHECK-NO-POINTER-CMP-NOT: "{{.*}}-fsanitize{{.*}}"