https://github.com/kuroyukiasuna updated 
https://github.com/llvm/llvm-project/pull/210635

>From 177b29fd8f8ee2b637c5ba0d82f666807a1e5b9e Mon Sep 17 00:00:00 2001
From: Jerry Dang <[email protected]>
Date: Sun, 19 Jul 2026 15:23:30 -0400
Subject: [PATCH 1/2] Enable ubsan to detect undefined subtraction of two
 pointers

---
 clang/docs/ReleaseNotes.md                    |  4 +
 clang/docs/UndefinedBehaviorSanitizer.md      |  2 +
 clang/include/clang/Basic/Sanitizers.def      |  4 +-
 clang/lib/CodeGen/CGExprScalar.cpp            | 21 +++++
 clang/lib/CodeGen/SanitizerHandler.h          |  4 +
 clang/test/CodeGen/allow-ubsan-check.c        |  8 +-
 .../ubsan-unaligned-pointer-subtraction.c     | 84 +++++++++++++++++++
 clang/test/Driver/amdgpu-validate-sanitize.cl |  2 +-
 .../Driver/fsanitize-annotate-debug-info.c    |  6 +-
 clang/test/Driver/fsanitize-merge.c           |  6 +-
 clang/test/Driver/fsanitize-minimal-runtime.c |  8 +-
 clang/test/Driver/fsanitize-recover.c         |  2 +-
 clang/test/Driver/fsanitize-skip-hot-cutoff.c |  8 +-
 clang/test/Driver/fsanitize-trap.c            |  6 +-
 clang/test/Driver/fsanitize-undefined.c       | 10 +--
 clang/test/Driver/fsanitize.c                 |  4 +-
 compiler-rt/lib/ubsan/ubsan_checks.inc        |  2 +
 compiler-rt/lib/ubsan/ubsan_handlers.cpp      | 33 ++++++++
 compiler-rt/lib/ubsan/ubsan_handlers.h        |  9 ++
 compiler-rt/lib/ubsan/ubsan_interface.inc     |  2 +
 .../ubsan_minimal/ubsan_minimal_handlers.cpp  |  1 +
 .../Pointer/unaligned-pointer-subtraction.c   | 66 +++++++++++++++
 22 files changed, 261 insertions(+), 31 deletions(-)
 create mode 100644 clang/test/CodeGen/ubsan-unaligned-pointer-subtraction.c
 create mode 100644 
compiler-rt/test/ubsan/TestCases/Pointer/unaligned-pointer-subtraction.c

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index a02ecc41b2292..58d2f30d26bec 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -555,6 +555,10 @@ features cannot lower the translation-unit ABI level;
 
 ### Sanitizers
 
+- Introduced `-fsanitize=unaligned-pointer-subtraction`, a new 
UndefinedBehaviorSanitizer check that
+  flag subtraction of two pointers whose byte distance is not a multiple of 
the element size.
+  It is part of the `undefined` group.
+
 ### Python Binding Changes
 
 ### OpenMP Support
diff --git a/clang/docs/UndefinedBehaviorSanitizer.md 
b/clang/docs/UndefinedBehaviorSanitizer.md
index 25587c6e8cb3c..0a23b2a9d6aa5 100644
--- a/clang/docs/UndefinedBehaviorSanitizer.md
+++ b/clang/docs/UndefinedBehaviorSanitizer.md
@@ -173,6 +173,8 @@ Available checks are:
 - `-fsanitize=pointer-overflow`: Performing pointer arithmetic which
   overflows, or where either the old or new pointer value is a null pointer
   (excluding the case where both are null pointers).
+- `-fsanitize=unaligned-pointer-subtraction`: Subtraction of two pointers whose
+  byte distance is not a multiple of the element size.
 - `-fsanitize=return`: In C++, reaching the end of a
   value-returning function without returning a value.
 - `-fsanitize=returns-nonnull-attribute`: Returning null pointer
diff --git a/clang/include/clang/Basic/Sanitizers.def 
b/clang/include/clang/Basic/Sanitizers.def
index da85431625026..c58c28f9dc7eb 100644
--- a/clang/include/clang/Basic/Sanitizers.def
+++ b/clang/include/clang/Basic/Sanitizers.def
@@ -113,6 +113,7 @@ SANITIZER("shift-base", ShiftBase)
 SANITIZER("shift-exponent", ShiftExponent)
 SANITIZER_GROUP("shift", Shift, ShiftBase | ShiftExponent)
 SANITIZER("signed-integer-overflow", SignedIntegerOverflow)
+SANITIZER("unaligned-pointer-subtraction", UnalignedPointerSubtraction)
 SANITIZER("unreachable", Unreachable)
 SANITIZER("vla-bound", VLABound)
 SANITIZER("vptr", Vptr)
@@ -152,7 +153,8 @@ SANITIZER_GROUP("undefined", Undefined,
                     FloatCastOverflow |
                     IntegerDivideByZero | NonnullAttribute | Null | ObjectSize 
|
                     PointerOverflow | Return | ReturnsNonnullAttribute | Shift 
|
-                    SignedIntegerOverflow | Unreachable | VLABound | Function)
+                    SignedIntegerOverflow | Unreachable | VLABound | Function |
+                    UnalignedPointerSubtraction)
 
 // -fsanitize=undefined-trap is an alias for -fsanitize=undefined.
 SANITIZER_GROUP("undefined-trap", UndefinedTrap, Undefined)
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp 
b/clang/lib/CodeGen/CGExprScalar.cpp
index b54f3b9f22f0d..8356e0e55ee53 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -20,6 +20,7 @@
 #include "CodeGenFunction.h"
 #include "CodeGenModule.h"
 #include "ConstantEmitter.h"
+#include "SanitizerHandler.h"
 #include "TargetInfo.h"
 #include "TrapReasonBuilder.h"
 #include "clang/AST/ASTContext.h"
@@ -5023,6 +5024,26 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
 
   if (CGF.getLangOpts().StablePointerSubtraction)
     return Builder.CreateSDiv(diffInChars, divisor, "sub.ptr.div");
+  
+  // If the unaligned-pointer-subtraction sanitizer is on, verify at runtime
+  // that the byte distance is an exact multiple of the element size.
+  if (CGF.SanOpts.has(SanitizerKind::UnalignedPointerSubtraction)) {
+    auto checkOrdinal = SanitizerKind::SO_UnalignedPointerSubtraction;
+    auto CheckHandler = SanitizerHandler::UnalignedPointerSubtraction;
+    SanitizerDebugLocation SanScope(&CGF, {checkOrdinal}, CheckHandler);
+
+    llvm::Value *Zero = llvm::ConstantInt::get(CGF.PtrDiffTy, 0);
+    llvm::Value *Rem = Builder.CreateSRem(diffInChars, divisor, "sub.ptr.rem");
+    llvm::Value *IsExact = Builder.CreateICmpEQ(Rem, Zero, "sub.ptr.exact");
+
+    llvm::Constant *StaticArgs[] = {
+        CGF.EmitCheckSourceLocation(op.E->getExprLoc()),
+        CGF.EmitCheckTypeDescriptor(op.E->getType())};
+    llvm::Value *DynamicArgs[] = {diffInChars, divisor};
+    CGF.EmitCheck({{IsExact, checkOrdinal}}, CheckHandler, StaticArgs,
+                  DynamicArgs);
+  }
+
   // Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since
   // pointer difference in C is only defined in the case where both operands
   // are pointing to elements of an array.
diff --git a/clang/lib/CodeGen/SanitizerHandler.h 
b/clang/lib/CodeGen/SanitizerHandler.h
index 871e17c22d3fa..b39f4f22de48c 100644
--- a/clang/lib/CodeGen/SanitizerHandler.h
+++ b/clang/lib/CodeGen/SanitizerHandler.h
@@ -70,6 +70,10 @@
   SANITIZER_CHECK(                                                             
\
       VLABoundNotPositive, vla_bound_not_positive, 0,                          
\
       "Variable length array bound evaluates to non-positive value")           
\
+  SANITIZER_CHECK(                                                             
\
+      UnalignedPointerSubtraction, unaligned_pointer_subtraction, 0,           
\
+      "Pointer subtraction where the byte distance is not a multiple of the "  
\
+      "element size")                                                          
\
   SANITIZER_CHECK(BoundsSafety, bounds_safety, 0,                              
\
                   "") // BoundsSafety Msg is empty because it is not considered
                       // part of UBSan; therefore, no trap reason is emitted 
for
diff --git a/clang/test/CodeGen/allow-ubsan-check.c 
b/clang/test/CodeGen/allow-ubsan-check.c
index 0fc95c41b3e3d..beb6fbdcb3c41 100644
--- a/clang/test/CodeGen/allow-ubsan-check.c
+++ b/clang/test/CodeGen/allow-ubsan-check.c
@@ -200,7 +200,7 @@ void use(double*);
 // CHECK-NEXT:    call void @use(ptr noundef nonnull [[VLA]]) #[[ATTR7:[0-9]+]]
 // CHECK-NEXT:    [[IDXPROM:%.*]] = sext i32 [[I]] to i64
 // CHECK-NEXT:    [[TMP1:%.*]] = icmp ule i64 [[TMP0]], [[IDXPROM]]
-// CHECK-NEXT:    [[TMP2:%.*]] = call i1 @llvm.allow.ubsan.check(i8 71), 
!nosanitize [[META6]]
+// CHECK-NEXT:    [[TMP2:%.*]] = call i1 @llvm.allow.ubsan.check(i8 72), 
!nosanitize [[META6]]
 // CHECK-NEXT:    [[TMP3:%.*]] = and i1 [[TMP1]], [[TMP2]], !nosanitize 
[[META6]]
 // CHECK-NEXT:    br i1 [[TMP3]], label %[[TRAP:.*]], label %[[BB4:.*]]
 // CHECK:       [[BB4]]:
@@ -219,7 +219,7 @@ void use(double*);
 // TR-NEXT:    call void @use(ptr noundef nonnull [[VLA]]) #[[ATTR8:[0-9]+]]
 // TR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[I]] to i64
 // TR-NEXT:    [[TMP1:%.*]] = icmp ule i64 [[TMP0]], [[IDXPROM]]
-// TR-NEXT:    [[TMP2:%.*]] = call i1 @llvm.allow.ubsan.check(i8 71), 
!nosanitize [[META6]]
+// TR-NEXT:    [[TMP2:%.*]] = call i1 @llvm.allow.ubsan.check(i8 72), 
!nosanitize [[META6]]
 // TR-NEXT:    [[TMP3:%.*]] = and i1 [[TMP1]], [[TMP2]], !nosanitize [[META6]]
 // TR-NEXT:    br i1 [[TMP3]], label %[[TRAP:.*]], label %[[BB4:.*]]
 // TR:       [[BB4]]:
@@ -227,7 +227,7 @@ void use(double*);
 // TR-NEXT:    [[TMP5:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa 
[[DOUBLE_TBAA10:![0-9]+]]
 // TR-NEXT:    ret double [[TMP5]]
 // TR:       [[TRAP]]:
-// TR-NEXT:    call void @llvm.ubsantrap(i8 71) #[[ATTR7]], !nosanitize 
[[META6]]
+// TR-NEXT:    call void @llvm.ubsantrap(i8 72) #[[ATTR7]], !nosanitize 
[[META6]]
 // TR-NEXT:    unreachable, !nosanitize [[META6]]
 //
 // REC-LABEL: define dso_local double @lbounds(
@@ -238,7 +238,7 @@ void use(double*);
 // REC-NEXT:    call void @use(ptr noundef nonnull [[VLA]]) #[[ATTR5:[0-9]+]]
 // REC-NEXT:    [[IDXPROM:%.*]] = sext i32 [[I]] to i64
 // REC-NEXT:    [[TMP1:%.*]] = icmp ule i64 [[TMP0]], [[IDXPROM]]
-// REC-NEXT:    [[TMP2:%.*]] = call i1 @llvm.allow.ubsan.check(i8 71), 
!nosanitize [[META6]]
+// REC-NEXT:    [[TMP2:%.*]] = call i1 @llvm.allow.ubsan.check(i8 72), 
!nosanitize [[META6]]
 // REC-NEXT:    [[TMP3:%.*]] = and i1 [[TMP1]], [[TMP2]], !nosanitize [[META6]]
 // REC-NEXT:    br i1 [[TMP3]], label %[[TRAP:.*]], label %[[BB4:.*]]
 // REC:       [[BB4]]:
