Skip to content

[cfi] Enable -fsanitize-annotate-debug-info functionality for CFI checks #139809

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
May 19, 2025

Conversation

thurstond
Copy link
Contributor

@thurstond thurstond commented May 13, 2025

This connects the -fsanitize-annotate-debug-info plumbing (#138577) to CFI check codegen, using SanitizerAnnotateDebugInfo() (#139965) and SanitizerInfoFromCFIKind (#140117).

Note: SanitizerAnnotateDebugInfo() is updated to a public function because it is needed in ItaniumCXXABI.

Updates the tests from #139149.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:codegen IR generation bugs: mangling, exceptions, etc. labels May 13, 2025
@llvmbot
Copy link
Member

llvmbot commented May 13, 2025

@llvm/pr-subscribers-clang

Author: Thurston Dang (thurstond)

Changes

This connects the -fsanitize-annotate-debug-info plumbing (#138577) to CFI check codegen.

Updates the tests from #139149.

A side effect is that "__ubsan_check_array_bounds" is renamed to "__ubsan_check_array-bounds". This affects clang/test/CodeGen/bounds-checking-debuginfo.c from #128977


Patch is 35.46 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/139809.diff

8 Files Affected:

  • (modified) clang/lib/CodeGen/CGClass.cpp (+42-11)
  • (modified) clang/lib/CodeGen/CGExpr.cpp (+32-10)
  • (modified) clang/lib/CodeGen/CodeGenFunction.h (+11)
  • (modified) clang/lib/CodeGen/ItaniumCXXABI.cpp (+6-1)
  • (modified) clang/test/CodeGen/bounds-checking-debuginfo.c (+2-2)
  • (modified) clang/test/CodeGen/cfi-check-fail-debuginfo.c (+13-10)
  • (modified) clang/test/CodeGen/cfi-icall-generalize-debuginfo.c (+26-20)
  • (modified) clang/test/CodeGen/cfi-icall-normalize2-debuginfo.c (+66-61)
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index befbfc64a680c..232965f8f0a84 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -2779,6 +2779,36 @@ void CodeGenFunction::EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD,
   }
 }
 
+void CodeGenFunction::ParseCFITypeCheckKind(CFITypeCheckKind TCK,
+                                            SanitizerKind::SanitizerOrdinal &M,
+                                            llvm::SanitizerStatKind &SSK) {
+  switch (TCK) {
+  case CFITCK_VCall:
+    M = SanitizerKind::SO_CFIVCall;
+    SSK = llvm::SanStat_CFI_VCall;
+    break;
+  case CFITCK_NVCall:
+    M = SanitizerKind::SO_CFINVCall;
+    SSK = llvm::SanStat_CFI_NVCall;
+    break;
+  case CFITCK_DerivedCast:
+    M = SanitizerKind::SO_CFIDerivedCast;
+    SSK = llvm::SanStat_CFI_DerivedCast;
+    break;
+  case CFITCK_UnrelatedCast:
+    M = SanitizerKind::SO_CFIUnrelatedCast;
+    SSK = llvm::SanStat_CFI_UnrelatedCast;
+    break;
+  case CFITCK_ICall:
+    M = SanitizerKind::SO_CFIICall;
+    SSK = llvm::SanStat_CFI_ICall;
+    break;
+  case CFITCK_NVMFCall:
+  case CFITCK_VMFCall:
+    llvm_unreachable("unexpected sanitizer kind");
+  }
+}
+
 void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXRecordDecl *RD,
                                                 llvm::Value *VTable,
                                                 CFITypeCheckKind TCK,
@@ -2786,6 +2816,10 @@ void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXRecordDecl *RD,
   if (!SanOpts.has(SanitizerKind::CFICastStrict))
     RD = LeastDerivedClassWithSameLayout(RD);
 
+  SanitizerKind::SanitizerOrdinal Ordinal;
+  llvm::SanitizerStatKind SSK;
+  ParseCFITypeCheckKind(TCK, Ordinal, SSK);
+  ApplyDebugLocation ApplyTrapDI(*this, SanitizerAnnotateDebugInfo(Ordinal));
   EmitVTablePtrCheck(RD, VTable, TCK, Loc);
 }
 
@@ -2808,6 +2842,11 @@ void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T, Address Derived,
   if (!SanOpts.has(SanitizerKind::CFICastStrict))
     ClassDecl = LeastDerivedClassWithSameLayout(ClassDecl);
 
+  SanitizerKind::SanitizerOrdinal Ordinal;
+  llvm::SanitizerStatKind SSK;
+  ParseCFITypeCheckKind(TCK, Ordinal, SSK);
+  ApplyDebugLocation ApplyTrapDI(*this, SanitizerAnnotateDebugInfo(Ordinal));
+
   llvm::BasicBlock *ContBlock = nullptr;
 
   if (MayBeNull) {
@@ -2844,22 +2883,12 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
 
   SanitizerKind::SanitizerOrdinal M;
   llvm::SanitizerStatKind SSK;
+  ParseCFITypeCheckKind(TCK, M, SSK);
   switch (TCK) {
   case CFITCK_VCall:
-    M = SanitizerKind::SO_CFIVCall;
-    SSK = llvm::SanStat_CFI_VCall;
-    break;
   case CFITCK_NVCall:
-    M = SanitizerKind::SO_CFINVCall;
-    SSK = llvm::SanStat_CFI_NVCall;
-    break;
   case CFITCK_DerivedCast:
-    M = SanitizerKind::SO_CFIDerivedCast;
-    SSK = llvm::SanStat_CFI_DerivedCast;
-    break;
   case CFITCK_UnrelatedCast:
-    M = SanitizerKind::SO_CFIUnrelatedCast;
-    SSK = llvm::SanStat_CFI_UnrelatedCast;
     break;
   case CFITCK_ICall:
   case CFITCK_NVMFCall:
@@ -2932,6 +2961,8 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
   SanitizerScope SanScope(this);
 
   EmitSanitizerStatReport(llvm::SanStat_CFI_VCall);
+  ApplyDebugLocation ApplyTrapDI(
+      *this, SanitizerAnnotateDebugInfo(SanitizerKind::SO_CFIVCall));
 
   llvm::Metadata *MD =
       CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 0d03923951a16..8519584c1f081 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1217,6 +1217,30 @@ void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
   EmitBoundsCheckImpl(E, Bound, Index, IndexType, IndexedType, Accessed);
 }
 
+llvm::DILocation *CodeGenFunction::SanitizerAnnotateDebugInfo(
+    SanitizerKind::SanitizerOrdinal CheckKindOrdinal) {
+  StringRef Label;
+  switch (CheckKindOrdinal) {
+#define SANITIZER(NAME, ID)                                                    \
+  case SanitizerKind::SO_##ID:                                                 \
+    Label = "__ubsan_check_" NAME;                                             \
+    break;
+#include "clang/Basic/Sanitizers.def"
+  default:
+    llvm_unreachable("unexpected sanitizer kind");
+  }
+
+  llvm::DILocation *CheckDI = Builder.getCurrentDebugLocation();
+  // TODO: deprecate ClArrayBoundsPseudoFn
+  if (((ClArrayBoundsPseudoFn &&
+        CheckKindOrdinal == SanitizerKind::SO_ArrayBounds) ||
+       CGM.getCodeGenOpts().SanitizeAnnotateDebugInfo.has(CheckKindOrdinal)) &&
+      CheckDI) {
+    CheckDI = getDebugInfo()->CreateSyntheticInlineAt(CheckDI, Label);
+  }
+  return CheckDI;
+}
+
 void CodeGenFunction::EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound,
                                           llvm::Value *Index,
                                           QualType IndexType,
@@ -1225,17 +1249,8 @@ void CodeGenFunction::EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound,
     return;
 
   SanitizerScope SanScope(this);
-
-  llvm::DILocation *CheckDI = Builder.getCurrentDebugLocation();
   auto CheckKind = SanitizerKind::SO_ArrayBounds;
-  // TODO: deprecate ClArrayBoundsPseudoFn
-  if ((ClArrayBoundsPseudoFn ||
-       CGM.getCodeGenOpts().SanitizeAnnotateDebugInfo.has(CheckKind)) &&
-      CheckDI) {
-    CheckDI = getDebugInfo()->CreateSyntheticInlineAt(
-        Builder.getCurrentDebugLocation(), "__ubsan_check_array_bounds");
-  }
-  ApplyDebugLocation ApplyTrapDI(*this, CheckDI);
+  ApplyDebugLocation ApplyTrapDI(*this, SanitizerAnnotateDebugInfo(CheckKind));
 
   bool IndexSigned = IndexType->isSignedIntegerOrEnumerationType();
   llvm::Value *IndexVal = Builder.CreateIntCast(Index, SizeTy, IndexSigned);
@@ -3950,6 +3965,8 @@ void CodeGenFunction::EmitCfiCheckFail() {
                          {Addr, AllVtables}),
       IntPtrTy);
 
