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