diff --git a/clang/test/CodeGen/ubsan-unaligned-pointer-subtraction.c 
b/clang/test/CodeGen/ubsan-unaligned-pointer-subtraction.c
new file mode 100644
index 0000000000000..08217f2f6eba3
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-unaligned-pointer-subtraction.c
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -x c -w -emit-llvm -o - %s 
\
+// RUN:     -fsanitize=unaligned-pointer-subtraction | \
+// RUN:     FileCheck %s --check-prefixes=CHECK,CONLY
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -x c++ -w -emit-llvm -o - 
%s \
+// RUN:     -fsanitize=unaligned-pointer-subtraction | \
+// RUN:     FileCheck %s
+//
+// Verify that -fsanitize=unaligned-pointer-subtraction instruments the
+// subtraction of two pointers: it checks at runtime that the byte distance is
+// an exact multiple of the element size, and skips the check when the element
+// size is one (where the remainder is trivially zero).
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct { int x, y; } A; // sizeof(A) == 8
+
+// Constant element size: the byte distance is divided by 8, so a check is
+// emitted before the exact division.
+// CHECK-LABEL: define{{.*}} i64 @f_const(
+long f_const(int *p) {
+  // CHECK:      %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast
+  // CHECK-NEXT: %sub.ptr.rem = srem i64 %sub.ptr.sub, 8, !nosanitize
+  // CHECK-NEXT: %sub.ptr.exact = icmp eq i64 %sub.ptr.rem, 0, !nosanitize
+  // CHECK-NEXT: br i1 %sub.ptr.exact, label %cont, label 
%handler.unaligned_pointer_subtraction{{.*}}, !nosanitize
+  // CHECK:      call void 
@__ubsan_handle_unaligned_pointer_subtraction{{.*}}(ptr @{{[0-9]+}}, i64 
%sub.ptr.sub, i64 8)
+  // CHECK:      %sub.ptr.div = sdiv exact i64 %sub.ptr.sub, 8
+  return (A *)(p + 1) - (A *)p;
+}
+
+// Element size one (char): no divide is emitted, so no check either.
+// CHECK-LABEL: define{{.*}} i64 @f_char(
+long f_char(char *a, char *b) {
+  // CHECK-NOT: srem
+  // CHECK-NOT: __ubsan_handle_unaligned_pointer_subtraction
+  // CHECK:     ret i64
+  return a - b;
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+// The remaining cases use pointer arithmetic that is only valid in C: VLA
+// element types and the GNU void*/function-pointer extensions. They are
+// compiled and checked only in the C RUN line (CONLY).
+#ifndef __cplusplus
+
+// VLA element type: the divisor is a runtime value (sizeof(int) * n), so the
+// remainder check runs against a non-constant divisor.
+// CONLY-LABEL: define{{.*}} i64 @f_vla(
+long f_vla(int n, int (*p)[n]) {
+  int (*q)[n] = (int (*)[n])((char *)p + 4);
+  // CONLY:      %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast
+  // CONLY-NEXT: %[[ELT:[0-9]+]] = mul nuw i64 4, %{{[0-9]+}}
+  // CONLY-NEXT: %sub.ptr.rem = srem i64 %sub.ptr.sub, %[[ELT]], !nosanitize
+  // CONLY-NEXT: %sub.ptr.exact = icmp eq i64 %sub.ptr.rem, 0, !nosanitize
+  // CONLY:      call void 
@__ubsan_handle_unaligned_pointer_subtraction{{.*}}(ptr @{{[0-9]+}}, i64 
%sub.ptr.sub, i64 %[[ELT]])
+  // CONLY:      %sub.ptr.div = sdiv exact i64 %sub.ptr.sub, %[[ELT]]
+  return q - p;
+}
+
+// void* arithmetic (GNU extension) has element size one: no check.
+// CONLY-LABEL: define{{.*}} i64 @f_void(
+long f_void(void *a, void *b) {
+  // CONLY-NOT: srem
+  // CONLY-NOT: __ubsan_handle_unaligned_pointer_subtraction
+  // CONLY:     ret i64
+  return a - b;
+}
+
+typedef void (*fp)(void);
+
+// Function-pointer arithmetic (GNU extension) has element size one: no check.
+// CONLY-LABEL: define{{.*}} i64 @f_func(
+long f_func(fp a, fp b) {
+  // CONLY-NOT: srem
+  // CONLY-NOT: __ubsan_handle_unaligned_pointer_subtraction
+  // CONLY:     ret i64
+  return a - b;
+}
+
+#endif // !__cplusplus
diff --git a/clang/test/Driver/amdgpu-validate-sanitize.cl 
b/clang/test/Driver/amdgpu-validate-sanitize.cl
index 907ad201b15b3..ddd80374cdfc4 100644
--- a/clang/test/Driver/amdgpu-validate-sanitize.cl
+++ b/clang/test/Driver/amdgpu-validate-sanitize.cl
@@ -33,7 +33,7 @@
 // CHECK-SAME: "-fsanitize=address"
 
 
-// GENERIC: 
"-fsanitize=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,nullability-arg,nullability-assign,nullability-return,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound,unsigned-integer-overflow,unsigned-shift-base,implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change,implicit-bitfield-conversion,local-bounds,alloc-token"
 
"-fsanitize-recover=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,nullability-arg,nullability-assign,nullability-return,pointer-overflow,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,vla-bound,unsigned-integer-overflow,unsigned-shift-base,implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change,implicit-bitfield-conversion"
 "-fsanitize-trap=local-bounds" 
"-fsanitize-merge=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
+// GENERIC: 
"-fsanitize=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,nullability-arg,nullability-assign,nullability-return,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unaligned-pointer-subtraction,unreachable,vla-bound,unsigned-integer-overflow,unsigned-shift-base,implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change,implicit-bitfield-conversion,local-bounds,alloc-token"
 
"-fsanitize-recover=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,float-divide-by-zero,function,integer-divide-by-zero,nonnull-attribute,null,nullability-arg,nullability-assign,nullability-return,pointer-overflow,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unaligned-pointer-subtraction,vla-bound,unsigned-integer-overflow,unsigned-shift-base,implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change,implicit-bitfield-conversion"
 "-fsanitize-trap=local-bounds" 
"-fsanitize-merge=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unaligned-pointer-subtraction,unreachable,vla-bound"
 
 
 // FIXME: Should not be forwarding argument
diff --git a/clang/test/Driver/fsanitize-annotate-debug-info.c 
b/clang/test/Driver/fsanitize-annotate-debug-info.c
index 27ffe950579d3..53ce753e53837 100644
--- a/clang/test/Driver/fsanitize-annotate-debug-info.c
+++ b/clang/test/Driver/fsanitize-annotate-debug-info.c
@@ -8,7 +8,7 @@
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined 
-fno-sanitize-annotate-debug-info=signed-integer-overflow 
-fsanitize-annotate-debug-info                                 %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined -fsanitize-annotate-debug-info=bool                   
    -fsanitize-annotate-debug-info=undefined                       %s -### 2>&1 
| FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined                                                       
     -fsanitize-annotate-debug-info=undefined 
-fsanitize-annotate-debug-info=bool %s -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-UNDEFINED-PSEUDO
-// CHECK-UNDEFINED-PSEUDO: 
"-fsanitize-annotate-debug-info=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
+// CHECK-UNDEFINED-PSEUDO: 
"-fsanitize-annotate-debug-info=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unaligned-pointer-subtraction,unreachable,vla-bound"
 
 // The trailing arguments (-fsanitize-annotate-debug-info 
-fno-sanitize-annotate-debug-info=signed-integer-overflow) take precedence
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined                                                       
     -fsanitize-annotate-debug-info           