+  // TODO: the instructions above are not annotated with debug info. It is
+  // inconvenient to do so because we hadn't determined the SanitizerKind yet.
   const std::pair<int, SanitizerKind::SanitizerOrdinal> CheckKinds[] = {
       {CFITCK_VCall, SanitizerKind::SO_CFIVCall},
       {CFITCK_NVCall, SanitizerKind::SO_CFINVCall},
@@ -3960,6 +3977,9 @@ void CodeGenFunction::EmitCfiCheckFail() {
   for (auto CheckKindOrdinalPair : CheckKinds) {
     int Kind = CheckKindOrdinalPair.first;
     SanitizerKind::SanitizerOrdinal Ordinal = CheckKindOrdinalPair.second;
+
+    ApplyDebugLocation ApplyTrapDI(*this, SanitizerAnnotateDebugInfo(Ordinal));
+
     llvm::Value *Cond =
         Builder.CreateICmpNE(CheckKind, llvm::ConstantInt::get(Int8Ty, Kind));
     if (CGM.getLangOpts().Sanitize.has(Ordinal))
@@ -6245,6 +6265,8 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
       (!TargetDecl || !isa<FunctionDecl>(TargetDecl))) {
     SanitizerScope SanScope(this);
     EmitSanitizerStatReport(llvm::SanStat_CFI_ICall);
+    ApplyDebugLocation ApplyTrapDI(
+        *this, SanitizerAnnotateDebugInfo(SanitizerKind::SO_CFIICall));
 
     llvm::Metadata *MD;
     if (CGM.getCodeGenOpts().SanitizeCfiICallGeneralizePointers)
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index c0bc3825f0188..ab36e0965d6fe 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3353,6 +3353,17 @@ class CodeGenFunction : public CodeGenTypeCache {
                      SanitizerSet SkippedChecks = SanitizerSet(),
                      llvm::Value *ArraySize = nullptr);
 
+  /// Returns debug info, with additional annotation if enabled by
+  /// CGM.getCodeGenOpts().SanitizeAnnotateDebugInfo[CheckKindOrdinal].
+  llvm::DILocation *
+  SanitizerAnnotateDebugInfo(SanitizerKind::SanitizerOrdinal CheckKindOrdinal);
+
+  /// Converts the CFITypeCheckKind into SanitizerKind::SanitizerOrdinal and
+  /// llvm::SanitizerStatKind.
+  void ParseCFITypeCheckKind(CFITypeCheckKind TCK,
+                             SanitizerKind::SanitizerOrdinal &M,
+                             llvm::SanitizerStatKind &SSK);
+
   /// Emit a check that \p Base points into an array object, which
   /// we can access at index \p Index. \p Accessed should be \c false if we
   /// this expression is used as an lvalue, for instance in "&Arr[Idx]".
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 70b53be7e77a3..df12425ee46f9 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -703,6 +703,9 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
 
   {
     CodeGenFunction::SanitizerScope SanScope(&CGF);
+    ApplyDebugLocation ApplyTrapDI(
+        CGF, CGF.SanitizerAnnotateDebugInfo(SanitizerKind::SO_CFIMFCall));
+
     llvm::Value *TypeId = nullptr;
     llvm::Value *CheckResult = nullptr;
 
@@ -792,14 +795,16 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
   // In the non-virtual path, the function pointer is actually a
   // function pointer.
   CGF.EmitBlock(FnNonVirtual);
+
   llvm::Value *NonVirtualFn =
       Builder.CreateIntToPtr(FnAsInt, CGF.UnqualPtrTy, "memptr.nonvirtualfn");
-
   // Check the function pointer if CFI on member function pointers is enabled.
   if (ShouldEmitCFICheck) {
     CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
     if (RD->hasDefinition()) {
       CodeGenFunction::SanitizerScope SanScope(&CGF);
+      ApplyDebugLocation ApplyTrapDI(
+          CGF, CGF.SanitizerAnnotateDebugInfo(SanitizerKind::SO_CFIMFCall));
 
       llvm::Constant *StaticData[] = {
           llvm::ConstantInt::get(CGF.Int8Ty, CodeGenFunction::CFITCK_NVMFCall),
diff --git a/clang/test/CodeGen/bounds-checking-debuginfo.c b/clang/test/CodeGen/bounds-checking-debuginfo.c
index 74c06665dfe02..1549b02938697 100644
--- a/clang/test/CodeGen/bounds-checking-debuginfo.c
+++ b/clang/test/CodeGen/bounds-checking-debuginfo.c
@@ -89,7 +89,7 @@ double f1(int b, int i) {
 // CHECK-TRAP: [[DBG21]] = !DILocation(line: 65, column: 3, scope: [[DBG4]])
 // CHECK-TRAP: [[DBG22]] = !DILocation(line: 66, column: 12, scope: [[DBG4]])
 // CHECK-TRAP: [[DBG23]] = !DILocation(line: 0, scope: [[META24:![0-9]+]], inlinedAt: [[DBG26]])
-// CHECK-TRAP: [[META24]] = distinct !DISubprogram(name: "__ubsan_check_array_bounds", scope: [[META5]], file: [[META5]], type: [[META25:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
+// CHECK-TRAP: [[META24]] = distinct !DISubprogram(name: "__ubsan_check_array-bounds", scope: [[META5]], file: [[META5]], type: [[META25:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
 // CHECK-TRAP: [[META25]] = !DISubroutineType(types: null)
 // CHECK-TRAP: [[DBG26]] = !DILocation(line: 66, column: 10, scope: [[DBG4]])
 // CHECK-TRAP: [[PROF27]] = !{!"branch_weights", i32 1048575, i32 1}
@@ -117,7 +117,7 @@ double f1(int b, int i) {
 // CHECK-NOTRAP: [[DBG21]] = !DILocation(line: 65, column: 3, scope: [[DBG4]])
 // CHECK-NOTRAP: [[DBG22]] = !DILocation(line: 66, column: 12, scope: [[DBG4]])
 // CHECK-NOTRAP: [[DBG23]] = !DILocation(line: 0, scope: [[META24:![0-9]+]], inlinedAt: [[DBG26]])
-// CHECK-NOTRAP: [[META24]] = distinct !DISubprogram(name: "__ubsan_check_array_bounds", scope: [[META5]], file: [[META5]], type: [[META25:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
+// CHECK-NOTRAP: [[META24]] = distinct !DISubprogram(name: "__ubsan_check_array-bounds", scope: [[META5]], file: [[META5]], type: [[META25:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
 // CHECK-NOTRAP: [[META25]] = !DISubroutineType(types: null)
 // CHECK-NOTRAP: [[DBG26]] = !DILocation(line: 66, column: 10, scope: [[DBG4]])
 // CHECK-NOTRAP: [[PROF27]] = !{!"branch_weights", i32 1048575, i32 1}
diff --git a/clang/test/CodeGen/cfi-check-fail-debuginfo.c b/clang/test/CodeGen/cfi-check-fail-debuginfo.c
index cd5ec567cb01b..7100a42fef886 100644
--- a/clang/test/CodeGen/cfi-check-fail-debuginfo.c
+++ b/clang/test/CodeGen/cfi-check-fail-debuginfo.c
@@ -10,14 +10,14 @@
 // CHECK-SAME: ptr noundef [[F:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] !dbg [[DBG7:![0-9]+]] !type [[META16:![0-9]+]] !type [[META17:![0-9]+]] !type [[META18:![0-9]+]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:      #dbg_value(ptr [[F]], [[META15:![0-9]+]], !DIExpression(), [[META19:![0-9]+]])
-// CHECK-NEXT:    [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[F]], metadata !"_ZTSFvvE"), !dbg [[DBG20:![0-9]+]], !nosanitize [[META21:![0-9]+]]
-// CHECK-NEXT:    br i1 [[TMP0]], label %[[CFI_CONT:.*]], label %[[CFI_SLOWPATH:.*]], !dbg [[DBG20]], !prof [[PROF22:![0-9]+]], !nosanitize [[META21]]
+// CHECK-NEXT:    [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[F]], metadata !"_ZTSFvvE"), !dbg [[DBG20:![0-9]+]], !nosanitize [[META24:![0-9]+]]
+// CHECK-NEXT:    br i1 [[TMP0]], label %[[CFI_CONT:.*]], label %[[CFI_SLOWPATH:.*]], !dbg [[DBG20]], !prof [[PROF25:![0-9]+]], !nosanitize [[META24]]
 // CHECK:       [[CFI_SLOWPATH]]:
-// CHECK-NEXT:    tail call void @__cfi_slowpath(i64 9080559750644022485, ptr [[F]]) #[[ATTR6:[0-9]+]], !dbg [[DBG20]], !nosanitize [[META21]]
-// CHECK-NEXT:    br label %[[CFI_CONT]], !dbg [[DBG20]], !nosanitize [[META21]]
+// CHECK-NEXT:    tail call void @__cfi_slowpath(i64 9080559750644022485, ptr [[F]]) #[[ATTR6:[0-9]+]], !dbg [[DBG20]], !nosanitize [[META24]]
+// CHECK-NEXT:    br label %[[CFI_CONT]], !dbg [[DBG20]], !nosanitize [[META24]]
 // CHECK:       [[CFI_CONT]]:
-// CHECK-NEXT:    tail call void [[F]]() #[[ATTR6]], !dbg [[DBG20]]
-// CHECK-NEXT:    ret void, !dbg [[DBG23:![0-9]+]]
+// CHECK-NEXT:    tail call void [[F]]() #[[ATTR6]], !dbg [[DBG23:![0-9]+]]
+// CHECK-NEXT:    ret void, !dbg [[DBG26:![0-9]+]]
 //
 void caller(void (*f)(void)) {
   f();
@@ -38,8 +38,11 @@ void caller(void (*f)(void)) {
 // CHECK: [[META17]] = !{i64 0, !"_ZTSFvPvE.generalized"}
 // CHECK: [[META18]] = !{i64 0, i64 2451761621477796417}
 // CHECK: [[META19]] = !DILocation(line: 0, scope: [[DBG7]])
-// CHECK: [[DBG20]] = !DILocation(line: 23, column: 3, scope: [[DBG7]])
-// CHECK: [[META21]] = !{}
-// CHECK: [[PROF22]] = !{!"branch_weights", i32 1048575, i32 1}
-// CHECK: [[DBG23]] = !DILocation(line: 24, column: 1, scope: [[DBG7]])
+// CHECK: [[DBG20]] = !DILocation(line: 0, scope: [[META21:![0-9]+]], inlinedAt: [[DBG23]])
+// CHECK: [[META21]] = distinct !DISubprogram(name: "__ubsan_check_cfi-icall", scope: [[META8]], file: [[META8]], type: [[META22:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
+// CHECK: [[META22]] = !DISubroutineType(types: null)
+// CHECK: [[DBG23]] = !DILocation(line: 23, column: 3, scope: [[DBG7]])
+// CHECK: [[META24]] = !{}
+// CHECK: [[PROF25]] = !{!"branch_weights", i32 1048575, i32 1}
+// CHECK: [[DBG26]] = !DILocation(line: 24, column: 1, scope: [[DBG7]])
 //.
diff --git a/clang/test/CodeGen/cfi-icall-generalize-debuginfo.c b/clang/test/CodeGen/cfi-icall-generalize-debuginfo.c
index 8b184528889a0..e47f058e2c633 100644
--- a/clang/test/CodeGen/cfi-icall-generalize-debuginfo.c
+++ b/clang/test/CodeGen/cfi-icall-generalize-debuginfo.c
@@ -27,27 +27,27 @@ int** f(const char *a, const char **b) {
 // UNGENERALIZED-SAME: ptr noundef [[FP:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] !dbg [[DBG25:![0-9]+]] !type [[META31:![0-9]+]] !type [[META32:![0-9]+]] {
 // UNGENERALIZED-NEXT:  [[ENTRY:.*:]]
 // UNGENERALIZED-NEXT:      #dbg_value(ptr [[FP]], [[META30:![0-9]+]], !DIExpression(), [[META33:![0-9]+]])
-// UNGENERALIZED-NEXT:    [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[FP]], metadata !"_ZTSFPPiPKcPS2_E"), !dbg [[DBG34:![0-9]+]], !nosanitize [[META35:![0-9]+]]
-// UNGENERALIZED-NEXT:    br i1 [[TMP0]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG34]], !prof [[PROF36:![0-9]+]], !nosanitize [[META35]]
+// UNGENERALIZED-NEXT:    [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[FP]], metadata !"_ZTSFPPiPKcPS2_E"), !dbg [[DBG34:![0-9]+]], !nosanitize [[META38:![0-9]+]]
+// UNGENERALIZED-NEXT:    br i1 [[TMP0]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG34]], !prof [[PROF39:![0-9]+]], !nosanitize [[META38]]
 // UNGENERALIZED:       [[TRAP]]:
-// UNGENERALIZED-NEXT:    tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !dbg [[DBG34]], !nosanitize [[META35]]
-// UNGENERALIZED-NEXT:    unreachable, !dbg [[DBG34]], !nosanitize [[META35]]
+// UNGENERALIZED-NEXT:    tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !dbg [[DBG34]], !nosanitize [[META38]]
+// UNGENERALIZED-NEXT:    unreachable, !dbg [[DBG34]], !nosanitize [[META38]]
 // UNGENERALIZED:       [[CONT]]:
-// UNGENERALIZED-NEXT:    [[CALL:%.*]] = tail call ptr [[FP]](ptr noundef null, ptr noundef null) #[[ATTR5:[0-9]+]], !dbg [[DBG34]]
-// UNGENERALIZED-NEXT:    ret void, !dbg [[DBG37:![0-9]+]]
+// UNGENERALIZED-NEXT:    [[CALL:%.*]] = tail call ptr [[FP]](ptr noundef null, ptr noundef null) #[[ATTR5:[0-9]+]], !dbg [[DBG37:![0-9]+]]
+// UNGENERALIZED-NEXT:    ret void, !dbg [[DBG40:![0-9]+]]
 //
 // GENERALIZED-LABEL: define dso_local void @g(
 // GENERALIZED-SAME: ptr noundef [[FP:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] !dbg [[DBG25:![0-9]+]] !type [[META31:![0-9]+]] !type [[META32:![0-9]+]] {
 // GENERALIZED-NEXT:  [[ENTRY:.*:]]
 // GENERALIZED-NEXT:      #dbg_value(ptr [[FP]], [[META30:![0-9]+]], !DIExpression(), [[META33:![0-9]+]])
-// GENERALIZED-NEXT:    [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[FP]], metadata !"_ZTSFPvPKvS_E.generalized"), !dbg [[DBG34:![0-9]+]], !nosanitize [[META35:![0-9]+]]
-// GENERALIZED-NEXT:    br i1 [[TMP0]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG34]], !prof [[PROF36:![0-9]+]], !nosanitize [[META35]]
+// GENERALIZED-NEXT:    [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[FP]], metadata !"_ZTSFPvPKvS_E.generalized"), !dbg [[DBG34:![0-9]+]], !nosanitize [[META38:![0-9]+]]
+// GENERALIZED-NEXT:    br i1 [[TMP0]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG34]], !prof [[PROF39:![0-9]+]], !nosanitize [[META38]]
 // GENERALIZED:       [[TRAP]]:
-// GENERALIZED-NEXT:    tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !dbg [[DBG34]], !nosanitize [[META35]]
-// GENERALIZED-NEXT:    unreachable, !dbg [[DBG34]], !nosanitize [[META35]]
+// GENERALIZED-NEXT:    tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !dbg [[DBG34]], !nosanitize [[META38]]
+// GENERALIZED-NEXT:    unreachable, !dbg [[DBG34]], !nosanitize [[META38]]
 // GENERALIZED:       [[CONT]]:
-// GENERALIZED-NEXT:    [[CALL:%.*]] = tail call ptr [[FP]](ptr noundef null, ptr noundef null) #[[ATTR5:[0-9]+]], !dbg [[DBG34]]
-// GENERALIZED-NEXT:    ret void, !dbg [[DBG37:![0-9]+]]
+// GENERALIZED-NEXT:    [[CALL:%.*]] = tail call ptr [[FP]](ptr noundef null, ptr noundef null) #[[ATTR5:[0-9]+]], !dbg [[DBG37:![0-9]+]]
+// GENERALIZED-NEXT:    ret void, !dbg [[DBG40:![0-9]+]]
 //
 void g(int** (*fp)(const char *, const char **)) {
   fp(0, 0);
@@ -84,10 +84,13 @@ void g(int** (*fp)(const char *, const char **)) {
 // UNGENERALIZED: [[META31]] = !{i64 0, !"_ZTSFvPFPPiPKcPS2_EE"}
 // UNGENERALIZED: [[META32]] = !{i64 0, !"_ZTSFvPvE.generalized"}
 // UNGENERALIZED: [[META33]] = !DILocation(line: 0, scope: [[DBG25]])
-// UNGENERALIZED: [[DBG34]] = !DILocation(line: 53, column: 3, scope: [[DBG25]])
-// UNGENERALIZED: [[META35]] = !{}
-// UNGENERALIZED: [[PROF36]] = !{!"branch_weights", i32 1048575, i32 1}
-// UNGENERALIZED: [[DBG37]] = !DILocation(line: 54, column: 1, scope: [[DBG25]])
+// UNGENERALIZED: [[DBG34]] = !DILocation(line: 0, scope: [[META35:![0-9]+]], inlinedAt: [[DBG37]])
+// UNGENERALIZED: [[META35]] = distinct !DISubprogram(name: "__ubsan_check_cfi-icall", scope: [[META11]], file: [[META11]], type: [[META36:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
+// UNGENERALIZED: [[META36]] = !DISubroutineType(types: null)
+// UNGENERALIZED: [[DBG37]] = !DILocation(line: 53, column: 3, scope: [[DBG25]])
+// UNGENERALIZED: [[META38]] = !{}
+// UNGENERALIZED: [[PROF39]] = !{!"branch_weights", i32 1048575, i32 1}
+// UNGENERALIZED: [[DBG40]] = !DILocation(line: 54, column: 1, scope: [[DBG25]])
 //.
 // GENERALIZED: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: [[META2:![0-9]+]], splitDebugIn...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented May 13, 2025

@llvm/pr-subscribers-clang-codegen

Author: Thurston Dang (thurstond)

Changes

This connects the -fsanitize-annotate-debug-info plumbing (#138577) to CFI check codegen.

Updates the tests from #139149.

A side effect is that "__ubsan_check_array_bounds" is renamed to "__ubsan_check_array-bounds". This affects clang/test/CodeGen/bounds-checking-debuginfo.c from #128977


Patch is 35.46 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/139809.diff

8 Files Affected:

  • (modified) clang/lib/CodeGen/CGClass.cpp (+42-11)
  • (modified) clang/lib/CodeGen/CGExpr.cpp (+32-10)
  • (modified) clang/lib/CodeGen/CodeGenFunction.h (+11)
  • (modified) clang/lib/CodeGen/ItaniumCXXABI.cpp (+6-1)
  • (modified) clang/test/CodeGen/bounds-checking-debuginfo.c (+2-2)
  • (modified) clang/test/CodeGen/cfi-check-fail-debuginfo.c (+13-10)
  • (modified) clang/test/CodeGen/cfi-icall-generalize-debuginfo.c (+26-20)
  • (modified) clang/test/CodeGen/cfi-icall-normalize2-debuginfo.c (+66-61)
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index befbfc64a680c..232965f8f0a84 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -2779,6 +2779,36 @@ void CodeGenFunction::EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD,
   }
 }
 
+void CodeGenFunction::ParseCFITypeCheckKind(CFITypeCheckKind TCK,
+                                            SanitizerKind::SanitizerOrdinal &M,
+                                            llvm::SanitizerStatKind &SSK) {
+  switch (TCK) {
+  case CFITCK_VCall:
+    M = SanitizerKind::SO_CFIVCall;
+    SSK = llvm::SanStat_CFI_VCall;
+    break;
+  case CFITCK_NVCall:
+    M = SanitizerKind::SO_CFINVCall;
+    SSK = llvm::SanStat_CFI_NVCall;
+    break;
+  case CFITCK_DerivedCast:
+    M = SanitizerKind::SO_CFIDerivedCast;
+    SSK = llvm::SanStat_CFI_DerivedCast;
+    break;
+  case CFITCK_UnrelatedCast:
+    M = SanitizerKind::SO_CFIUnrelatedCast;
+    SSK = llvm::SanStat_CFI_UnrelatedCast;
+    break;
+  case CFITCK_ICall:
+    M = SanitizerKind::SO_CFIICall;
+    SSK = llvm::SanStat_CFI_ICall;
+    break;
+  case CFITCK_NVMFCall:
+  case CFITCK_VMFCall:
+    llvm_unreachable("unexpected sanitizer kind");
+  }
+}
+
 void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXRecordDecl *RD,
                                                 llvm::Value *VTable,
                                                 CFITypeCheckKind TCK,
@@ -2786,6 +2816,10 @@ void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXRecordDecl *RD,
   if (!SanOpts.has(SanitizerKind::CFICastStrict))
     RD = LeastDerivedClassWithSameLayout(RD);
 
+  SanitizerKind::SanitizerOrdinal Ordinal;
+  llvm::SanitizerStatKind SSK;
+  ParseCFITypeCheckKind(TCK, Ordinal, SSK);
+  ApplyDebugLocation ApplyTrapDI(*this, SanitizerAnnotateDebugInfo(Ordinal));
   EmitVTablePtrCheck(RD, VTable, TCK, Loc);
 }
 
@@ -2808,6 +2842,11 @@ void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T, Address Derived,
   if (!SanOpts.has(SanitizerKind::CFICastStrict))
     ClassDecl = LeastDerivedClassWithSameLayout(ClassDecl);
 
+  SanitizerKind::SanitizerOrdinal Ordinal;
+  llvm::SanitizerStatKind SSK;
+  ParseCFITypeCheckKind(TCK, Ordinal, SSK);
+  ApplyDebugLocation ApplyTrapDI(*this, SanitizerAnnotateDebugInfo(Ordinal));
+
   llvm::BasicBlock *ContBlock = nullptr;
 
   if (MayBeNull) {
@@ -2844,22 +2883,12 @@ void CodeGenFunction::EmitVTablePtrCheck(const CXXRecordDecl *RD,
 
   SanitizerKind::SanitizerOrdinal M;
   llvm::SanitizerStatKind SSK;
+  ParseCFITypeCheckKind(TCK, M, SSK);
   switch (TCK) {
   case CFITCK_VCall:
-    M = SanitizerKind::SO_CFIVCall;
-    SSK = llvm::SanStat_CFI_VCall;
-    break;
   case CFITCK_NVCall:
-    M = SanitizerKind::SO_CFINVCall;
-    SSK = llvm::SanStat_CFI_NVCall;
-    break;
   case CFITCK_DerivedCast:
-    M = SanitizerKind::SO_CFIDerivedCast;
-    SSK = llvm::SanStat_CFI_DerivedCast;
-    break;
   case CFITCK_UnrelatedCast:
-    M = SanitizerKind::SO_CFIUnrelatedCast;
-    SSK = llvm::SanStat_CFI_UnrelatedCast;
     break;
   case CFITCK_ICall:
   case CFITCK_NVMFCall:
@@ -2932,6 +2961,8 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad(
   SanitizerScope SanScope(this);
 
   EmitSanitizerStatReport(llvm::SanStat_CFI_VCall);
+  ApplyDebugLocation ApplyTrapDI(
+      *this, SanitizerAnnotateDebugInfo(SanitizerKind::SO_CFIVCall));
 
   llvm::Metadata *MD =
       CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 0d03923951a16..8519584c1f081 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1217,6 +1217,30 @@ void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
   EmitBoundsCheckImpl(E, Bound, Index, IndexType, IndexedType, Accessed);
 }
 
+llvm::DILocation *CodeGenFunction::SanitizerAnnotateDebugInfo(
+    SanitizerKind::SanitizerOrdinal CheckKindOrdinal) {
+  StringRef Label;
+  switch (CheckKindOrdinal) {
+#define SANITIZER(NAME, ID)                                                    \
+  case SanitizerKind::SO_##ID:                                                 \
+    Label = "__ubsan_check_" NAME;                                             \
+    break;
+#include "clang/Basic/Sanitizers.def"
+  default:
+    llvm_unreachable("unexpected sanitizer kind");
+  }
+
+  llvm::DILocation *CheckDI = Builder.getCurrentDebugLocation();
+  // TODO: deprecate ClArrayBoundsPseudoFn
+  if (((ClArrayBoundsPseudoFn &&
+        CheckKindOrdinal == SanitizerKind::SO_ArrayBounds) ||
+       CGM.getCodeGenOpts().SanitizeAnnotateDebugInfo.has(CheckKindOrdinal)) &&
+      CheckDI) {
+    CheckDI = getDebugInfo()->CreateSyntheticInlineAt(CheckDI, Label);
+  }
+  return CheckDI;
+}
+
 void CodeGenFunction::EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound,
                                           llvm::Value *Index,
                                           QualType IndexType,
@@ -1225,17 +1249,8 @@ void CodeGenFunction::EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound,
     return;
 
   SanitizerScope SanScope(this);
-
-  llvm::DILocation *CheckDI = Builder.getCurrentDebugLocation();
   auto CheckKind = SanitizerKind::SO_ArrayBounds;
-  // TODO: deprecate ClArrayBoundsPseudoFn
-  if ((ClArrayBoundsPseudoFn ||
-       CGM.getCodeGenOpts().SanitizeAnnotateDebugInfo.has(CheckKind)) &&
-      CheckDI) {
-    CheckDI = getDebugInfo()->CreateSyntheticInlineAt(
-        Builder.getCurrentDebugLocation(), "__ubsan_check_array_bounds");
-  }
-  ApplyDebugLocation ApplyTrapDI(*this, CheckDI);
+  ApplyDebugLocation ApplyTrapDI(*this, SanitizerAnnotateDebugInfo(CheckKind));
 
   bool IndexSigned = IndexType->isSignedIntegerOrEnumerationType();
   llvm::Value *IndexVal = Builder.CreateIntCast(Index, SizeTy, IndexSigned);
@@ -3950,6 +3965,8 @@ void CodeGenFunction::EmitCfiCheckFail() {
                          {Addr, AllVtables}),
       IntPtrTy);
 
+  // TODO: the instructions above are not annotated with debug info. It is
+  // inconvenient to do so because we hadn't determined the SanitizerKind yet.
   const std::pair<int, SanitizerKind::SanitizerOrdinal> CheckKinds[] = {
       {CFITCK_VCall, SanitizerKind::SO_CFIVCall},
       {CFITCK_NVCall, SanitizerKind::SO_CFINVCall},
@@ -3960,6 +3977,9 @@ void CodeGenFunction::EmitCfiCheckFail() {
   for (auto CheckKindOrdinalPair : CheckKinds) {
     int Kind = CheckKindOrdinalPair.first;
     SanitizerKind::SanitizerOrdinal Ordinal = CheckKindOrdinalPair.second;
+
+    ApplyDebugLocation ApplyTrapDI(*this, SanitizerAnnotateDebugInfo(Ordinal));
+
     llvm::Value *Cond =
         Builder.CreateICmpNE(CheckKind, llvm::ConstantInt::get(Int8Ty, Kind));
     if (CGM.getLangOpts().Sanitize.has(Ordinal))
@@ -6245,6 +6265,8 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
       (!TargetDecl || !isa<FunctionDecl>(TargetDecl))) {
     SanitizerScope SanScope(this);
     EmitSanitizerStatReport(llvm::SanStat_CFI_ICall);
+    ApplyDebugLocation ApplyTrapDI(
+        *this, SanitizerAnnotateDebugInfo(SanitizerKind::SO_CFIICall));
 
     llvm::Metadata *MD;
     if (CGM.getCodeGenOpts().SanitizeCfiICallGeneralizePointers)
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index c0bc3825f0188..ab36e0965d6fe 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3353,6 +3353,17 @@ class CodeGenFunction : public CodeGenTypeCache {
                      SanitizerSet SkippedChecks = SanitizerSet(),
                      llvm::Value *ArraySize = nullptr);
 
+  /// Returns debug info, with additional annotation if enabled by
+  /// CGM.getCodeGenOpts().SanitizeAnnotateDebugInfo[CheckKindOrdinal].
+  llvm::DILocation *
+  SanitizerAnnotateDebugInfo(SanitizerKind::SanitizerOrdinal CheckKindOrdinal);
+
+  /// Converts the CFITypeCheckKind into SanitizerKind::SanitizerOrdinal and
+  /// llvm::SanitizerStatKind.
+  void ParseCFITypeCheckKind(CFITypeCheckKind TCK,
+                             SanitizerKind::SanitizerOrdinal &M,
+                             llvm::SanitizerStatKind &SSK);
+
   /// Emit a check that \p Base points into an array object, which
   /// we can access at index \p Index. \p Accessed should be \c false if we
   /// this expression is used as an lvalue, for instance in "&Arr[Idx]".
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 70b53be7e77a3..df12425ee46f9 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -703,6 +703,9 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
 
   {
     CodeGenFunction::SanitizerScope SanScope(&CGF);
+    ApplyDebugLocation ApplyTrapDI(
+        CGF, CGF.SanitizerAnnotateDebugInfo(SanitizerKind::SO_CFIMFCall));
+
     llvm::Value *TypeId = nullptr;
     llvm::Value *CheckResult = nullptr;
 
@@ -792,14 +795,16 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
   // In the non-virtual path, the function pointer is actually a
   // function pointer.
   CGF.EmitBlock(FnNonVirtual);
+
   llvm::Value *NonVirtualFn =
       Builder.CreateIntToPtr(FnAsInt, CGF.UnqualPtrTy, "memptr.nonvirtualfn");
-
   // Check the function pointer if CFI on member function pointers is enabled.
   if (ShouldEmitCFICheck) {
     CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
     if (RD->hasDefinition()) {
       CodeGenFunction::SanitizerScope SanScope(&CGF);
+      ApplyDebugLocation ApplyTrapDI(
+          CGF, CGF.SanitizerAnnotateDebugInfo(SanitizerKind::SO_CFIMFCall));
 
       llvm::Constant *StaticData[] = {
           llvm::ConstantInt::get(CGF.Int8Ty, CodeGenFunction::CFITCK_NVMFCall),
diff --git a/clang/test/CodeGen/bounds-checking-debuginfo.c b/clang/test/CodeGen/bounds-checking-debuginfo.c
index 74c06665dfe02..1549b02938697 100644
--- a/clang/test/CodeGen/bounds-checking-debuginfo.c
+++ b/clang/test/CodeGen/bounds-checking-debuginfo.c
@@ -89,7 +89,7 @@ double f1(int b, int i) {
 // CHECK-TRAP: [[DBG21]] = !DILocation(line: 65, column: 3, scope: [[DBG4]])
 // CHECK-TRAP: [[DBG22]] = !DILocation(line: 66, column: 12, scope: [[DBG4]])
 // CHECK-TRAP: [[DBG23]] = !DILocation(line: 0, scope: [[META24:![0-9]+]], inlinedAt: [[DBG26]])
-// CHECK-TRAP: [[META24]] = distinct !DISubprogram(name: "__ubsan_check_array_bounds", scope: [[META5]], file: [[META5]], type: [[META25:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
+// CHECK-TRAP: [[META24]] = distinct !DISubprogram(name: "__ubsan_check_array-bounds", scope: [[META5]], file: [[META5]], type: [[META25:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
 // CHECK-TRAP: [[META25]] = !DISubroutineType(types: null)
 // CHECK-TRAP: [[DBG26]] = !DILocation(line: 66, column: 10, scope: [[DBG4]])
 // CHECK-TRAP: [[PROF27]] = !{!"branch_weights", i32 1048575, i32 1}
@@ -117,7 +117,7 @@ double f1(int b, int i) {
 // CHECK-NOTRAP: [[DBG21]] = !DILocation(line: 65, column: 3, scope: [[DBG4]])
 // CHECK-NOTRAP: [[DBG22]] = !DILocation(line: 66, column: 12, scope: [[DBG4]])
 // CHECK-NOTRAP: [[DBG23]] = !DILocation(line: 0, scope: [[META24:![0-9]+]], inlinedAt: [[DBG26]])
-// CHECK-NOTRAP: [[META24]] = distinct !DISubprogram(name: "__ubsan_check_array_bounds", scope: [[META5]], file: [[META5]], type: [[META25:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
+// CHECK-NOTRAP: [[META24]] = distinct !DISubprogram(name: "__ubsan_check_array-bounds", scope: [[META5]], file: [[META5]], type: [[META25:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
 // CHECK-NOTRAP: [[META25]] = !DISubroutineType(types: null)
 // CHECK-NOTRAP: [[DBG26]] = !DILocation(line: 66, column: 10, scope: [[DBG4]])
 // CHECK-NOTRAP: [[PROF27]] = !{!"branch_weights", i32 1048575, i32 1}
diff --git a/clang/test/CodeGen/cfi-check-fail-debuginfo.c b/clang/test/CodeGen/cfi-check-fail-debuginfo.c
index cd5ec567cb01b..7100a42fef886 100644
--- a/clang/test/CodeGen/cfi-check-fail-debuginfo.c
+++ b/clang/test/CodeGen/cfi-check-fail-debuginfo.c
@@ -10,14 +10,14 @@
 // CHECK-SAME: ptr noundef [[F:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] !dbg [[DBG7:![0-9]+]] !type [[META16:![0-9]+]] !type [[META17:![0-9]+]] !type [[META18:![0-9]+]] {
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:      #dbg_value(ptr [[F]], [[META15:![0-9]+]], !DIExpression(), [[META19:![0-9]+]])
-// CHECK-NEXT:    [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[F]], metadata !"_ZTSFvvE"), !dbg [[DBG20:![0-9]+]], !nosanitize [[META21:![0-9]+]]
-// CHECK-NEXT:    br i1 [[TMP0]], label %[[CFI_CONT:.*]], label %[[CFI_SLOWPATH:.*]], !dbg [[DBG20]], !prof [[PROF22:![0-9]+]], !nosanitize [[META21]]
+// CHECK-NEXT:    [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[F]], metadata !"_ZTSFvvE"), !dbg [[DBG20:![0-9]+]], !nosanitize [[META24:![0-9]+]]
+// CHECK-NEXT:    br i1 [[TMP0]], label %[[CFI_CONT:.*]], label %[[CFI_SLOWPATH:.*]], !dbg [[DBG20]], !prof [[PROF25:![0-9]+]], !nosanitize [[META24]]
 // CHECK:       [[CFI_SLOWPATH]]:
-// CHECK-NEXT:    tail call void @__cfi_slowpath(i64 9080559750644022485, ptr [[F]]) #[[ATTR6:[0-9]+]], !dbg [[DBG20]], !nosanitize [[META21]]
-// CHECK-NEXT:    br label %[[CFI_CONT]], !dbg [[DBG20]], !nosanitize [[META21]]
+// CHECK-NEXT:    tail call void @__cfi_slowpath(i64 9080559750644022485, ptr [[F]]) #[[ATTR6:[0-9]+]], !dbg [[DBG20]], !nosanitize [[META24]]
+// CHECK-NEXT:    br label %[[CFI_CONT]], !dbg [[DBG20]], !nosanitize [[META24]]
 // CHECK:       [[CFI_CONT]]:
-// CHECK-NEXT:    tail call void [[F]]() #[[ATTR6]], !dbg [[DBG20]]
-// CHECK-NEXT:    ret void, !dbg [[DBG23:![0-9]+]]
+// CHECK-NEXT:    tail call void [[F]]() #[[ATTR6]], !dbg [[DBG23:![0-9]+]]
+// CHECK-NEXT:    ret void, !dbg [[DBG26:![0-9]+]]
 //
 void caller(void (*f)(void)) {
   f();
@@ -38,8 +38,11 @@ void caller(void (*f)(void)) {
 // CHECK: [[META17]] = !{i64 0, !"_ZTSFvPvE.generalized"}
 // CHECK: [[META18]] = !{i64 0, i64 2451761621477796417}
 // CHECK: [[META19]] = !DILocation(line: 0, scope: [[DBG7]])
-// CHECK: [[DBG20]] = !DILocation(line: 23, column: 3, scope: [[DBG7]])
-// CHECK: [[META21]] = !{}
-// CHECK: [[PROF22]] = !{!"branch_weights", i32 1048575, i32 1}
-// CHECK: [[DBG23]] = !DILocation(line: 24, column: 1, scope: [[DBG7]])
+// CHECK: [[DBG20]] = !DILocation(line: 0, scope: [[META21:![0-9]+]], inlinedAt: [[DBG23]])
+// CHECK: [[META21]] = distinct !DISubprogram(name: "__ubsan_check_cfi-icall", scope: [[META8]], file: [[META8]], type: [[META22:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
+// CHECK: [[META22]] = !DISubroutineType(types: null)
+// CHECK: [[DBG23]] = !DILocation(line: 23, column: 3, scope: [[DBG7]])
+// CHECK: [[META24]] = !{}
+// CHECK: [[PROF25]] = !{!"branch_weights", i32 1048575, i32 1}
+// CHECK: [[DBG26]] = !DILocation(line: 24, column: 1, scope: [[DBG7]])
 //.
diff --git a/clang/test/CodeGen/cfi-icall-generalize-debuginfo.c b/clang/test/CodeGen/cfi-icall-generalize-debuginfo.c
index 8b184528889a0..e47f058e2c633 100644
--- a/clang/test/CodeGen/cfi-icall-generalize-debuginfo.c
+++ b/clang/test/CodeGen/cfi-icall-generalize-debuginfo.c
@@ -27,27 +27,27 @@ int** f(const char *a, const char **b) {
 // UNGENERALIZED-SAME: ptr noundef [[FP:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] !dbg [[DBG25:![0-9]+]] !type [[META31:![0-9]+]] !type [[META32:![0-9]+]] {
 // UNGENERALIZED-NEXT:  [[ENTRY:.*:]]
 // UNGENERALIZED-NEXT:      #dbg_value(ptr [[FP]], [[META30:![0-9]+]], !DIExpression(), [[META33:![0-9]+]])
-// UNGENERALIZED-NEXT:    [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[FP]], metadata !"_ZTSFPPiPKcPS2_E"), !dbg [[DBG34:![0-9]+]], !nosanitize [[META35:![0-9]+]]
-// UNGENERALIZED-NEXT:    br i1 [[TMP0]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG34]], !prof [[PROF36:![0-9]+]], !nosanitize [[META35]]
+// UNGENERALIZED-NEXT:    [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[FP]], metadata !"_ZTSFPPiPKcPS2_E"), !dbg [[DBG34:![0-9]+]], !nosanitize [[META38:![0-9]+]]
+// UNGENERALIZED-NEXT:    br i1 [[TMP0]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG34]], !prof [[PROF39:![0-9]+]], !nosanitize [[META38]]
 // UNGENERALIZED:       [[TRAP]]:
-// UNGENERALIZED-NEXT:    tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !dbg [[DBG34]], !nosanitize [[META35]]
-// UNGENERALIZED-NEXT:    unreachable, !dbg [[DBG34]], !nosanitize [[META35]]
+// UNGENERALIZED-NEXT:    tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !dbg [[DBG34]], !nosanitize [[META38]]
+// UNGENERALIZED-NEXT:    unreachable, !dbg [[DBG34]], !nosanitize [[META38]]
 // UNGENERALIZED:       [[CONT]]:
-// UNGENERALIZED-NEXT:    [[CALL:%.*]] = tail call ptr [[FP]](ptr noundef null, ptr noundef null) #[[ATTR5:[0-9]+]], !dbg [[DBG34]]
-// UNGENERALIZED-NEXT:    ret void, !dbg [[DBG37:![0-9]+]]
+// UNGENERALIZED-NEXT:    [[CALL:%.*]] = tail call ptr [[FP]](ptr noundef null, ptr noundef null) #[[ATTR5:[0-9]+]], !dbg [[DBG37:![0-9]+]]
+// UNGENERALIZED-NEXT:    ret void, !dbg [[DBG40:![0-9]+]]
 //
 // GENERALIZED-LABEL: define dso_local void @g(
 // GENERALIZED-SAME: ptr noundef [[FP:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] !dbg [[DBG25:![0-9]+]] !type [[META31:![0-9]+]] !type [[META32:![0-9]+]] {
 // GENERALIZED-NEXT:  [[ENTRY:.*:]]
 // GENERALIZED-NEXT:      #dbg_value(ptr [[FP]], [[META30:![0-9]+]], !DIExpression(), [[META33:![0-9]+]])
-// GENERALIZED-NEXT:    [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[FP]], metadata !"_ZTSFPvPKvS_E.generalized"), !dbg [[DBG34:![0-9]+]], !nosanitize [[META35:![0-9]+]]
-// GENERALIZED-NEXT:    br i1 [[TMP0]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG34]], !prof [[PROF36:![0-9]+]], !nosanitize [[META35]]
+// GENERALIZED-NEXT:    [[TMP0:%.*]] = tail call i1 @llvm.type.test(ptr [[FP]], metadata !"_ZTSFPvPKvS_E.generalized"), !dbg [[DBG34:![0-9]+]], !nosanitize [[META38:![0-9]+]]
+// GENERALIZED-NEXT:    br i1 [[TMP0]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG34]], !prof [[PROF39:![0-9]+]], !nosanitize [[META38]]
 // GENERALIZED:       [[TRAP]]:
-// GENERALIZED-NEXT:    tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !dbg [[DBG34]], !nosanitize [[META35]]
-// GENERALIZED-NEXT:    unreachable, !dbg [[DBG34]], !nosanitize [[META35]]
+// GENERALIZED-NEXT:    tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !dbg [[DBG34]], !nosanitize [[META38]]
+// GENERALIZED-NEXT:    unreachable, !dbg [[DBG34]], !nosanitize [[META38]]
 // GENERALIZED:       [[CONT]]:
-// GENERALIZED-NEXT:    [[CALL:%.*]] = tail call ptr [[FP]](ptr noundef null, ptr noundef null) #[[ATTR5:[0-9]+]], !dbg [[DBG34]]
-// GENERALIZED-NEXT:    ret void, !dbg [[DBG37:![0-9]+]]
+// GENERALIZED-NEXT:    [[CALL:%.*]] = tail call ptr [[FP]](ptr noundef null, ptr noundef null) #[[ATTR5:[0-9]+]], !dbg [[DBG37:![0-9]+]]
+// GENERALIZED-NEXT:    ret void, !dbg [[DBG40:![0-9]+]]
 //
 void g(int** (*fp)(const char *, const char **)) {
   fp(0, 0);
@@ -84,10 +84,13 @@ void g(int** (*fp)(const char *, const char **)) {
 // UNGENERALIZED: [[META31]] = !{i64 0, !"_ZTSFvPFPPiPKcPS2_EE"}
 // UNGENERALIZED: [[META32]] = !{i64 0, !"_ZTSFvPvE.generalized"}
 // UNGENERALIZED: [[META33]] = !DILocation(line: 0, scope: [[DBG25]])
-// UNGENERALIZED: [[DBG34]] = !DILocation(line: 53, column: 3, scope: [[DBG25]])
-// UNGENERALIZED: [[META35]] = !{}
-// UNGENERALIZED: [[PROF36]] = !{!"branch_weights", i32 1048575, i32 1}
-// UNGENERALIZED: [[DBG37]] = !DILocation(line: 54, column: 1, scope: [[DBG25]])
+// UNGENERALIZED: [[DBG34]] = !DILocation(line: 0, scope: [[META35:![0-9]+]], inlinedAt: [[DBG37]])
+// UNGENERALIZED: [[META35]] = distinct !DISubprogram(name: "__ubsan_check_cfi-icall", scope: [[META11]], file: [[META11]], type: [[META36:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
+// UNGENERALIZED: [[META36]] = !DISubroutineType(types: null)
+// UNGENERALIZED: [[DBG37]] = !DILocation(line: 53, column: 3, scope: [[DBG25]])
+// UNGENERALIZED: [[META38]] = !{}
+// UNGENERALIZED: [[PROF39]] = !{!"branch_weights", i32 1048575, i32 1}
+// UNGENERALIZED: [[DBG40]] = !DILocation(line: 54, column: 1, scope: [[DBG25]])
 //.
 // GENERALIZED: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: [[META2:![0-9]+]], splitDebugIn...
[truncated]

@fmayer
Copy link
Contributor

fmayer commented May 13, 2025

I am not a fan of the change to the function used for array-bounds.

@vitalybuka
Copy link
Collaborator

I am not a fan of the change to the function used for array-bounds.

More specific? I like it in general.
It's about just about the name of a new fake function?

@fmayer
Copy link
Contributor

fmayer commented May 13, 2025

I am not a fan of the change to the function used for array-bounds.

More specific? I like it in general. It's about just about the name of a new fake function?

Sorry, I meant the new name.

I don't like that it has a - in it, and I don't like that it changed for no good reason.

@thurstond
Copy link
Contributor Author

I am not a fan of the change to the function used for array-bounds.

More specific? I like it in general. It's about just about the name of a new fake function?

Sorry, I meant the new name.

I don't like that it has a - in it, and I don't like that it changed for no good reason.

It was changed for efficiency. Anyway, fixed in dfc3919

@thurstond thurstond requested a review from vitalybuka May 14, 2025 00:00
@thurstond thurstond requested a review from fmayer May 14, 2025 16:30
@thurstond thurstond requested review from vitalybuka and fmayer May 15, 2025 18:01
@thurstond thurstond marked this pull request as draft May 15, 2025 18:06
@thurstond
Copy link
Contributor Author

Marking as draft - I'll pull out ParseCFITypeCheckKind as a separate NFC patch

thurstond added a commit to thurstond/llvm-project that referenced this pull request May 15, 2025
This refactors existing code into a 'ParseCFITypeCheckKind' helper
function. This will be useful in future work to annotate CFI checks with
debug info (llvm#139809).
Copy link
Contributor

@delcypher delcypher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems reasonable to me other than my coding style nits. I don't own this code though so you should wait for approval from one of the code owners.

void CodeGenFunction::EmitVTablePtrCheckForCall(const CXXRecordDecl *RD,
llvm::Value *VTable,
CFITypeCheckKind TCK,
SourceLocation Loc) {
if (!SanOpts.has(SanitizerKind::CFICastStrict))
RD = LeastDerivedClassWithSameLayout(RD);

auto [Ordinal, SSK] = ParseCFITypeCheckKind(TCK);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is SSK unused?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Renamed SSK to '_'. Thanks!

@@ -2808,6 +2842,9 @@ void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T, Address Derived,
if (!SanOpts.has(SanitizerKind::CFICastStrict))
ClassDecl = LeastDerivedClassWithSameLayout(ClassDecl);

auto [Ordinal, SSK] = ParseCFITypeCheckKind(TCK);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is SSK unused?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto


switch (TCK) {
case CFITCK_VCall:
M = SanitizerKind::SO_CFIVCall;
Copy link
Contributor

@delcypher delcypher May 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just return std::make_pair(SanitizerKind::SO_CFIVCall, llvm::SanStat_CFI_VCall)? It's a little more concise and also more inline with LLVM's coding style of returning as early as possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review! I refactored this function into #140117. I'll make the change there.

thurstond added a commit that referenced this pull request May 15, 2025
This refactors existing code into a 'SanitizerInfoFromCFICheckKind'
helper function. This will be useful in future work to annotate CFI
checks with debug info
(#139809).
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request May 16, 2025
…(#140117)

This refactors existing code into a 'SanitizerInfoFromCFICheckKind'
helper function. This will be useful in future work to annotate CFI
checks with debug info
(llvm/llvm-project#139809).
thurstond added 10 commits May 16, 2025 01:55
This connects the -fsanitize-annotate-debug-info plumbing
(llvm#138577) to CFI check codegen.

Updates the tests from llvm#139149.

A side effect is that __ubsan_check_array_bounds is renamed to __ubsan_check_array-bounds.
This affects clang/test/CodeGen/bounds-checking-debuginfo.c
from llvm#128977
…Kind> ParseCFITypeCheckKind(CFITypeCheckKind TCK);
@thurstond thurstond marked this pull request as ready for review May 16, 2025 02:30
@thurstond thurstond merged commit b24c33a into llvm:main May 19, 2025
11 checks passed
thurstond added a commit to thurstond/llvm-project that referenced this pull request May 28, 2025
These tests will track progress on extending
llvm#139809 from CFI to more UBSan
checks.
thurstond added a commit that referenced this pull request May 28, 2025
…1814)

These tests will track progress on extending
#139809 from CFI to more UBSan
checks.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request May 28, 2025
…g-info (#141814)

These tests will track progress on extending
llvm/llvm-project#139809 from CFI to more UBSan
checks.
thurstond added a commit to thurstond/llvm-project that referenced this pull request May 29, 2025
This extends llvm#138577 to more
UBSan checks.

Note that the annotations are less detailed: they will always be
__ubsan_check_singularity, rather than using the SanitizerKind (previous
behavior, which is not always possible for all UBSan checks) or SanitizerHandler.
This is a (minor) regression compared to
llvm#128977 and
llvm#139809.

Updates the tests from llvm#128976,
llvm#139149 and llvm#141814.
google-yfyang pushed a commit to google-yfyang/llvm-project that referenced this pull request May 29, 2025
…m#141814)

These tests will track progress on extending
llvm#139809 from CFI to more UBSan
checks.
sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Jun 3, 2025
…cks (llvm#139809)

This connects the -fsanitize-annotate-debug-info plumbing (llvm#138577) to CFI check codegen, using SanitizerAnnotateDebugInfo() (llvm#139965) and SanitizerInfoFromCFIKind (llvm#140117).

Note: SanitizerAnnotateDebugInfo() is updated to a public function because it is needed in ItaniumCXXABI.

Updates the tests from llvm#139149.
sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Jun 3, 2025
…m#141814)

These tests will track progress on extending
llvm#139809 from CFI to more UBSan
checks.
ajaden-codes pushed a commit to Jaddyen/llvm-project that referenced this pull request Jun 6, 2025
…cks (llvm#139809)

This connects the -fsanitize-annotate-debug-info plumbing (llvm#138577) to CFI check codegen, using SanitizerAnnotateDebugInfo() (llvm#139965) and SanitizerInfoFromCFIKind (llvm#140117).

Note: SanitizerAnnotateDebugInfo() is updated to a public function because it is needed in ItaniumCXXABI.

Updates the tests from llvm#139149.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants