Skip to content

[Clang] [CodeGen] UBSan Trap Reasons #145967

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
117 changes: 115 additions & 2 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,96 @@ enum VariableTypeDescriptorKind : uint16_t {
// Miscellaneous Helper Methods
//===--------------------------------------------------------------------===//

static llvm::StringRef GetUBSanTrapForHandler(SanitizerHandler ID) {
switch (ID) {
case SanitizerHandler::AddOverflow:
return "Signed integer addition overflowed";

case SanitizerHandler::BuiltinUnreachable:
return "_builtin_unreachable(), execution reached an unreachable program "
"point";

case SanitizerHandler::CFICheckFail:
return "Control flow integrity check failed";

case SanitizerHandler::DivremOverflow:
return "Signed integer divide or remainder overflowed";

case SanitizerHandler::DynamicTypeCacheMiss:
return "Dynamic type cache miss, member call made on an object whose "
"dynamic type differs from the expected type";

case SanitizerHandler::FloatCastOverflow:
return "Floating-point to integer conversion overflowed";

case SanitizerHandler::FunctionTypeMismatch:
return "Function called with mismatched signature";

case SanitizerHandler::ImplicitConversion:
return "Implicit integer conversion overflowed or lost data";

case SanitizerHandler::InvalidBuiltin:
return "Invalid use of builtin function";

case SanitizerHandler::InvalidObjCCast:
return "Invalid Objective-C cast";

case SanitizerHandler::LoadInvalidValue:
return "Loaded an invalid or uninitialized value for the type";

case SanitizerHandler::MissingReturn:
return "Execution reached the end of a value-returning function without "
"returning a value";

case SanitizerHandler::MulOverflow:
return "Signed integer multiplication overflowed";

case SanitizerHandler::NegateOverflow:
return "Signed integer negation overflowed";

case SanitizerHandler::NullabilityArg:
return "Passing null as an argument which is annotated with "
"_Nonnull";

case SanitizerHandler::NullabilityReturn:
return "Returning null from a function with a return type annotated with "
"_Nonnull";

case SanitizerHandler::NonnullArg:
return "Passing null pointer as an argument which is declared to never be "
"null";

case SanitizerHandler::NonnullReturn:
return "Returning null pointer from a function which is declared to never "
"return null";

case SanitizerHandler::OutOfBounds:
return "Array index out of bounds";

case SanitizerHandler::PointerOverflow:
return "Pointer arithmetic overflowed bounds";

case SanitizerHandler::ShiftOutOfBounds:
return "Shift exponent is too large for the type";

case SanitizerHandler::SubOverflow:
return "Signed integer subtraction overflowed";

case SanitizerHandler::TypeMismatch:
return "Type mismatch in operation";

case SanitizerHandler::AlignmentAssumption:
return "Alignment assumption violated";

case SanitizerHandler::VLABoundNotPositive:
return "Variable length array bound evaluates to non-positive value";

case SanitizerHandler::BoundsSafety:
Copy link
Member

Choose a reason for hiding this comment

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

Should we leave a comment here explaining why BoundsSafety isn't handled like the other enums here?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes we should do that

// Not added as of current, will be added in future patch.
return {};
}
}

/// CreateTempAlloca - This creates a alloca and inserts it into the entry
/// block.
RawAddress
Expand Down Expand Up @@ -4051,6 +4141,27 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,

llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID];

llvm::DILocation *TrapLocation = Builder.getCurrentDebugLocation();
llvm::StringRef TrapMessage = GetUBSanTrapForHandler(CheckHandlerID);

// Explicitly used to prevent infinite wrapping in cfi-check-fail-debuginfo.c
// test
auto NeedsAnnotation = [](llvm::DILocation *Loc) {
if (!Loc)
return false;
if (Loc->getLine() != 0)
return true;
if (auto *SubProgram =
llvm::dyn_cast_or_null<llvm::DISubprogram>(Loc->getScope()))
return (SubProgram->getFile() != nullptr);
return false;
};

if (getDebugInfo() && NeedsAnnotation(TrapLocation) && !TrapMessage.empty()) {
TrapLocation = getDebugInfo()->CreateTrapFailureMessageFor(
TrapLocation, "Undefined Behavior Sanitizer", TrapMessage);
}

NoMerge = NoMerge || !CGM.getCodeGenOpts().OptimizationLevel ||
(CurCodeDecl && CurCodeDecl->hasAttr<OptimizeNoneAttr>());

Expand All @@ -4059,8 +4170,8 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
auto Call = TrapBB->begin();
assert(isa<llvm::CallInst>(Call) && "Expected call in trap BB");

Call->applyMergedLocation(Call->getDebugLoc(),
Builder.getCurrentDebugLocation());
Call->applyMergedLocation(Call->getDebugLoc(), TrapLocation);

Builder.CreateCondBr(Checked, Cont, TrapBB,
MDHelper.createLikelyBranchWeights());
} else {
Expand All @@ -4069,6 +4180,8 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
MDHelper.createLikelyBranchWeights());
EmitBlock(TrapBB);

ApplyDebugLocation applyTrapDI(*this, TrapLocation);

llvm::CallInst *TrapCall =
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::ubsantrap),
llvm::ConstantInt::get(CGM.Int8Ty, CheckHandlerID));
Expand Down
18 changes: 10 additions & 8 deletions clang/test/CodeGen/bounds-checking-debuginfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ void d(double*);
// CHECK-TRAP-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 10, !dbg [[DBG23]], !nosanitize [[META10]]
// CHECK-TRAP-NEXT: br i1 [[TMP1]], label %[[CONT:.*]], label %[[TRAP:.*]], !dbg [[DBG23]], !prof [[PROF27:![0-9]+]], !nosanitize [[META10]]
// CHECK-TRAP: [[TRAP]]:
// 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-NEXT: call void @llvm.ubsantrap(i8 18) #[[ATTR3:[0-9]+]], !dbg [[DBG28:![0-9]+]], !nosanitize [[META10]]
// CHECK-TRAP-NEXT: unreachable, !dbg [[DBG28]], !nosanitize [[META10]]
// CHECK-TRAP: [[CONT]]:
// 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 [[DBG28:![0-9]+]]
// CHECK-TRAP-NEXT: ret double [[TMP2]], !dbg [[DBG30:![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 Down Expand Up @@ -68,9 +68,9 @@ double f1(int b, int i) {

//.
// CHECK-TRAP: [[META0:![0-9]+]] = distinct !DICompileUnit(language: DW_LANG_C11, file: [[META1:![0-9]+]], isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
// CHECK-TRAP: [[META1]] = !DIFile(filename: "<stdin>", directory: {{.*}})
// CHECK-TRAP: [[META1]] = !DIFile(filename: "{{.*}}<stdin>", directory: {{.*}})
// CHECK-TRAP: [[DBG4]] = distinct !DISubprogram(name: "f1", scope: [[META5:![0-9]+]], file: [[META5]], line: 63, type: [[META6:![0-9]+]], scopeLine: 63, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META10]])
// CHECK-TRAP: [[META5]] = !DIFile(filename: "bounds-checking-debuginfo.c", directory: {{.*}})
// CHECK-TRAP: [[META5]] = !DIFile(filename: "{{.*}}bounds-checking-debuginfo.c", directory: {{.*}})
// CHECK-TRAP: [[META6]] = !DISubroutineType(types: [[META7:![0-9]+]])
// CHECK-TRAP: [[META7]] = !{[[META8:![0-9]+]], [[META9:![0-9]+]], [[META9]]}
// CHECK-TRAP: [[META8]] = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float)
Expand All @@ -93,12 +93,14 @@ double f1(int b, int i) {
// 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}
// CHECK-TRAP: [[DBG28]] = !DILocation(line: 66, column: 3, scope: [[DBG4]])
// CHECK-TRAP: [[DBG28]] = !DILocation(line: 0, scope: [[META29:![0-9]+]], inlinedAt: [[DBG23]])
// CHECK-TRAP: [[META29]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Array index out of bounds", scope: [[META5]], file: [[META5]], type: [[META25]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
// CHECK-TRAP: [[DBG30]] = !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: {{.*}})
// CHECK-NOTRAP: [[META1]] = !DIFile(filename: "{{.*}}<stdin>", directory: {{.*}})
// CHECK-NOTRAP: [[DBG4]] = distinct !DISubprogram(name: "f1", scope: [[META5:![0-9]+]], file: [[META5]], line: 63, type: [[META6:![0-9]+]], scopeLine: 63, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: [[META0]], retainedNodes: [[META10]])
// CHECK-NOTRAP: [[META5]] = !DIFile(filename: "bounds-checking-debuginfo.c", directory: {{.*}})
// CHECK-NOTRAP: [[META5]] = !DIFile(filename: "{{.*}}bounds-checking-debuginfo.c", directory: {{.*}})
// CHECK-NOTRAP: [[META6]] = !DISubroutineType(types: [[META7:![0-9]+]])
// CHECK-NOTRAP: [[META7]] = !{[[META8:![0-9]+]], [[META9:![0-9]+]], [[META9]]}
// CHECK-NOTRAP: [[META8]] = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float)
Expand Down
20 changes: 12 additions & 8 deletions clang/test/CodeGen/cfi-icall-generalize-debuginfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ int** f(const char *a, const char **b) {
// 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 [[META38]]
// UNGENERALIZED-NEXT: unreachable, !dbg [[DBG34]], !nosanitize [[META38]]
// UNGENERALIZED-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !dbg [[DBG40:![0-9]+]], !nosanitize [[META38]]
// UNGENERALIZED-NEXT: unreachable, !dbg [[DBG40]], !nosanitize [[META38]]
// UNGENERALIZED: [[CONT]]:
// 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]+]]
// UNGENERALIZED-NEXT: ret void, !dbg [[DBG42:![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]+]] {
Expand All @@ -43,11 +43,11 @@ int** f(const char *a, const char **b) {
// 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 [[META38]]
// GENERALIZED-NEXT: unreachable, !dbg [[DBG34]], !nosanitize [[META38]]
// GENERALIZED-NEXT: tail call void @llvm.ubsantrap(i8 2) #[[ATTR4:[0-9]+]], !dbg [[DBG40:![0-9]+]], !nosanitize [[META38]]
// GENERALIZED-NEXT: unreachable, !dbg [[DBG40]], !nosanitize [[META38]]
// GENERALIZED: [[CONT]]:
// 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]+]]
// GENERALIZED-NEXT: ret void, !dbg [[DBG42:![0-9]+]]
//
void g(int** (*fp)(const char *, const char **)) {
fp(0, 0);
Expand Down Expand Up @@ -90,7 +90,9 @@ void g(int** (*fp)(const char *, const char **)) {
// 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]])
// UNGENERALIZED: [[DBG40]] = !DILocation(line: 0, scope: [[META41:![0-9]+]], inlinedAt: [[DBG34]])
// UNGENERALIZED: [[META41]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Control flow integrity check failed", scope: [[META11]], file: [[META11]], type: [[META36]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
// UNGENERALIZED: [[DBG42]] = !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]+]], splitDebugInlining: false, nameTableKind: None)
// GENERALIZED: [[META1]] = !DIFile(filename: "{{.*}}<stdin>", directory: {{.*}})
Expand Down Expand Up @@ -128,5 +130,7 @@ void g(int** (*fp)(const char *, const char **)) {
// GENERALIZED: [[DBG37]] = !DILocation(line: 53, column: 3, scope: [[DBG25]])
// GENERALIZED: [[META38]] = !{}
// GENERALIZED: [[PROF39]] = !{!"branch_weights", i32 1048575, i32 1}
// GENERALIZED: [[DBG40]] = !DILocation(line: 54, column: 1, scope: [[DBG25]])
// GENERALIZED: [[DBG40]] = !DILocation(line: 0, scope: [[META41:![0-9]+]], inlinedAt: [[DBG34]])
// GENERALIZED: [[META41]] = distinct !DISubprogram(name: "__clang_trap_msg$Undefined Behavior Sanitizer$Control flow integrity check failed", scope: [[META11]], file: [[META11]], type: [[META36]], flags: DIFlagArtificial, spFlags: DISPFlagDefinition, unit: [[META0]])
// GENERALIZED: [[DBG42]] = !DILocation(line: 54, column: 1, scope: [[DBG25]])
//.
Loading