-fno-sanitize-annotate-debug-info=signed-integer-overflow %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO2
@@ -17,7 +17,7 @@
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined -fno-sanitize-annotate-debug-info                     
    -fsanitize-annotate-debug-info=undefined 
-fno-sanitize-annotate-debug-info=signed-integer-overflow %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO2
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined 
-fno-sanitize-annotate-debug-info=signed-integer-overflow 
-fsanitize-annotate-debug-info           
-fno-sanitize-annotate-debug-info=signed-integer-overflow %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO2
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined 
-fno-sanitize-annotate-debug-info=signed-integer-overflow 
-fsanitize-annotate-debug-info=undefined 
-fno-sanitize-annotate-debug-info=signed-integer-overflow %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO2
-// CHECK-UNDEFINED-PSEUDO2: 
"-fsanitize-annotate-debug-info=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound"
+// CHECK-UNDEFINED-PSEUDO2: 
"-fsanitize-annotate-debug-info=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unaligned-pointer-subtraction,unreachable,vla-bound"
 
 // The trailing -fno-sanitize-annotate-debug-info takes precedence
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined                                           
-fno-sanitize-annotate-debug-info                                    %s -### 
2>&1 | not FileCheck %s --check-prefix=CHECK-UNDEFINED-PSEUDO3
@@ -37,7 +37,7 @@
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined -fno-sanitize-annotate-debug-info                     
    -fsanitize-annotate-debug-info=undefined 
-fno-sanitize-annotate-debug-info=alignment,null %s -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-UNDEFINED-PSEUDO4
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined 
-fno-sanitize-annotate-debug-info=signed-integer-overflow 
-fsanitize-annotate-debug-info           
-fno-sanitize-annotate-debug-info=alignment,null %s -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-UNDEFINED-PSEUDO4
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined 
-fno-sanitize-annotate-debug-info=signed-integer-overflow 
-fsanitize-annotate-debug-info=undefined 
-fno-sanitize-annotate-debug-info=alignment,null %s -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-UNDEFINED-PSEUDO4
-// CHECK-UNDEFINED-PSEUDO4: 
"-fsanitize-annotate-debug-info=array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
+// CHECK-UNDEFINED-PSEUDO4: 
"-fsanitize-annotate-debug-info=array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unaligned-pointer-subtraction,unreachable,vla-bound"
 
 // The trailing arguments (-fno-sanitize-annotate-debug-info 
-fsanitize-annotate-debug-info=alignment,null) take precedence
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined                                                       
  -fno-sanitize-annotate-debug-info=undefined 
-fsanitize-annotate-debug-info=alignment,null %s -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-UNDEFINED-PSEUDO5
diff --git a/clang/test/Driver/fsanitize-merge.c 
b/clang/test/Driver/fsanitize-merge.c
index 936da5bd34a80..93651248cb335 100644
--- a/clang/test/Driver/fsanitize-merge.c
+++ b/clang/test/Driver/fsanitize-merge.c
@@ -9,7 +9,7 @@
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined -fno-sanitize-merge=signed-integer-overflow 
-fsanitize-merge                                 %s -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-UNDEFINED-MERGE
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined -fsanitize-merge=bool                       
-fsanitize-merge=undefined                       %s -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-UNDEFINED-MERGE
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined                                             
-fsanitize-merge=undefined -fsanitize-merge=bool %s -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-UNDEFINED-MERGE
-// CHECK-UNDEFINED-MERGE: 
"-fsanitize-merge=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
+// CHECK-UNDEFINED-MERGE: 
"-fsanitize-merge=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unaligned-pointer-subtraction,unreachable,vla-bound"
 
 // The trailing arguments (-fsanitize-merge 
-fno-sanitize-merge=signed-integer-overflow) take precedence
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined                                                       
                 -fno-sanitize-merge=signed-integer-overflow %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE2
@@ -19,7 +19,7 @@
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined -fno-sanitize-merge                         
-fsanitize-merge=undefined -fno-sanitize-merge=signed-integer-overflow %s -### 
2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE2
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined -fno-sanitize-merge=signed-integer-overflow 
-fsanitize-merge           -fno-sanitize-merge=signed-integer-overflow %s -### 
2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE2
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined -fno-sanitize-merge=signed-integer-overflow 
-fsanitize-merge=undefined -fno-sanitize-merge=signed-integer-overflow %s -### 
2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE2
-// CHECK-UNDEFINED-MERGE2: 
"-fsanitize-merge=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound"
+// CHECK-UNDEFINED-MERGE2: 
"-fsanitize-merge=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unaligned-pointer-subtraction,unreachable,vla-bound"
 
 // The trailing -fno-sanitize-merge takes precedence
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined                            -fno-sanitize-merge        
                            %s -### 2>&1 | not FileCheck %s 
--check-prefix=CHECK-UNDEFINED-MERGE3
@@ -40,7 +40,7 @@
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined -fno-sanitize-merge                         
-fsanitize-merge=undefined -fno-sanitize-merge=alignment,null %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE4
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined -fno-sanitize-merge=signed-integer-overflow 
-fsanitize-merge           -fno-sanitize-merge=alignment,null %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE4
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined -fno-sanitize-merge=signed-integer-overflow 
-fsanitize-merge=undefined -fno-sanitize-merge=alignment,null %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE4
-// CHECK-UNDEFINED-MERGE4: 
"-fsanitize-merge=array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
+// CHECK-UNDEFINED-MERGE4: 
"-fsanitize-merge=array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unaligned-pointer-subtraction,unreachable,vla-bound"
 
 // The trailing arguments (-fno-sanitize-merge 
