Skip to content

[clang] [sanitizer] add pseudofunction to indicate array-bounds check #128977

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
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1771,12 +1771,12 @@ llvm::DIType *CGDebugInfo::createFieldType(
}

llvm::DISubprogram *
CGDebugInfo::createInlinedTrapSubprogram(StringRef FuncName,
llvm::DIFile *FileScope) {
CGDebugInfo::createInlinedSubprogram(StringRef FuncName,
llvm::DIFile *FileScope) {
// We are caching the subprogram because we don't want to duplicate
// subprograms with the same message. Note that `SPFlagDefinition` prevents
// subprograms from being uniqued.
llvm::DISubprogram *&SP = InlinedTrapFuncMap[FuncName];
llvm::DISubprogram *&SP = InlinedSubprogramMap[FuncName];

if (!SP) {
llvm::DISubroutineType *DIFnTy = DBuilder.createSubroutineType(nullptr);
Expand Down Expand Up @@ -3598,6 +3598,14 @@ llvm::DIMacroFile *CGDebugInfo::CreateTempMacroFile(llvm::DIMacroFile *Parent,
return DBuilder.createTempMacroFile(Parent, Line, FName);
}

llvm::DILocation *CGDebugInfo::CreateSyntheticInline(llvm::DebugLoc Location,
StringRef FuncName) {
llvm::DISubprogram *TrapSP =
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit. The name TrapSP doesn't make much sense here given this function isn't specifically for traps.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

createInlinedSubprogram(FuncName, Location->getFile());
return llvm::DILocation::get(CGM.getLLVMContext(), /*Line=*/0, /*Column=*/0,
/*Scope=*/TrapSP, /*InlinedAt=*/Location);
}

llvm::DILocation *CGDebugInfo::CreateTrapFailureMessageFor(
llvm::DebugLoc TrapLocation, StringRef Category, StringRef FailureMsg) {
// Create a debug location from `TrapLocation` that adds an artificial inline
Expand All @@ -3609,10 +3617,7 @@ llvm::DILocation *CGDebugInfo::CreateTrapFailureMessageFor(
FuncName += "$";
FuncName += FailureMsg;

llvm::DISubprogram *TrapSP =
createInlinedTrapSubprogram(FuncName, TrapLocation->getFile());
return llvm::DILocation::get(CGM.getLLVMContext(), /*Line=*/0, /*Column=*/0,
/*Scope=*/TrapSP, /*InlinedAt=*/TrapLocation);
return CreateSyntheticInline(TrapLocation, FuncName);
}

static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
Expand Down
13 changes: 10 additions & 3 deletions clang/lib/CodeGen/CGDebugInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,12 +355,12 @@ class CGDebugInfo {
llvm::ArrayRef<llvm::Metadata *> PreviousFieldsDI, const RecordDecl *RD);

/// A cache that maps names of artificial inlined functions to subprograms.
llvm::StringMap<llvm::DISubprogram *> InlinedTrapFuncMap;
llvm::StringMap<llvm::DISubprogram *> InlinedSubprogramMap;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you rename in a separate NFC patch?

Copy link
Contributor Author

Choose a reason for hiding this comment

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


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

/// Helpers for collecting fields of a record.
/// @{
Expand Down Expand Up @@ -635,6 +635,13 @@ class CGDebugInfo {
llvm::DILocation *CreateTrapFailureMessageFor(llvm::DebugLoc TrapLocation,
StringRef Category,
StringRef FailureMsg);
/// Create a debug location from `Location` that adds an artificial inline
/// frame where the frame name is FuncName
///
/// This is used to indiciate instructions that come from compiler
/// instrumentation.
llvm::DILocation *CreateSyntheticInline(llvm::DebugLoc Location,
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit. Maybe call it CreateSyntheticInlineAt ? Those who know more about Clang debug info generation (e.g. @adrian-prantl @felipepiovezan @Michael137 ) might have ideas on a better name though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

StringRef FuncName);

private:
/// Emit call to llvm.dbg.declare for a variable declaration.
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
Expand Down Expand Up @@ -60,8 +61,14 @@ namespace clang {
llvm::cl::opt<bool> ClSanitizeGuardChecks(
"ubsan-guard-checks", llvm::cl::Optional,
llvm::cl::desc("Guard UBSAN checks with `llvm.allow.ubsan.check()`."));

} // namespace clang

static llvm::cl::opt<bool> ClArrayBoundsPseudoFn(
"array-bounds-pseudofn", llvm::cl::Hidden, llvm::cl::Optional,
llvm::cl::desc("Emit debug info that places array-bounds instrumentation "
"in an inline function called __ubsan_check_array_bounds."));

//===--------------------------------------------------------------------===//
// Defines for metadata
//===--------------------------------------------------------------------===//
Expand Down Expand Up @@ -1215,6 +1222,13 @@ void CodeGenFunction::EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound,

SanitizerScope SanScope(this);

llvm::DILocation *CheckDI = Builder.getCurrentDebugLocation();
if (ClArrayBoundsPseudoFn && CheckDI) {
CheckDI = getDebugInfo()->CreateSyntheticInline(
Builder.getCurrentDebugLocation(), "__ubsan_check_array_bounds");
}
ApplyDebugLocation ApplyTrapDI(*this, CheckDI);

bool IndexSigned = IndexType->isSignedIntegerOrEnumerationType();
llvm::Value *IndexVal = Builder.CreateIntCast(Index, SizeTy, IndexSigned);
llvm::Value *BoundVal = Builder.CreateIntCast(Bound, SizeTy, false);
Expand Down
38 changes: 22 additions & 16 deletions clang/test/CodeGen/bounds-checking-debuginfo.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
// 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
// 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
// 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
// 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


int f();
Expand Down Expand Up @@ -28,10 +28,10 @@ void d(double*);
// CHECK-TRAP-NEXT: call void @llvm.ubsantrap(i8 18) #[[ATTR3:[0-9]+]], !dbg [[DBG23]], !nosanitize [[META10]]
// CHECK-TRAP-NEXT: unreachable, !dbg [[DBG23]], !nosanitize [[META10]]
// CHECK-TRAP: [[CONT]]:
// CHECK-TRAP-NEXT: [[IDXPROM:%.*]] = sext i32 [[CALL]] to i64, !dbg [[DBG23]]
// CHECK-TRAP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x double], ptr [[A]], i64 0, i64 [[IDXPROM]], !dbg [[DBG23]]
// CHECK-TRAP-NEXT: [[TMP2:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !dbg [[DBG23]]
// CHECK-TRAP-NEXT: ret double [[TMP2]], !dbg [[DBG24:![0-9]+]]
// CHECK-TRAP-NEXT: [[IDXPROM:%.*]] = sext i32 [[CALL]] to i64, !dbg [[DBG26:![0-9]+]]
// CHECK-TRAP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x double], ptr [[A]], i64 0, i64 [[IDXPROM]], !dbg [[DBG26]]
// CHECK-TRAP-NEXT: [[TMP2:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !dbg [[DBG26]]
// CHECK-TRAP-NEXT: ret double [[TMP2]], !dbg [[DBG27:![0-9]+]]
//
// CHECK-NOTRAP-LABEL: define dso_local double @f1(
// CHECK-NOTRAP-SAME: i32 noundef [[B:%.*]], i32 noundef [[I:%.*]]) #[[ATTR0:[0-9]+]] !dbg [[DBG4:![0-9]+]] {
Expand All @@ -49,16 +49,16 @@ void d(double*);
// CHECK-NOTRAP-NEXT: [[CALL:%.*]] = call i32 (...) @f(), !dbg [[DBG22:![0-9]+]]
// CHECK-NOTRAP-NEXT: [[TMP0:%.*]] = sext i32 [[CALL]] to i64, !dbg [[DBG23:![0-9]+]], !nosanitize [[META10:![0-9]+]]
// CHECK-NOTRAP-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 10, !dbg [[DBG23]], !nosanitize [[META10]]
// CHECK-NOTRAP-NEXT: br i1 [[TMP1]], label %[[CONT:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !dbg [[DBG23]], !prof [[PROF24:![0-9]+]], !nosanitize [[META10]]
// CHECK-NOTRAP-NEXT: br i1 [[TMP1]], label %[[CONT:.*]], label %[[HANDLER_OUT_OF_BOUNDS:.*]], !dbg [[DBG23]], !prof [[PROF27:![0-9]+]], !nosanitize [[META10]]
// CHECK-NOTRAP: [[HANDLER_OUT_OF_BOUNDS]]:
// CHECK-NOTRAP-NEXT: [[TMP2:%.*]] = zext i32 [[CALL]] to i64, !dbg [[DBG23]], !nosanitize [[META10]]
// CHECK-NOTRAP-NEXT: call void @__ubsan_handle_out_of_bounds_abort(ptr @[[GLOB2:[0-9]+]], i64 [[TMP2]]) #[[ATTR3:[0-9]+]], !dbg [[DBG23]], !nosanitize [[META10]]
// CHECK-NOTRAP-NEXT: unreachable, !dbg [[DBG23]], !nosanitize [[META10]]
// CHECK-NOTRAP: [[CONT]]:
// CHECK-NOTRAP-NEXT: [[IDXPROM:%.*]] = sext i32 [[CALL]] to i64, !dbg [[DBG23]]
// CHECK-NOTRAP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x double], ptr [[A]], i64 0, i64 [[IDXPROM]], !dbg [[DBG23]]
// CHECK-NOTRAP-NEXT: [[TMP3:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !dbg [[DBG23]]
// CHECK-NOTRAP-NEXT: ret double [[TMP3]], !dbg [[DBG25:![0-9]+]]
// CHECK-NOTRAP-NEXT: [[IDXPROM:%.*]] = sext i32 [[CALL]] to i64, !dbg [[DBG26:![0-9]+]]
// CHECK-NOTRAP-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x double], ptr [[A]], i64 0, i64 [[IDXPROM]], !dbg [[DBG26]]
// CHECK-NOTRAP-NEXT: [[TMP3:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !dbg [[DBG26]]
// CHECK-NOTRAP-NEXT: ret double [[TMP3]], !dbg [[DBG28:![0-9]+]]
//
double f1(int b, int i) {
double a[10];
Expand Down Expand Up @@ -88,8 +88,11 @@ double f1(int b, int i) {
// CHECK-TRAP: [[DBG20]] = !DILocation(line: 65, column: 5, scope: [[DBG4]])
// 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: 66, column: 10, scope: [[DBG4]])
// CHECK-TRAP: [[DBG24]] = !DILocation(line: 66, column: 3, 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: [[META25]] = !DISubroutineType(types: null)
// CHECK-TRAP: [[DBG26]] = !DILocation(line: 66, column: 10, scope: [[DBG4]])
// CHECK-TRAP: [[DBG27]] = !DILocation(line: 66, column: 3, scope: [[DBG4]])
//.
// 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)
// CHECK-NOTRAP: [[META1]] = !DIFile(filename: "<stdin>", directory: {{.*}})
Expand All @@ -112,7 +115,10 @@ double f1(int b, int i) {
// CHECK-NOTRAP: [[DBG20]] = !DILocation(line: 65, column: 5, scope: [[DBG4]])
// 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: 66, column: 10, scope: [[DBG4]])
// CHECK-NOTRAP: [[PROF24]] = !{!"branch_weights", i32 1048575, i32 1}
// CHECK-NOTRAP: [[DBG25]] = !DILocation(line: 66, column: 3, 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: [[META25]] = !DISubroutineType(types: null)
// CHECK-NOTRAP: [[DBG26]] = !DILocation(line: 66, column: 10, scope: [[DBG4]])
// CHECK-NOTRAP: [[PROF27]] = !{!"branch_weights", i32 1048575, i32 1}
// CHECK-NOTRAP: [[DBG28]] = !DILocation(line: 66, column: 3, scope: [[DBG4]])
//.