Skip to content

Commit d8f555d

Browse files
dtcxzywvitalybuka
andauthored
[UBSan] Diagnose assumption violation (#104741)
This patch extends [D34590](https://reviews.llvm.org/D34590) to check assumption violations. --------- Co-authored-by: Vitaly Buka <[email protected]>
1 parent fa824dc commit d8f555d

File tree

7 files changed

+62
-9
lines changed

7 files changed

+62
-9
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1997,8 +1997,8 @@ struct CallObjCArcUse final : EHScopeStack::Cleanup {
19971997

19981998
Value *CodeGenFunction::EmitCheckedArgForBuiltin(const Expr *E,
19991999
BuiltinCheckKind Kind) {
2000-
assert((Kind == BCK_CLZPassedZero || Kind == BCK_CTZPassedZero)
2001-
&& "Unsupported builtin check kind");
2000+
assert((Kind == BCK_CLZPassedZero || Kind == BCK_CTZPassedZero) &&
2001+
"Unsupported builtin check kind");
20022002

20032003
Value *ArgValue = EmitScalarExpr(E);
20042004
if (!SanOpts.has(SanitizerKind::Builtin))
@@ -2015,6 +2015,21 @@ Value *CodeGenFunction::EmitCheckedArgForBuiltin(const Expr *E,
20152015
return ArgValue;
20162016
}
20172017

2018+
Value *CodeGenFunction::EmitCheckedArgForAssume(const Expr *E) {
2019+
Value *ArgValue = EvaluateExprAsBool(E);
2020+
if (!SanOpts.has(SanitizerKind::Builtin))
2021+
return ArgValue;
2022+
2023+
SanitizerScope SanScope(this);
2024+
EmitCheck(
2025+
std::make_pair(ArgValue, SanitizerKind::Builtin),
2026+
SanitizerHandler::InvalidBuiltin,
2027+
{EmitCheckSourceLocation(E->getExprLoc()),
2028+
llvm::ConstantInt::get(Builder.getInt8Ty(), BCK_AssumePassedFalse)},
2029+
std::nullopt);
2030+
return ArgValue;
2031+
}
2032+
20182033
static Value *EmitAbs(CodeGenFunction &CGF, Value *ArgValue, bool HasNSW) {
20192034
return CGF.Builder.CreateBinaryIntrinsic(
20202035
Intrinsic::abs, ArgValue,
@@ -3428,7 +3443,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
34283443
if (E->getArg(0)->HasSideEffects(getContext()))
34293444
return RValue::get(nullptr);
34303445

3431-
Value *ArgValue = EmitScalarExpr(E->getArg(0));
3446+
Value *ArgValue = EmitCheckedArgForAssume(E->getArg(0));
34323447
Function *FnAssume = CGM.getIntrinsic(Intrinsic::assume);
34333448
Builder.CreateCall(FnAssume, ArgValue);
34343449
return RValue::get(nullptr);

clang/lib/CodeGen/CGStmt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
754754
const Expr *Assumption = cast<CXXAssumeAttr>(A)->getAssumption();
755755
if (getLangOpts().CXXAssumptions && Builder.GetInsertBlock() &&
756756
!Assumption->HasSideEffects(getContext())) {
757-
llvm::Value *AssumptionVal = EvaluateExprAsBool(Assumption);
757+
llvm::Value *AssumptionVal = EmitCheckedArgForAssume(Assumption);
758758
Builder.CreateAssumption(AssumptionVal);
759759
}
760760
} break;

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5084,12 +5084,17 @@ class CodeGenFunction : public CodeGenTypeCache {
50845084
enum BuiltinCheckKind {
50855085
BCK_CTZPassedZero,
50865086
BCK_CLZPassedZero,
5087+
BCK_AssumePassedFalse,
50875088
};
50885089

50895090
/// Emits an argument for a call to a builtin. If the builtin sanitizer is
50905091
/// enabled, a runtime check specified by \p Kind is also emitted.
50915092
llvm::Value *EmitCheckedArgForBuiltin(const Expr *E, BuiltinCheckKind Kind);
50925093

5094+
/// Emits an argument for a call to a `__builtin_assume`. If the builtin
5095+
/// sanitizer is enabled, a runtime check is also emitted.
5096+
llvm::Value *EmitCheckedArgForAssume(const Expr *E);
5097+
50935098
/// Emit a description of a type in a format suitable for passing to
50945099
/// a runtime sanitizer handler.
50955100
llvm::Constant *EmitCheckTypeDescriptor(QualType T);

clang/test/CodeGen/ubsan-builtin-checks.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,20 @@ void check_clz(int n) {
5151
// CHECK: call void @__ubsan_handle_invalid_builtin
5252
__builtin_clzg((unsigned int)n);
5353
}
54+
55+
// CHECK: define{{.*}} void @check_assume
56+
void check_assume(int n) {
57+
// CHECK: [[TOBOOL:%.*]] = icmp ne i32 [[N:%.*]], 0
58+
// CHECK-NEXT: br i1 [[TOBOOL]]
59+
//
60+
// Handler block:
61+
// CHECK: call void @__ubsan_handle_invalid_builtin
62+
// CHECK-NEXT: unreachable
63+
//
64+
// Continuation block:
65+
// CHECK: call void @llvm.assume(i1 [[TOBOOL]])
66+
__builtin_assume(n);
67+
68+
// CHECK: call void @__ubsan_handle_invalid_builtin
69+
__attribute__((assume(n)));
70+
}

compiler-rt/lib/ubsan/ubsan_handlers.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -633,9 +633,12 @@ static void handleInvalidBuiltin(InvalidBuiltinData *Data, ReportOptions Opts) {
633633

634634
ScopedReport R(Opts, Loc, ET);
635635

636-
Diag(Loc, DL_Error, ET,
637-
"passing zero to __builtin_%0(), which is not a valid argument")
638-
<< ((Data->Kind == BCK_CTZPassedZero) ? "ctz" : "clz");
636+
if (Data->Kind == BCK_AssumePassedFalse)
637+
Diag(Loc, DL_Error, ET, "assumption is violated during execution");
638+
else
639+
Diag(Loc, DL_Error, ET,
640+
"passing zero to __builtin_%0(), which is not a valid argument")
641+
<< ((Data->Kind == BCK_CTZPassedZero) ? "ctz" : "clz");
639642
}
640643

641644
void __ubsan::__ubsan_handle_invalid_builtin(InvalidBuiltinData *Data) {

compiler-rt/lib/ubsan/ubsan_handlers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ RECOVERABLE(implicit_conversion, ImplicitConversionData *Data, ValueHandle Src,
159159
enum BuiltinCheckKind : unsigned char {
160160
BCK_CTZPassedZero,
161161
BCK_CLZPassedZero,
162+
BCK_AssumePassedFalse,
162163
};
163164

164165
struct InvalidBuiltinData {

compiler-rt/test/ubsan/TestCases/Misc/builtins.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// REQUIRES: target={{x86_64.*}}
22
//
3-
// RUN: %clangxx -fsanitize=builtin -w %s -O3 -o %t
3+
// RUN: %clangxx -fsanitize=builtin -fno-inline -w %s -O3 -o %t
44
// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER
5-
// RUN: %clangxx -fsanitize=builtin -fno-sanitize-recover=builtin -w %s -O3 -o %t.abort
5+
// RUN: %clangxx -fsanitize=builtin -fno-inline -fno-sanitize-recover=builtin -w %s -O3 -o %t.abort
66
// RUN: not %run %t.abort 2>&1 | FileCheck %s --check-prefix=ABORT
77

88
void check_ctz(int n) {
@@ -28,8 +28,20 @@ void check_clz(int n) {
2828
__builtin_clzll(n);
2929
}
3030

31+
void check_assume(int n) {
32+
// RECOVER: builtins.cpp:[[@LINE+1]]:20: runtime error: assumption is violated during execution
33+
__builtin_assume(n);
34+
}
35+
36+
void check_assume_attr(int n) {
37+
// RECOVER: builtins.cpp:[[@LINE+1]]:25: runtime error: assumption is violated during execution
38+
__attribute__((assume(n)));
39+
}
40+
3141
int main() {
3242
check_ctz(0);
3343
check_clz(0);
44+
check_assume(0);
45+
check_assume_attr(0);
3446
return 0;
3547
}

0 commit comments

Comments
 (0)