Skip to content

[cfi][NFCI] Pre-commit -fsanitize-annotate-debug-info tests for CFI #139149

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 4 commits into from
May 12, 2025

Conversation

thurstond
Copy link
Contributor

These tests will show progress as the -fsanitize-annotate-debug-info plumbing (#138577) gets connected to CFI check codegen.

These tests will show progress as the -fsanitize-annotate-debug-info
plumbing (llvm#138577) gets
connected to CFI check codegen.
@thurstond thurstond requested review from fmayer, pcc and vitalybuka May 8, 2025 20:21
@llvmbot llvmbot added the clang Clang issues not falling into any other category label May 8, 2025
@llvmbot
Copy link
Member

llvmbot commented May 8, 2025

@llvm/pr-subscribers-clang

Author: Thurston Dang (thurstond)

Changes

These tests will show progress as the -fsanitize-annotate-debug-info plumbing (#138577) gets connected to CFI check codegen.


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

3 Files Affected:

  • (added) clang/test/CodeGen/cfi-check-fail-debuginfo.c (+47)
  • (added) clang/test/CodeGen/cfi-icall-generalize-debuginfo.c (+134)
  • (added) clang/test/CodeGen/cfi-icall-normalize2-debuginfo.c (+155)
diff --git a/clang/test/CodeGen/cfi-check-fail-debuginfo.c b/clang/test/CodeGen/cfi-check-fail-debuginfo.c
new file mode 100644
index 0000000000000..024b0eb0191f7
--- /dev/null
+++ b/clang/test/CodeGen/cfi-check-fail-debuginfo.c
@@ -0,0 +1,47 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -O0 -fsanitize-cfi-cross-dso \
+// RUN:     -fsanitize=cfi-icall,cfi-nvcall,cfi-vcall,cfi-unrelated-cast,cfi-derived-cast \
+// RUN:     -fsanitize-trap=cfi-icall,cfi-nvcall -fsanitize-recover=cfi-vcall,cfi-unrelated-cast \
+// RUN:     -fsanitize-annotate-debug-info=cfi-icall,cfi-nvcall,cfi-vcall,cfi-unrelated-cast,cfi-derived-cast \
+// RUN:     -fdebug-prefix-map=%S/= -fno-ident -fdebug-compilation-dir=%S -debug-info-kind=limited \
+// RUN:     -emit-llvm -o - %s | FileCheck %s
+
+// CHECK-LABEL: define dso_local void @caller(
+// CHECK-SAME: ptr noundef [[F:%.*]]) #[[ATTR0:[0-9]+]] !dbg [[DBG6:![0-9]+]] !type [[META14:![0-9]+]] !type [[META15:![0-9]+]] !type [[META16:![0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[F_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    store ptr [[F]], ptr [[F_ADDR]], align 8
+// CHECK-NEXT:      #dbg_declare(ptr [[F_ADDR]], [[META17:![0-9]+]], !DIExpression(), [[META18:![0-9]+]])
+// CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[F_ADDR]], align 8, !dbg [[DBG19:![0-9]+]]
+// CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.type.test(ptr [[TMP0]], metadata !"_ZTSFvvE"), !dbg [[DBG19]], !nosanitize [[META13:![0-9]+]]
+// CHECK-NEXT:    br i1 [[TMP1]], label %[[CFI_CONT:.*]], label %[[CFI_SLOWPATH:.*]], !dbg [[DBG19]], !prof [[PROF20:![0-9]+]], !nosanitize [[META13]]
+// CHECK:       [[CFI_SLOWPATH]]:
+// CHECK-NEXT:    call void @__cfi_slowpath(i64 9080559750644022485, ptr [[TMP0]]) #[[ATTR7:[0-9]+]], !dbg [[DBG19]], !nosanitize [[META13]]
+// CHECK-NEXT:    br label %[[CFI_CONT]], !dbg [[DBG19]], !nosanitize [[META13]]
+// CHECK:       [[CFI_CONT]]:
+// CHECK-NEXT:    call void [[TMP0]](), !dbg [[DBG19]]
+// CHECK-NEXT:    ret void, !dbg [[DBG21:![0-9]+]]
+//
+void caller(void (*f)(void)) {
+  f();
+}
+//.
+// CHECK: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+// CHECK: [[META1]] = !DIFile(filename: "{{.*}}<stdin>", directory: {{.*}})
+// CHECK: [[DBG6]] = distinct !DISubprogram(name: "caller", scope: [[META7:![0-9]+]], file: [[META7]], line: 8, type: [[META8:![0-9]+]], scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META13]])
+// CHECK: [[META7]] = !DIFile(filename: "{{.*}}cfi-check-fail-debuginfo.c", directory: {{.*}})
+// CHECK: [[META8]] = !DISubroutineType(types: [[META9:![0-9]+]])
+// CHECK: [[META9]] = !{null, [[META10:![0-9]+]]}
+// CHECK: [[META10]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META11:![0-9]+]], size: 64)
+// CHECK: [[META11]] = !DISubroutineType(types: [[META12:![0-9]+]])
+// CHECK: [[META12]] = !{null}
+// CHECK: [[META13]] = !{}
+// CHECK: [[META14]] = !{i64 0, !"_ZTSFvPFvvEE"}
+// CHECK: [[META15]] = !{i64 0, !"_ZTSFvPvE.generalized"}
+// CHECK: [[META16]] = !{i64 0, i64 2451761621477796417}
+// CHECK: [[META17]] = !DILocalVariable(name: "f", arg: 1, scope: [[DBG6]], file: [[META7]], line: 8, type: [[META10]])
+// CHECK: [[META18]] = !DILocation(line: 8, column: 20, scope: [[DBG6]])
+// CHECK: [[DBG19]] = !DILocation(line: 9, column: 3, scope: [[DBG6]])
+// CHECK: [[PROF20]] = !{!"branch_weights", i32 1048575, i32 1}
+// CHECK: [[DBG21]] = !DILocation(line: 10, column: 1, scope: [[DBG6]])
+//.
diff --git a/clang/test/CodeGen/cfi-icall-generalize-debuginfo.c b/clang/test/CodeGen/cfi-icall-generalize-debuginfo.c
new file mode 100644
index 0000000000000..3819adc8a466b
--- /dev/null
+++ b/clang/test/CodeGen/cfi-icall-generalize-debuginfo.c
@@ -0,0 +1,134 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -emit-llvm -o - %s \
+// RUN:     -fsanitize-annotate-debug-info=cfi-icall,cfi-nvcall,cfi-vcall,cfi-unrelated-cast,cfi-derived-cast \
+// RUN:     -fdebug-prefix-map=%S/= -fno-ident -fdebug-compilation-dir=%S -debug-info-kind=limited \
+// RUN:     | FileCheck --check-prefix=CHECK --check-prefix=UNGENERALIZED %s
+//
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -fsanitize-cfi-icall-generalize-pointers -emit-llvm -o - %s \
+// RUN:     -fsanitize-annotate-debug-info=cfi-icall,cfi-nvcall,cfi-vcall,cfi-unrelated-cast,cfi-derived-cast \
+// RUN:     -fdebug-prefix-map=%S/= -fno-ident -fdebug-compilation-dir=%S -debug-info-kind=limited \
+// RUN:     | FileCheck --check-prefix=CHECK --check-prefix=GENERALIZED %s
+
+// Test that const char* is generalized to const ptr and that const char** is
+// generalized to ptr
+
+// CHECK-LABEL: define dso_local ptr @f(
+// CHECK-SAME: ptr noundef [[A:%.*]], ptr noundef [[B:%.*]]) #[[ATTR0:[0-9]+]] !dbg [[DBG9:![0-9]+]] !type [[META18:![0-9]+]] !type [[META19:![0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[A_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[B_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    store ptr [[A]], ptr [[A_ADDR]], align 8
+// CHECK-NEXT:      #dbg_declare(ptr [[A_ADDR]], [[META20:![0-9]+]], !DIExpression(), [[META21:![0-9]+]])
+// CHECK-NEXT:    store ptr [[B]], ptr [[B_ADDR]], align 8
+// CHECK-NEXT:      #dbg_declare(ptr [[B_ADDR]], [[META22:![0-9]+]], !DIExpression(), [[META23:![0-9]+]])
+// CHECK-NEXT:    ret ptr null, !dbg [[DBG24:![0-9]+]]
+//
+int** f(const char *a, const char **b) {
+  return (int**)0;
+}
+
+// UNGENERALIZED-LABEL: define dso_local void @g(
+// UNGENERALIZED-SAME: ptr noundef [[FP:%.*]]) #[[ATTR0]] !dbg [[DBG25:![0-9]+]] !type [[META29:![0-9]+]] !type [[META30:![0-9]+]] {
+// UNGENERALIZED-NEXT:  [[ENTRY:.*:]]
+// UNGENERALIZED-NEXT:    [[FP_ADDR:%.*]] = alloca ptr, align 8
+// UNGENERALIZED-NEXT:    store ptr [[FP]], ptr [[FP_ADDR]], align 8
+// UNGENERALIZED-NEXT:      #dbg_declare(ptr [[FP_ADDR]], [[META31:![0-9]+]], !DIExpression(), [[META32:![0-9]+]])
+// UNGENERALIZED-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[FP_ADDR]], align 8, !dbg [[DBG33:![0-9]+]]
+// UNGENERALIZED-NEXT:    [[TMP1:%.*]] = call i1 @llvm.type.test(ptr [[TMP0]], metadata !"_ZTSFPPiPKcPS2_E"), !dbg [[DBG33]], !nosanitize [[META17:![0-9]+]]
+// UNGENERALIZED-NEXT:    br i1 [[TMP1]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG33]], !prof [[PROF34:![0-9]+]], !nosanitize [[META17]]
+// UNGENERALIZED:       [[TRAP]]:
+// UNGENERALIZED-NEXT:    call void @llvm.ubsantrap(i8 2) #[[ATTR3:[0-9]+]], !dbg [[DBG33]], !nosanitize [[META17]]
+// UNGENERALIZED-NEXT:    unreachable, !dbg [[DBG33]], !nosanitize [[META17]]
+// UNGENERALIZED:       [[CONT]]:
+// UNGENERALIZED-NEXT:    [[CALL:%.*]] = call ptr [[TMP0]](ptr noundef null, ptr noundef null), !dbg [[DBG33]]
+// UNGENERALIZED-NEXT:    ret void, !dbg [[DBG35:![0-9]+]]
+//
+// GENERALIZED-LABEL: define dso_local void @g(
+// GENERALIZED-SAME: ptr noundef [[FP:%.*]]) #[[ATTR0]] !dbg [[DBG25:![0-9]+]] !type [[META29:![0-9]+]] !type [[META30:![0-9]+]] {
+// GENERALIZED-NEXT:  [[ENTRY:.*:]]
+// GENERALIZED-NEXT:    [[FP_ADDR:%.*]] = alloca ptr, align 8
+// GENERALIZED-NEXT:    store ptr [[FP]], ptr [[FP_ADDR]], align 8
+// GENERALIZED-NEXT:      #dbg_declare(ptr [[FP_ADDR]], [[META31:![0-9]+]], !DIExpression(), [[META32:![0-9]+]])
+// GENERALIZED-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[FP_ADDR]], align 8, !dbg [[DBG33:![0-9]+]]
+// GENERALIZED-NEXT:    [[TMP1:%.*]] = call i1 @llvm.type.test(ptr [[TMP0]], metadata !"_ZTSFPvPKvS_E.generalized"), !dbg [[DBG33]], !nosanitize [[META17:![0-9]+]]
+// GENERALIZED-NEXT:    br i1 [[TMP1]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG33]], !prof [[PROF34:![0-9]+]], !nosanitize [[META17]]
+// GENERALIZED:       [[TRAP]]:
+// GENERALIZED-NEXT:    call void @llvm.ubsantrap(i8 2) #[[ATTR3:[0-9]+]], !dbg [[DBG33]], !nosanitize [[META17]]
+// GENERALIZED-NEXT:    unreachable, !dbg [[DBG33]], !nosanitize [[META17]]
+// GENERALIZED:       [[CONT]]:
+// GENERALIZED-NEXT:    [[CALL:%.*]] = call ptr [[TMP0]](ptr noundef null, ptr noundef null), !dbg [[DBG33]]
+// GENERALIZED-NEXT:    ret void, !dbg [[DBG35:![0-9]+]]
+//
+void g(int** (*fp)(const char *, const char **)) {
+  fp(0, 0);
+}
+
+//.
+// UNGENERALIZED: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: [[META2:![0-9]+]], splitDebugInlining: false, nameTableKind: None)
+// UNGENERALIZED: [[META1]] = !DIFile(filename: "{{.*}}<stdin>", directory: {{.*}})
+// UNGENERALIZED: [[META2]] = !{[[META3:![0-9]+]]}
+// UNGENERALIZED: [[META3]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META4:![0-9]+]], size: 64)
+// UNGENERALIZED: [[META4]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META5:![0-9]+]], size: 64)
+// UNGENERALIZED: [[META5]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+// UNGENERALIZED: [[DBG9]] = distinct !DISubprogram(name: "f", scope: [[META10:![0-9]+]], file: [[META10]], line: 15, type: [[META11:![0-9]+]], scopeLine: 15, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META17]])
+// UNGENERALIZED: [[META10]] = !DIFile(filename: "{{.*}}cfi-icall-generalize-debuginfo.c", directory: {{.*}})
+// UNGENERALIZED: [[META11]] = !DISubroutineType(types: [[META12:![0-9]+]])
+// UNGENERALIZED: [[META12]] = !{[[META3]], [[META13:![0-9]+]], [[META16:![0-9]+]]}
+// UNGENERALIZED: [[META13]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META14:![0-9]+]], size: 64)
+// UNGENERALIZED: [[META14]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: [[META15:![0-9]+]])
+// UNGENERALIZED: [[META15]] = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+// UNGENERALIZED: [[META16]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META13]], size: 64)
+// UNGENERALIZED: [[META17]] = !{}
+// UNGENERALIZED: [[META18]] = !{i64 0, !"_ZTSFPPiPKcPS2_E"}
+// UNGENERALIZED: [[META19]] = !{i64 0, !"_ZTSFPvPKvS_E.generalized"}
+// UNGENERALIZED: [[META20]] = !DILocalVariable(name: "a", arg: 1, scope: [[DBG9]], file: [[META10]], line: 15, type: [[META13]])
+// UNGENERALIZED: [[META21]] = !DILocation(line: 15, column: 21, scope: [[DBG9]])
+// UNGENERALIZED: [[META22]] = !DILocalVariable(name: "b", arg: 2, scope: [[DBG9]], file: [[META10]], line: 15, type: [[META16]])
+// UNGENERALIZED: [[META23]] = !DILocation(line: 15, column: 37, scope: [[DBG9]])
+// UNGENERALIZED: [[DBG24]] = !DILocation(line: 16, column: 3, scope: [[DBG9]])
+// UNGENERALIZED: [[DBG25]] = distinct !DISubprogram(name: "g", scope: [[META10]], file: [[META10]], line: 19, type: [[META26:![0-9]+]], scopeLine: 19, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META17]])
+// UNGENERALIZED: [[META26]] = !DISubroutineType(types: [[META27:![0-9]+]])
+// UNGENERALIZED: [[META27]] = !{null, [[META28:![0-9]+]]}
+// UNGENERALIZED: [[META28]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META11]], size: 64)
+// UNGENERALIZED: [[META29]] = !{i64 0, !"_ZTSFvPFPPiPKcPS2_EE"}
+// UNGENERALIZED: [[META30]] = !{i64 0, !"_ZTSFvPvE.generalized"}
+// UNGENERALIZED: [[META31]] = !DILocalVariable(name: "fp", arg: 1, scope: [[DBG25]], file: [[META10]], line: 19, type: [[META28]])
+// UNGENERALIZED: [[META32]] = !DILocation(line: 19, column: 16, scope: [[DBG25]])
+// UNGENERALIZED: [[DBG33]] = !DILocation(line: 22, column: 3, scope: [[DBG25]])
+// UNGENERALIZED: [[PROF34]] = !{!"branch_weights", i32 1048575, i32 1}
+// UNGENERALIZED: [[DBG35]] = !DILocation(line: 23, column: 1, scope: [[DBG25]])
+//.
+// GENERALIZED: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: [[META2:![0-9]+]], splitDebugInlining: false, nameTableKind: None)
+// GENERALIZED: [[META1]] = !DIFile(filename: "{{.*}}<stdin>", directory: {{.*}})
+// GENERALIZED: [[META2]] = !{[[META3:![0-9]+]]}
+// GENERALIZED: [[META3]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META4:![0-9]+]], size: 64)
+// GENERALIZED: [[META4]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META5:![0-9]+]], size: 64)
+// GENERALIZED: [[META5]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+// GENERALIZED: [[DBG9]] = distinct !DISubprogram(name: "f", scope: [[META10:![0-9]+]], file: [[META10]], line: 15, type: [[META11:![0-9]+]], scopeLine: 15, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META17]])
+// GENERALIZED: [[META10]] = !DIFile(filename: "{{.*}}cfi-icall-generalize-debuginfo.c", directory: {{.*}})
+// GENERALIZED: [[META11]] = !DISubroutineType(types: [[META12:![0-9]+]])
+// GENERALIZED: [[META12]] = !{[[META3]], [[META13:![0-9]+]], [[META16:![0-9]+]]}
+// GENERALIZED: [[META13]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META14:![0-9]+]], size: 64)
+// GENERALIZED: [[META14]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: [[META15:![0-9]+]])
+// GENERALIZED: [[META15]] = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
+// GENERALIZED: [[META16]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META13]], size: 64)
+// GENERALIZED: [[META17]] = !{}
+// GENERALIZED: [[META18]] = !{i64 0, !"_ZTSFPPiPKcPS2_E"}
+// GENERALIZED: [[META19]] = !{i64 0, !"_ZTSFPvPKvS_E.generalized"}
+// GENERALIZED: [[META20]] = !DILocalVariable(name: "a", arg: 1, scope: [[DBG9]], file: [[META10]], line: 15, type: [[META13]])
+// GENERALIZED: [[META21]] = !DILocation(line: 15, column: 21, scope: [[DBG9]])
+// GENERALIZED: [[META22]] = !DILocalVariable(name: "b", arg: 2, scope: [[DBG9]], file: [[META10]], line: 15, type: [[META16]])
+// GENERALIZED: [[META23]] = !DILocation(line: 15, column: 37, scope: [[DBG9]])
+// GENERALIZED: [[DBG24]] = !DILocation(line: 16, column: 3, scope: [[DBG9]])
+// GENERALIZED: [[DBG25]] = distinct !DISubprogram(name: "g", scope: [[META10]], file: [[META10]], line: 19, type: [[META26:![0-9]+]], scopeLine: 19, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META17]])
+// GENERALIZED: [[META26]] = !DISubroutineType(types: [[META27:![0-9]+]])
+// GENERALIZED: [[META27]] = !{null, [[META28:![0-9]+]]}
+// GENERALIZED: [[META28]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: [[META11]], size: 64)
+// GENERALIZED: [[META29]] = !{i64 0, !"_ZTSFvPFPPiPKcPS2_EE"}
+// GENERALIZED: [[META30]] = !{i64 0, !"_ZTSFvPvE.generalized"}
+// GENERALIZED: [[META31]] = !DILocalVariable(name: "fp", arg: 1, scope: [[DBG25]], file: [[META10]], line: 19, type: [[META28]])
+// GENERALIZED: [[META32]] = !DILocation(line: 19, column: 16, scope: [[DBG25]])
+// GENERALIZED: [[DBG33]] = !DILocation(line: 22, column: 3, scope: [[DBG25]])
+// GENERALIZED: [[PROF34]] = !{!"branch_weights", i32 1048575, i32 1}
+// GENERALIZED: [[DBG35]] = !DILocation(line: 23, column: 1, scope: [[DBG25]])
+//.
diff --git a/clang/test/CodeGen/cfi-icall-normalize2-debuginfo.c b/clang/test/CodeGen/cfi-icall-normalize2-debuginfo.c
new file mode 100644
index 0000000000000..aa06013c91b9d
--- /dev/null
+++ b/clang/test/CodeGen/cfi-icall-normalize2-debuginfo.c
@@ -0,0 +1,155 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -triple x86_64-unknown-linux -fsanitize=cfi-icall -fsanitize-trap=cfi-icall -fsanitize-cfi-icall-experimental-normalize-integers -emit-llvm -o - %s \
+// RUN:     -fsanitize-annotate-debug-info=cfi-icall,cfi-nvcall,cfi-vcall,cfi-unrelated-cast,cfi-derived-cast \
+// RUN:     -fdebug-prefix-map=%S/= -fno-ident -fdebug-compilation-dir=%S -debug-info-kind=limited \
+// RUN:     | FileCheck %s
+
+// Test that normalized type metadata for functions are emitted for cross-language CFI support with
+// other languages that can't represent and encode C/C++ integer types.
+
+// CHECK-LABEL: define dso_local void @foo(
+// CHECK-SAME: ptr noundef [[FN:%.*]], i32 noundef [[ARG:%.*]]) #[[ATTR0:[0-9]+]] !dbg [[DBG6:![0-9]+]] !type [[META15:![0-9]+]] !type [[META16:![0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[FN_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[ARG_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store ptr [[FN]], ptr [[FN_ADDR]], align 8
+// CHECK-NEXT:      #dbg_declare(ptr [[FN_ADDR]], [[META17:![0-9]+]], !DIExpression(), [[META18:![0-9]+]])
+// CHECK-NEXT:    store i32 [[ARG]], ptr [[ARG_ADDR]], align 4
+// CHECK-NEXT:      #dbg_declare(ptr [[ARG_ADDR]], [[META19:![0-9]+]], !DIExpression(), [[META20:![0-9]+]])
+// CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[FN_ADDR]], align 8, !dbg [[DBG21:![0-9]+]]
+// CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.type.test(ptr [[TMP0]], metadata !"_ZTSFvu3i32E.normalized"), !dbg [[DBG21]], !nosanitize [[META14:![0-9]+]]
+// CHECK-NEXT:    br i1 [[TMP1]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG21]], !prof [[PROF22:![0-9]+]], !nosanitize [[META14]]
+// CHECK:       [[TRAP]]:
+// CHECK-NEXT:    call void @llvm.ubsantrap(i8 2) #[[ATTR3:[0-9]+]], !dbg [[DBG21]], !nosanitize [[META14]]
+// CHECK-NEXT:    unreachable, !dbg [[DBG21]], !nosanitize [[META14]]
+// CHECK:       [[CONT]]:
+// CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[ARG_ADDR]], align 4, !dbg [[DBG23:![0-9]+]]
+// CHECK-NEXT:    call void [[TMP0]](i32 noundef [[TMP2]]), !dbg [[DBG21]]
+// CHECK-NEXT:    ret void, !dbg [[DBG24:![0-9]+]]
+//
+void foo(void (*fn)(int), int arg) {
+    fn(arg);
+}
+
+// CHECK-LABEL: define dso_local void @bar(
+// CHECK-SAME: ptr noundef [[FN:%.*]], i32 noundef [[ARG1:%.*]], i32 noundef [[ARG2:%.*]]) #[[ATTR0]] !dbg [[DBG25:![0-9]+]] !type [[META31:![0-9]+]] !type [[META32:![0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[FN_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[ARG1_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[ARG2_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store ptr [[FN]], ptr [[FN_ADDR]], align 8
+// CHECK-NEXT:      #dbg_declare(ptr [[FN_ADDR]], [[META33:![0-9]+]], !DIExpression(), [[META34:![0-9]+]])
+// CHECK-NEXT:    store i32 [[ARG1]], ptr [[ARG1_ADDR]], align 4
+// CHECK-NEXT:      #dbg_declare(ptr [[ARG1_ADDR]], [[META35:![0-9]+]], !DIExpression(), [[META36:![0-9]+]])
+// CHECK-NEXT:    store i32 [[ARG2]], ptr [[ARG2_ADDR]], align 4
+// CHECK-NEXT:      #dbg_declare(ptr [[ARG2_ADDR]], [[META37:![0-9]+]], !DIExpression(), [[META38:![0-9]+]])
+// CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[FN_ADDR]], align 8, !dbg [[DBG39:![0-9]+]]
+// CHECK-NEXT:    [[TMP1:%.*]] = call i1 @llvm.type.test(ptr [[TMP0]], metadata !"_ZTSFvu3i32S_E.normalized"), !dbg [[DBG39]], !nosanitize [[META14]]
+// CHECK-NEXT:    br i1 [[TMP1]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG39]], !prof [[PROF22]], !nosanitize [[META14]]
+// CHECK:       [[TRAP]]:
+// CHECK-NEXT:    call void @llvm.ubsantrap(i8 2) #[[ATTR3]], !dbg [[DBG39]], !nosanitize [[META14]]
+// CHECK-NEXT:    unreachable, !dbg [[DBG39]], !nosanitize [[META14]]
+// CHECK:       [[CONT]]:
+// CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[ARG1_ADDR]], align 4, !dbg [[DBG40:![0-9]+]]
+// CHECK-NEXT:    [[TMP3:%.*]] = load i32, ptr [[ARG2_ADDR]], align 4, !dbg [[DBG41:![0-9]+]]
+// CHECK-NEXT:    call void [[TMP0]](i32 noundef [[TMP2]], i32 noundef [[TMP3]]), !dbg [[DBG39]]
+// CHECK-NEXT:    ret void, !dbg [[DBG42:![0-9]+]]
+//
+void bar(void (*fn)(int, int), int arg1, int arg2) {
+    fn(arg1, arg2);
+}
+
+// CHECK-LABEL: define dso_local void @baz(
+// CHECK-SAME: ptr noundef [[FN:%.*]], i32 noundef [[ARG1:%.*]], i32 noundef [[ARG2:%.*]], i32 noundef [[ARG3:%.*]]) #[[ATTR0]] !dbg [[DBG43:![0-9]+]] !type [[META49:![0-9]+]] !type [[META50:![0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[FN_ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[ARG1_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[ARG2_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[ARG3_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store ptr [[FN]], ptr [[FN_ADDR]], align 8
+// CHECK-NEXT:  ...
[truncated]

@@ -0,0 +1,47 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
// RUN: %clang_cc1 -triple x86_64-unknown-linux -O0 -fsanitize-cfi-cross-dso \
Copy link
Collaborator

Choose a reason for hiding this comment

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

would we have less boilerplate if we do e.g. "-O2"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to -O2 in d5ea43f

@thurstond thurstond requested a review from vitalybuka May 8, 2025 21:07
Copy link
Contributor

@fmayer fmayer left a comment

Choose a reason for hiding this comment

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

windows bot fails. argument ordering strikes again?

@thurstond
Copy link
Contributor Author

windows bot fails. argument ordering strikes again?

Test output fixed in bb3df7d, tests now pass

@thurstond thurstond requested a review from fmayer May 12, 2025 17:32
@thurstond thurstond merged commit 40767e9 into llvm:main May 12, 2025
11 checks passed
thurstond added a commit to thurstond/llvm-project that referenced this pull request May 13, 2025
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants