Skip to content

Commit c0952a9

Browse files
committed
[clang] [sanitizer] add pseudofunction to indicate array-bounds check (#128977)
With this, we can: * use profilers to estimate how many cycles we spend on these checks (subject to caveats), * more easily see why we crashed.
1 parent 812efdb commit c0952a9

File tree

4 files changed

+56
-24
lines changed

4 files changed

+56
-24
lines changed

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1786,8 +1786,8 @@ llvm::DIType *CGDebugInfo::createFieldType(
17861786
}
17871787

17881788
llvm::DISubprogram *
1789-
CGDebugInfo::createInlinedTrapSubprogram(StringRef FuncName,
1790-
llvm::DIFile *FileScope) {
1789+
CGDebugInfo::createInlinedSubprogram(StringRef FuncName,
1790+
llvm::DIFile *FileScope) {
17911791
// We are caching the subprogram because we don't want to duplicate
17921792
// subprograms with the same message. Note that `SPFlagDefinition` prevents
17931793
// subprograms from being uniqued.
@@ -3614,6 +3614,14 @@ llvm::DIMacroFile *CGDebugInfo::CreateTempMacroFile(llvm::DIMacroFile *Parent,
36143614
return DBuilder.createTempMacroFile(Parent, Line, FName);
36153615
}
36163616

3617+
llvm::DILocation *CGDebugInfo::CreateSyntheticInlineAt(llvm::DebugLoc Location,
3618+
StringRef FuncName) {
3619+
llvm::DISubprogram *SP =
3620+
createInlinedSubprogram(FuncName, Location->getFile());
3621+
return llvm::DILocation::get(CGM.getLLVMContext(), /*Line=*/0, /*Column=*/0,
3622+
/*Scope=*/SP, /*InlinedAt=*/Location);
3623+
}
3624+
36173625
llvm::DILocation *CGDebugInfo::CreateTrapFailureMessageFor(
36183626
llvm::DebugLoc TrapLocation, StringRef Category, StringRef FailureMsg) {
36193627
// Create a debug location from `TrapLocation` that adds an artificial inline
@@ -3625,10 +3633,7 @@ llvm::DILocation *CGDebugInfo::CreateTrapFailureMessageFor(
36253633
FuncName += "$";
36263634
FuncName += FailureMsg;
36273635

3628-
llvm::DISubprogram *TrapSP =
3629-
createInlinedTrapSubprogram(FuncName, TrapLocation->getFile());
3630-
return llvm::DILocation::get(CGM.getLLVMContext(), /*Line=*/0, /*Column=*/0,
3631-
/*Scope=*/TrapSP, /*InlinedAt=*/TrapLocation);
3636+
return CreateSyntheticInlineAt(TrapLocation, FuncName);
36323637
}
36333638

36343639
static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {

clang/lib/CodeGen/CGDebugInfo.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,8 +359,8 @@ class CGDebugInfo {
359359

360360
/// A function that returns the subprogram corresponding to the artificial
361361
/// inlined function for traps.
362-
llvm::DISubprogram *createInlinedTrapSubprogram(StringRef FuncName,
363-
llvm::DIFile *FileScope);
362+
llvm::DISubprogram *createInlinedSubprogram(StringRef FuncName,
363+
llvm::DIFile *FileScope);
364364

365365
/// Helpers for collecting fields of a record.
366366
/// @{
@@ -635,6 +635,13 @@ class CGDebugInfo {
635635
llvm::DILocation *CreateTrapFailureMessageFor(llvm::DebugLoc TrapLocation,
636636
StringRef Category,
637637
StringRef FailureMsg);
638+
/// Create a debug location from `Location` that adds an artificial inline
639+
/// frame where the frame name is FuncName
640+
///
641+
/// This is used to indiciate instructions that come from compiler
642+
/// instrumentation.
643+
llvm::DILocation *CreateSyntheticInlineAt(llvm::DebugLoc Location,
644+
StringRef FuncName);
638645

639646
private:
640647
/// Emit call to llvm.dbg.declare for a variable declaration.

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "clang/AST/StmtVisitor.h"
3232
#include "clang/Basic/Builtins.h"
3333
#include "clang/Basic/CodeGenOptions.h"
34+
#include "clang/Basic/Module.h"
3435
#include "clang/Basic/SourceManager.h"
3536
#include "llvm/ADT/STLExtras.h"
3637
#include "llvm/ADT/ScopeExit.h"
@@ -60,8 +61,14 @@ namespace clang {
6061
llvm::cl::opt<bool> ClSanitizeGuardChecks(
6162
"ubsan-guard-checks", llvm::cl::Optional,
6263
llvm::cl::desc("Guard UBSAN checks with `llvm.allow.ubsan.check()`."));
64+
6365
} // namespace clang
6466

67+
static llvm::cl::opt<bool> ClArrayBoundsPseudoFn(
68+
"array-bounds-pseudofn", llvm::cl::Hidden, llvm::cl::Optional,
69+
llvm::cl::desc("Emit debug info that places array-bounds instrumentation "
70+
"in an inline function called __ubsan_check_array_bounds."));
71+
6572
//===--------------------------------------------------------------------===//
6673
// Defines for metadata
6774
//===--------------------------------------------------------------------===//
@@ -1215,6 +1222,13 @@ void CodeGenFunction::EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound,
12151222

12161223
SanitizerScope SanScope(this);
12171224

1225+
llvm::DILocation *CheckDI = Builder.getCurrentDebugLocation();
1226+
if (ClArrayBoundsPseudoFn && CheckDI) {
1227+
CheckDI = getDebugInfo()->CreateSyntheticInlineAt(
1228+
Builder.getCurrentDebugLocation(), "__ubsan_check_array_bounds");
1229+
}
1230+
ApplyDebugLocation ApplyTrapDI(*this, CheckDI);
1231+
12181232
bool IndexSigned = IndexType->isSignedIntegerOrEnumerationType();
12191233
llvm::Value *IndexVal = Builder.CreateIntCast(Index, SizeTy, IndexSigned);
12201234
llvm::Value *BoundVal = Builder.CreateIntCast(Bound, SizeTy, false);

clang/test/CodeGen/bounds-checking-debuginfo.c

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
2-
// RUN: %clang_cc1 -emit-llvm -fdebug-prefix-map=%S/= -fno-ident -fdebug-compilation-dir=%S -fsanitize=array-bounds -fsanitize-trap=array-bounds -triple x86_64 -debug-info-kind=limited %s -o - | FileCheck --check-prefix=CHECK-TRAP %s
3-
// RUN: %clang_cc1 -emit-llvm -fdebug-prefix-map=%S/= -fno-ident -fdebug-compilation-dir=%S -fsanitize=array-bounds -triple x86_64 -debug-info-kind=limited %s -o - | FileCheck --check-prefix=CHECK-NOTRAP %s
2+
// RUN: %clang_cc1 -mllvm -array-bounds-pseudofn -emit-llvm -fdebug-prefix-map=%S/= -fno-ident -fdebug-compilation-dir=%S -fsanitize=array-bounds -fsanitize-trap=array-bounds -triple x86_64 -debug-info-kind=limited %s -o - | FileCheck --check-prefix=CHECK-TRAP %s
3+
// RUN: %clang_cc1 -mllvm -array-bounds-pseudofn -emit-llvm -fdebug-prefix-map=%S/= -fno-ident -fdebug-compilation-dir=%S -fsanitize=array-bounds -triple x86_64 -debug-info-kind=limited %s -o - | FileCheck --check-prefix=CHECK-NOTRAP %s
44

55

66
int f();
@@ -28,10 +28,10 @@ void d(double*);
2828
// CHECK-TRAP-NEXT: call void @llvm.ubsantrap(i8 18) #[[ATTR3:[0-9]+]], !dbg [[DBG23]], !nosanitize [[META10]]
2929
// CHECK-TRAP-NEXT: unreachable, !dbg [[DBG23]], !nosanitize [[META10]]
3030
// CHECK-TRAP: [[CONT]]:
31-
// CHECK-TRAP-NEXT: [[IDXPROM:%.*]] = sext i32 [[CALL]] to i64, !dbg [[DBG23]]
32-
// CHECK-TRAP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x double], ptr [[A]], i64 0, i64 [[IDXPROM]], !dbg [[DBG23]]
33-
// CHECK-TRAP-NEXT: [[TMP2:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !dbg [[DBG23]]
34-
// CHECK-TRAP-NEXT: ret double [[TMP2]], !dbg [[DBG24:![0-9]+]]
31+
// CHECK-TRAP-NEXT: [[IDXPROM:%.*]] = sext i32 [[CALL]] to i64, !dbg [[DBG26:![0-9]+]]
32+
// CHECK-TRAP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x double], ptr [[A]], i64 0, i64 [[IDXPROM]], !dbg [[DBG26]]
33+
// CHECK-TRAP-NEXT: [[TMP2:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !dbg [[DBG26]]
34+
// CHECK-TRAP-NEXT: ret double [[TMP2]], !dbg [[DBG27:![0-9]+]]
3535
//
3636
// CHECK-NOTRAP-LABEL: define dso_local double @f1(
3737
// CHECK-NOTRAP-SAME: i32 noundef [[B:%.*]], i32 noundef [[I:%.*]]) #[[ATTR0:[0-9]+]] !dbg [[DBG4:![0-9]+]] {
@@ -49,16 +49,16 @@ void d(double*);
4949
// CHECK-NOTRAP-NEXT: [[CALL:%.*]] = call i32 (...) @f(), !dbg [[DBG22:![0-9]+]]
5050
// CHECK-NOTRAP-NEXT: [[TMP0:%.*]] = sext i32 [[CALL]] to i64, !dbg [[DBG23:![0-9]+]], !nosanitize [[META10:![0-9]+]]
5151
// CHECK-NOTRAP-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 10, !dbg [[DBG23]], !nosanitize [[META10]]
52-
// CHECK-NOTRAP-NEXT: br i1 [[TMP1]], label %[[CONT:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !dbg [[DBG23]], !prof [[PROF24:![0-9]+]], !nosanitize [[META10]]
52+
// CHECK-NOTRAP-NEXT: br i1 [[TMP1]], label %[[CONT:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !dbg [[DBG23]], !prof [[PROF27:![0-9]+]], !nosanitize [[META10]]
5353
// CHECK-NOTRAP: [[HANDLER_OUT_OF_BOUNDS]]:
5454
// CHECK-NOTRAP-NEXT: [[TMP2:%.*]] = zext i32 [[CALL]] to i64, !dbg [[DBG23]], !nosanitize [[META10]]
5555
// CHECK-NOTRAP-NEXT: call void @__ubsan_handle_out_of_bounds_abort(ptr @[[GLOB2:[0-9]+]], i64 [[TMP2]]) #[[ATTR3:[0-9]+]], !dbg [[DBG23]], !nosanitize [[META10]]
5656
// CHECK-NOTRAP-NEXT: unreachable, !dbg [[DBG23]], !nosanitize [[META10]]
5757
// CHECK-NOTRAP: [[CONT]]:
58-
// CHECK-NOTRAP-NEXT: [[IDXPROM:%.*]] = sext i32 [[CALL]] to i64, !dbg [[DBG23]]
59-
// CHECK-NOTRAP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x double], ptr [[A]], i64 0, i64 [[IDXPROM]], !dbg [[DBG23]]
60-
// CHECK-NOTRAP-NEXT: [[TMP3:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !dbg [[DBG23]]
61-
// CHECK-NOTRAP-NEXT: ret double [[TMP3]], !dbg [[DBG25:![0-9]+]]
58+
// CHECK-NOTRAP-NEXT: [[IDXPROM:%.*]] = sext i32 [[CALL]] to i64, !dbg [[DBG26:![0-9]+]]
59+
// CHECK-NOTRAP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x double], ptr [[A]], i64 0, i64 [[IDXPROM]], !dbg [[DBG26]]
60+
// CHECK-NOTRAP-NEXT: [[TMP3:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !dbg [[DBG26]]
61+
// CHECK-NOTRAP-NEXT: ret double [[TMP3]], !dbg [[DBG28:![0-9]+]]
6262
//
6363
double f1(int b, int i) {
6464
double a[10];
@@ -88,8 +88,11 @@ double f1(int b, int i) {
8888
// CHECK-TRAP: [[DBG20]] = !DILocation(line: 65, column: 5, scope: [[DBG4]])
8989
// CHECK-TRAP: [[DBG21]] = !DILocation(line: 65, column: 3, scope: [[DBG4]])
9090
// CHECK-TRAP: [[DBG22]] = !DILocation(line: 66, column: 12, scope: [[DBG4]])
91-
// CHECK-TRAP: [[DBG23]] = !DILocation(line: 66, column: 10, scope: [[DBG4]])
92-
// CHECK-TRAP: [[DBG24]] = !DILocation(line: 66, column: 3, scope: [[DBG4]])
91+
// CHECK-TRAP: [[DBG23]] = !DILocation(line: 0, scope: [[META24:![0-9]+]], inlinedAt: [[DBG26]])
92+
// CHECK-TRAP: [[META24]] = distinct !DISubprogram(name: "__ubsan_check_array_bounds", scope: [[META5]], file: [[META5]], type: [[META25:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
93+
// CHECK-TRAP: [[META25]] = !DISubroutineType(types: null)
94+
// CHECK-TRAP: [[DBG26]] = !DILocation(line: 66, column: 10, scope: [[DBG4]])
95+
// CHECK-TRAP: [[DBG27]] = !DILocation(line: 66, column: 3, scope: [[DBG4]])
9396
//.
9497
// CHECK-NOTRAP: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
9598
// CHECK-NOTRAP: [[META1]] = !DIFile(filename: "<stdin>", directory: {{.*}})
@@ -112,7 +115,10 @@ double f1(int b, int i) {
112115
// CHECK-NOTRAP: [[DBG20]] = !DILocation(line: 65, column: 5, scope: [[DBG4]])
113116
// CHECK-NOTRAP: [[DBG21]] = !DILocation(line: 65, column: 3, scope: [[DBG4]])
114117
// CHECK-NOTRAP: [[DBG22]] = !DILocation(line: 66, column: 12, scope: [[DBG4]])
115-
// CHECK-NOTRAP: [[DBG23]] = !DILocation(line: 66, column: 10, scope: [[DBG4]])
116-
// CHECK-NOTRAP: [[PROF24]] = !{!"branch_weights", i32 1048575, i32 1}
117-
// CHECK-NOTRAP: [[DBG25]] = !DILocation(line: 66, column: 3, scope: [[DBG4]])
118+
// CHECK-NOTRAP: [[DBG23]] = !DILocation(line: 0, scope: [[META24:![0-9]+]], inlinedAt: [[DBG26]])
119+
// CHECK-NOTRAP: [[META24]] = distinct !DISubprogram(name: "__ubsan_check_array_bounds", scope: [[META5]], file: [[META5]], type: [[META25:![0-9]+]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
120+
// CHECK-NOTRAP: [[META25]] = !DISubroutineType(types: null)
121+
// CHECK-NOTRAP: [[DBG26]] = !DILocation(line: 66, column: 10, scope: [[DBG4]])
122+
// CHECK-NOTRAP: [[PROF27]] = !{!"branch_weights", i32 1048575, i32 1}
123+
// CHECK-NOTRAP: [[DBG28]] = !DILocation(line: 66, column: 3, scope: [[DBG4]])
118124
//.

0 commit comments

Comments
 (0)