-fsanitize-merge=alignment,null) take precedence
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-trap=undefined                                          
-fno-sanitize-merge           -fsanitize-merge=alignment,null %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-UNDEFINED-MERGE5
diff --git a/clang/test/Driver/fsanitize-minimal-runtime.c 
b/clang/test/Driver/fsanitize-minimal-runtime.c
index 32714dfb806dd..60b834e9f4401 100644
--- a/clang/test/Driver/fsanitize-minimal-runtime.c
+++ b/clang/test/Driver/fsanitize-minimal-runtime.c
@@ -5,21 +5,21 @@
 // CHECK-TSAN-MINIMAL: error: invalid argument '-fsanitize-minimal-runtime' 
not allowed with '-fsanitize=thread'
 
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-minimal-runtime %s -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-UBSAN-MINIMAL
-// CHECK-UBSAN-MINIMAL: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}}
+// CHECK-UBSAN-MINIMAL: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|unaligned-pointer-subtraction),?){19}"}}
 // CHECK-UBSAN-MINIMAL: "-fsanitize-minimal-runtime"
 
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-minimal-runtime -fsanitize-handler-preserve-all-regs %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-UBSAN-MINIMAL-PRESERVE-X86-64
-// CHECK-UBSAN-MINIMAL-PRESERVE-X86-64: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}}
+// CHECK-UBSAN-MINIMAL-PRESERVE-X86-64: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|unaligned-pointer-subtraction),?){19}"}}
 // CHECK-UBSAN-MINIMAL-PRESERVE-X86-64: "-fsanitize-minimal-runtime"
 // CHECK-UBSAN-MINIMAL-PRESERVE-X86-64: "-fsanitize-handler-preserve-all-regs
 
 // RUN: %clang --target=aarch64-linux-gnu -fsanitize=undefined 
-fsanitize-minimal-runtime -fsanitize-handler-preserve-all-regs %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-UBSAN-MINIMAL-PRESERVE-AARCH64
-// CHECK-UBSAN-MINIMAL-PRESERVE-AARCH64: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}}
+// CHECK-UBSAN-MINIMAL-PRESERVE-AARCH64: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|unaligned-pointer-subtraction),?){19}"}}
 // CHECK-UBSAN-MINIMAL-PRESERVE-AARCH64: "-fsanitize-minimal-runtime"
 // CHECK-UBSAN-MINIMAL-PRESERVE-AARCH64: "-fsanitize-handler-preserve-all-regs
 
 // RUN: %clang --target=i386-linux-gnu -fsanitize=undefined 
-fsanitize-minimal-runtime -fsanitize-handler-preserve-all-regs %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-UBSAN-MINIMAL-PRESERVE-I386
-// CHECK-UBSAN-MINIMAL-PRESERVE-I386: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}}
+// CHECK-UBSAN-MINIMAL-PRESERVE-I386: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|unaligned-pointer-subtraction),?){19}"}}
 // CHECK-UBSAN-MINIMAL-PRESERVE-I386: "-fsanitize-minimal-runtime"
 // CHECK-UBSAN-MINIMAL-PRESERVE-I386-NOT: "-fsanitize-handler-preserve-all-regs
 
diff --git a/clang/test/Driver/fsanitize-recover.c 
b/clang/test/Driver/fsanitize-recover.c
index 2f2d793ddd379..dc15dbc975ce1 100644
--- a/clang/test/Driver/fsanitize-recover.c
+++ b/clang/test/Driver/fsanitize-recover.c
@@ -5,7 +5,7 @@
 // RUN: %clang --target=x86_64-linux-gnu %s -fsanitize=undefined 
-fno-sanitize-recover=undefined -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-NO-RECOVER-UBSAN
 // RUN: %clang --target=x86_64-linux-gnu %s -fsanitize=undefined 
-fno-sanitize-recover=all -fsanitize-recover=thread -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-NO-RECOVER-UBSAN
 // RUN: %clang --target=x86_64-linux-gnu %s -fsanitize=undefined 
-fsanitize-recover=all -fno-sanitize-recover=undefined -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-NO-RECOVER-UBSAN
-// CHECK-RECOVER-UBSAN: 
"-fsanitize-recover={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){16}"}}
+// CHECK-RECOVER-UBSAN: 
"-fsanitize-recover={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|unaligned-pointer-subtraction),?){17}"}}
 // CHECK-NO-RECOVER-UBSAN-NOT: -fsanitize-recover
 
 // RUN: %clang --target=x86_64-linux-gnu %s -fsanitize=undefined 
-fno-sanitize-recover=all -fsanitize-recover=object-size,shift-base -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-PARTIAL-RECOVER
diff --git a/clang/test/Driver/fsanitize-skip-hot-cutoff.c 
b/clang/test/Driver/fsanitize-skip-hot-cutoff.c
index 313ec69ca74d1..b763838a551bd 100644
--- a/clang/test/Driver/fsanitize-skip-hot-cutoff.c
+++ b/clang/test/Driver/fsanitize-skip-hot-cutoff.c
@@ -1,6 +1,6 @@
 // -fsanitize-skip-hot-cutoff=undefined=0.5
 // RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-skip-hot-cutoff=undefined=0.5 %s -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-SKIP-HOT-CUTOFF1
-// CHECK-SKIP-HOT-CUTOFF1: 
"-fsanitize-skip-hot-cutoff={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function)=0.5(0*),?){18}"}}
+// CHECK-SKIP-HOT-CUTOFF1: 
"-fsanitize-skip-hot-cutoff={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|unaligned-pointer-subtraction)=0.5(0*),?){19}"}}
 
 // No-op: no sanitizers are specified
 // RUN: %clang -Werror --target=x86_64-linux-gnu 
-fsanitize-skip-hot-cutoff=undefined=0.5 %s -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-SKIP-HOT-CUTOFF2
@@ -9,11 +9,11 @@
 
 // Enable undefined, then cancel out integer using a cutoff of 0.0
 // RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-skip-hot-cutoff=undefined=0.5,integer=0.0 %s -### 2>&1 | FileCheck 
%s --check-prefix=CHECK-SKIP-HOT-CUTOFF3
-// CHECK-SKIP-HOT-CUTOFF3: 
"-fsanitize-skip-hot-cutoff={{((unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function)=0.5(0*),?){14}"}}
+// CHECK-SKIP-HOT-CUTOFF3: 
"-fsanitize-skip-hot-cutoff={{((unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|unaligned-pointer-subtraction)=0.5(0*),?){15}"}}
 
 // Enable undefined, then cancel out integer using a cutoff of 0.0, then 
re-enable signed-integer-overflow
 // RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-skip-hot-cutoff=undefined=0.5,integer=0.0,signed-integer-overflow=0.7
 %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-SKIP-HOT-CUTOFF4
-// CHECK-SKIP-HOT-CUTOFF4: 
"-fsanitize-skip-hot-cutoff={{((signed-integer-overflow|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function)=0.[57]0*,?){15}"}}
+// CHECK-SKIP-HOT-CUTOFF4: 
"-fsanitize-skip-hot-cutoff={{((signed-integer-overflow|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|unaligned-pointer-subtraction)=0.[57]0*,?){16}"}}
 
 // Check that -fsanitize-skip-hot-cutoff=undefined=0.4 does not widen the set 
of -fsanitize=integer checks.
 // RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=integer 
-fsanitize-skip-hot-cutoff=undefined=0.4 %s -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-SKIP-HOT-CUTOFF5
@@ -21,7 +21,7 @@
 
 // No-op: it's allowed for the user to specify a cutoff of 0.0, though the 
argument is not passed along by the driver.
 // RUN: %clang -Werror --target=x86_64-linux-gnu -fsanitize=undefined 
-fsanitize-skip-hot-cutoff=undefined=0.0 %s -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-SKIP-HOT-CUTOFF6
-// CHECK-SKIP-HOT-CUTOFF6: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}}
+// CHECK-SKIP-HOT-CUTOFF6: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|unaligned-pointer-subtraction),?){19}"}}
 // CHECK-SKIP-HOT-CUTOFF6-NOT: "-fsanitize-skip-hot-cutoff"
 
 // Invalid: bad sanitizer
diff --git a/clang/test/Driver/fsanitize-trap.c 
b/clang/test/Driver/fsanitize-trap.c
index be13edeffdda0..6ee3480108f9d 100644
--- a/clang/test/Driver/fsanitize-trap.c
+++ b/clang/test/Driver/fsanitize-trap.c
@@ -5,6 +5,6 @@
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize-undefined-trap-on-error 
-fsanitize=undefined-trap %s -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-UNDEFINED-TRAP
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize-trap 
-fsanitize=undefined-trap %s -### 2>&1 | FileCheck %s 
--check-prefix=CHECK-UNDEFINED-TRAP
 // CHECK-UNDEFINED-TRAP-NOT: -fsanitize-recover
-// CHECK-UNDEFINED-TRAP: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}}
-// CHECK-UNDEFINED-TRAP: 
"-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unreachable,vla-bound"
-// CHECK-UNDEFINED-TRAP2: 
"-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unreachable,vla-bound"
+// CHECK-UNDEFINED-TRAP: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|unaligned-pointer-subtraction),?){19}"}}
+// CHECK-UNDEFINED-TRAP: 
"-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,signed-integer-overflow,unaligned-pointer-subtraction,unreachable,vla-bound"
+// CHECK-UNDEFINED-TRAP2: 
"-fsanitize-trap=alignment,array-bounds,bool,builtin,enum,float-cast-overflow,function,integer-divide-by-zero,nonnull-attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-base,shift-exponent,unaligned-pointer-subtraction,unreachable,vla-bound"
diff --git a/clang/test/Driver/fsanitize-undefined.c 
b/clang/test/Driver/fsanitize-undefined.c
index 13234a43e5074..e2e440ad6fa4a 100644
--- a/clang/test/Driver/fsanitize-undefined.c
+++ b/clang/test/Driver/fsanitize-undefined.c
@@ -1,11 +1,11 @@
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-UNDEFINED
-// CHECK-UNDEFINED: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){18}"}}
+// CHECK-UNDEFINED: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|unaligned-pointer-subtraction),?){19}"}}
 
 // RUN: %clang --target=x86_64-linux-gnu -fsanitize=thread,undefined 
-fno-sanitize=thread -fno-sanitize=float-cast-overflow,vptr,bool,builtin,enum 
%s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PARTIAL-UNDEFINED
-// CHECK-PARTIAL-UNDEFINED: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|array-bounds|returns-nonnull-attribute|nonnull-attribute),?){14}"}}
+// CHECK-PARTIAL-UNDEFINED: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|array-bounds|returns-nonnull-attribute|nonnull-attribute|unaligned-pointer-subtraction),?){15}"}}
 
 // RUN: %clang --target=x86_64-apple-darwin10 -fsanitize=undefined %s -### 
2>&1 | FileCheck %s --check-prefix=CHECK-UNDEFINED-DARWIN
-// CHECK-UNDEFINED-DARWIN: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){18}"}}
+// CHECK-UNDEFINED-DARWIN: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|unaligned-pointer-subtraction),?){19}"}}
 
 // RUN: %clang --target=i386-pc-win32 -fsanitize=undefined %s -### 2>&1 | 
FileCheck %s --check-prefixes=CHECK-UNDEFINED-WIN32,CHECK-UNDEFINED-MSVC
 // RUN: %clang --target=i386-pc-win32 -fsanitize=undefined -x c++ %s -### 2>&1 
| FileCheck %s 
--check-prefixes=CHECK-UNDEFINED-WIN32,CHECK-UNDEFINED-WIN-CXX,CHECK-UNDEFINED-MSVC
@@ -16,8 +16,8 @@
 // CHECK-UNDEFINED-WIN64: 
"--dependent-lib={{[^"]*}}ubsan_standalone{{(-x86_64)?}}.lib"
 // CHECK-UNDEFINED-WIN64-MINGW: 
"--dependent-lib={{[^"]*}}libclang_rt.ubsan_standalone{{(-x86_64)?}}.a"
 // CHECK-UNDEFINED-WIN-CXX: 
"--dependent-lib={{[^"]*}}ubsan_standalone_cxx{{[^"]*}}.lib"
-// CHECK-UNDEFINED-MSVC-SAME: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}}
-// CHECK-UNDEFINED-WIN64-MINGW-SAME: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}}
+// CHECK-UNDEFINED-MSVC-SAME: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|unaligned-pointer-subtraction),?){19}"}}
+// CHECK-UNDEFINED-WIN64-MINGW-SAME: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function|unaligned-pointer-subtraction),?){19}"}}
 
 // RUN: %clang --target=i386-pc-win32 -fsanitize-coverage=bb %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-COVERAGE-WIN32
 // CHECK-COVERAGE-WIN32: 
"--dependent-lib={{[^"]*}}ubsan_standalone{{(-i386)?}}.lib"
diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c
index f6a82d899d5bf..ffa0bbc880879 100644
--- a/clang/test/Driver/fsanitize.c
+++ b/clang/test/Driver/fsanitize.c
@@ -340,7 +340,7 @@
 // CHECK-ASAN-IOS: -fsanitize=address
 
 // RUN: %clang --target=i386-pc-openbsd -fsanitize=undefined %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-UBSAN-OPENBSD
-// CHECK-UBSAN-OPENBSD: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){18}"}}
+// CHECK-UBSAN-OPENBSD: 
"-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|function|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|unaligned-pointer-subtraction|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute),?){19}"}}
 
 // RUN: not %clang --target=i386-pc-openbsd -fsanitize=address %s -### 2>&1 | 
FileCheck %s --check-prefix=CHECK-ASAN-OPENBSD
 // CHECK-ASAN-OPENBSD: unsupported option '-fsanitize=address' for target 
'i386-pc-openbsd'
@@ -562,4 +562,4 @@
 // CHECK-UBSAN-FUNCTION-TARGET-DAG: error: unsupported option 
'-fsanitize=function' for target 'x86_64-sie-ps5'
 // CHECK-UBSAN-FUNCTION-MEXECUTE-ONLY-DAG: error: invalid argument 
'-fsanitize=function' not allowed with '-mexecute-only'
 // CHECK-UBSAN-FUNCTION-MPURE-CODE-DAG: error: invalid argument 
'-fsanitize=function' not allowed with '-mpure-code'
-// CHECK-UBSAN-UNDEFINED: 
"-fsanitize={{((alignment|array-bounds|bool|builtin|enum|float-cast-overflow|integer-divide-by-zero|nonnull-attribute|null|pointer-overflow|return|returns-nonnull-attribute|shift-base|shift-exponent|signed-integer-overflow|unreachable|vla-bound),?){17}"}}
+// CHECK-UBSAN-UNDEFINED: 
"-fsanitize={{((alignment|array-bounds|bool|builtin|enum|float-cast-overflow|integer-divide-by-zero|nonnull-attribute|null|pointer-overflow|return|returns-nonnull-attribute|shift-base|shift-exponent|signed-integer-overflow|unaligned-pointer-subtraction|unreachable|vla-bound),?){18}"}}
diff --git a/compiler-rt/lib/ubsan/ubsan_checks.inc 
b/compiler-rt/lib/ubsan/ubsan_checks.inc
index ebcd5df872d69..620e962767bfb 100644
--- a/compiler-rt/lib/ubsan/ubsan_checks.inc
+++ b/compiler-rt/lib/ubsan/ubsan_checks.inc
@@ -26,6 +26,8 @@ UBSAN_CHECK(NullptrWithNonZeroOffset, 
"nullptr-with-nonzero-offset",
 UBSAN_CHECK(NullptrAfterNonZeroOffset, "nullptr-after-nonzero-offset",
             "pointer-overflow")
 UBSAN_CHECK(PointerOverflow, "pointer-overflow", "pointer-overflow")
+UBSAN_CHECK(UnalignedPointerSubtraction, "unaligned-pointer-subtraction",
+            "unaligned-pointer-subtraction")
 UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use", "alignment")
 UBSAN_CHECK(AlignmentAssumption, "alignment-assumption", "alignment")
 UBSAN_CHECK(InsufficientObjectSize, "insufficient-object-size", "object-size")
diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.cpp 
b/compiler-rt/lib/ubsan/ubsan_handlers.cpp
index 0cd8a437adf4d..5c0fbb0f00ac9 100644
--- a/compiler-rt/lib/ubsan/ubsan_handlers.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_handlers.cpp
@@ -855,6 +855,39 @@ void 
__ubsan::__ubsan_handle_pointer_overflow_abort(PointerOverflowData *Data,
   Die();
 }
 
+static void
+handleUnalignedPointerSubtractionImpl(UnalignedPointerSubtractionData *Data,
+                                      ValueHandle Diff, ValueHandle EltSize,
+                                      ReportOptions Opts) {
+  SourceLocation Loc = Data->Loc.acquire();
+  ErrorType ET = ErrorType::UnalignedPointerSubtraction;
+
+  if (ignoreReport(Loc, Opts, ET))
+    return;
+
+  ScopedReport R(Opts, Loc, ET);
+
+  Diag(Loc, DL_Error, ET,
+       "pointer subtraction with byte distance %0 that is not a multiple of "
+       "the element size %1")
+      << Value(Data->Type, Diff) << (unsigned long long)EltSize;
+}
+
+void __ubsan::__ubsan_handle_unaligned_pointer_subtraction(
+    UnalignedPointerSubtractionData *Data, ValueHandle Diff,
+    ValueHandle EltSize) {
+  GET_REPORT_OPTIONS(false);
+  handleUnalignedPointerSubtractionImpl(Data, Diff, EltSize, Opts);
+}
+
+void __ubsan::__ubsan_handle_unaligned_pointer_subtraction_abort(
+    UnalignedPointerSubtractionData *Data, ValueHandle Diff,
+    ValueHandle EltSize) {
+  GET_REPORT_OPTIONS(true);
+  handleUnalignedPointerSubtractionImpl(Data, Diff, EltSize, Opts);
+  Die();
+}
+
 // Returns true if this is an artificial debug location created by the
 // LowerTypeTests pass (see createJumpTableDebugInfo in LLVM).
 static bool isArtificialStack(const SymbolizedStack *S) {
diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.h 
b/compiler-rt/lib/ubsan/ubsan_handlers.h
index 521caa96bc771..c41235327206d 100644
--- a/compiler-rt/lib/ubsan/ubsan_handlers.h
+++ b/compiler-rt/lib/ubsan/ubsan_handlers.h
@@ -208,6 +208,15 @@ struct PointerOverflowData {
 RECOVERABLE(pointer_overflow, PointerOverflowData *Data, ValueHandle Base,
             ValueHandle Result)
 
+struct UnalignedPointerSubtractionData {
+  SourceLocation Loc;
+  const TypeDescriptor &Type;
+};
+
+RECOVERABLE(unaligned_pointer_subtraction,
+            UnalignedPointerSubtractionData *Data, ValueHandle Diff,
+            ValueHandle EltSize)
+
 /// \brief Known CFI check kinds.
 /// Keep in sync with the enum of the same name in CodeGenFunction.h
 enum CFITypeCheckKind : unsigned char {
diff --git a/compiler-rt/lib/ubsan/ubsan_interface.inc 
b/compiler-rt/lib/ubsan/ubsan_interface.inc
index 7a9cb9b336f6e..3dbfbb0a4d0d2 100644
--- a/compiler-rt/lib/ubsan/ubsan_interface.inc
+++ b/compiler-rt/lib/ubsan/ubsan_interface.inc
@@ -56,6 +56,8 @@ INTERFACE_FUNCTION(__ubsan_handle_sub_overflow)
 INTERFACE_FUNCTION(__ubsan_handle_sub_overflow_abort)
 INTERFACE_FUNCTION(__ubsan_handle_type_mismatch_v1)
 INTERFACE_FUNCTION(__ubsan_handle_type_mismatch_v1_abort)
+INTERFACE_FUNCTION(__ubsan_handle_unaligned_pointer_subtraction)
+INTERFACE_FUNCTION(__ubsan_handle_unaligned_pointer_subtraction_abort)
 INTERFACE_FUNCTION(__ubsan_handle_vla_bound_not_positive)
 INTERFACE_FUNCTION(__ubsan_handle_vla_bound_not_positive_abort)
 INTERFACE_WEAK_FUNCTION(__ubsan_default_options)
diff --git a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp 
b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp
index e68e494564cc8..400f733cfa633 100644
--- a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp
+++ b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp
@@ -227,4 +227,5 @@ HANDLER(nonnull_return, "nonnull-return")
 HANDLER(nullability_arg, "nullability-arg")
 HANDLER(nullability_return, "nullability-return")
 HANDLER(pointer_overflow, "pointer-overflow")
+HANDLER(unaligned_pointer_subtraction, "unaligned-pointer-subtraction")
 HANDLER(cfi_check_fail, "cfi-check-fail")
diff --git 
a/compiler-rt/test/ubsan/TestCases/Pointer/unaligned-pointer-subtraction.c 
b/compiler-rt/test/ubsan/TestCases/Pointer/unaligned-pointer-subtraction.c
new file mode 100644
index 0000000000000..7eace9910881a
--- /dev/null
+++ b/compiler-rt/test/ubsan/TestCases/Pointer/unaligned-pointer-subtraction.c
@@ -0,0 +1,66 @@
+// Check that -fsanitize=unaligned-pointer-subtraction reports, at runtime, a
+// subtraction of two pointers whose byte distance is not an exact multiple of
+// the element size (i.e. the operands do not point into the same array).
+//
+// RUN: %clang -fsanitize=unaligned-pointer-subtraction %s -o %t
+// RUN: %run %t a 2>&1 | FileCheck %s --check-prefix=CONST
+// RUN: %run %t n 2>&1 | FileCheck %s --check-prefix=NEG
+// RUN: %run %t v 2>&1 | FileCheck %s --check-prefix=VLA
+// RUN: %run %t o 2>&1 | FileCheck %s --check-prefix=SAFE 
--implicit-check-not="runtime error:"
+//
+// Fatal (non-recoverable) mode aborts after the first report.
+// RUN: %clang -fsanitize=unaligned-pointer-subtraction \
+// RUN:     -fno-sanitize-recover=unaligned-pointer-subtraction %s -o %t.abort
+// RUN: not %run %t.abort a 2>&1 | FileCheck %s --check-prefix=ABORT
+
+#include <stdio.h>
+
+typedef struct {
+  int x, y;
+} A; // sizeof(A) == 8
+
+// Constant element size: byte distance 4 is not a multiple of 8.
+__attribute__((noinline)) long sub_const(int *p) {
+  return (A *)(p + 1) - (A *)p;
+}
+
+// Negative distance: exercises signed formatting of the reported distance.
+__attribute__((noinline)) long sub_negative(int *p) {
+  return (A *)p - (A *)(p + 1);
+}
+
+// VLA element type: the element size (sizeof(int) * n) is a runtime value.
+__attribute__((noinline)) long sub_vla(int n, int (*p)[n]) {
+  int(*q)[n] = (int(*)[n])((char *)p + 4);
+  return q - p;
+}
+
+// Valid subtraction: byte distance 8 is a multiple of 8, so no report.
+__attribute__((noinline)) long sub_ok(int *p) { return (A *)(p + 2) - (A *)p; }
+
+// CONST: runtime error: pointer subtraction with byte distance 4 that is not 
a multiple of the element size 8
+// NEG: runtime error: pointer subtraction with byte distance -4 that is not a 
multiple of the element size 8
+// VLA: runtime error: pointer subtraction with byte distance 4 that is not a 
multiple of the element size 12
+// ABORT: runtime error: pointer subtraction with byte distance 4 that is not 
a multiple of the element size 8
+// SAFE: r=1
+int main(int argc, char **argv) {
+  static int a[8];
+  char c = argc > 1 ? argv[1][0] : 'a';
+  long r = 0;
+  switch (c) {
+  case 'a':
+    r = sub_const(a);
+    break;
+  case 'n':
+    r = sub_negative(a);
+    break;
+  case 'v':
+    r = sub_vla(3, (int(*)[3])a);
+    break;
+  case 'o':
+    r = sub_ok(a);
+    break;
+  }
+  printf("r=%ld\n", r);
+  return 0;
+}

>From 80c6dbb575865eb4768d4222475e1cb44ba89edc Mon Sep 17 00:00:00 2001
From: Jerry Dang <[email protected]>
Date: Wed, 5 Aug 2026 20:47:04 -0400
Subject: [PATCH 2/2] clang-format

---
 clang/lib/CodeGen/CGExprScalar.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGExprScalar.cpp 
b/clang/lib/CodeGen/CGExprScalar.cpp
index 8356e0e55ee53..fb9ace4ea191e 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -5024,7 +5024,7 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) {
 
   if (CGF.getLangOpts().StablePointerSubtraction)
     return Builder.CreateSDiv(diffInChars, divisor, "sub.ptr.div");
-  
+
   // If the unaligned-pointer-subtraction sanitizer is on, verify at runtime
   // that the byte distance is an exact multiple of the element size.
   if (CGF.SanOpts.has(SanitizerKind::UnalignedPointerSubtraction)) {

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to