[clang] [compiler-rt] [UBSan] Diagnose assumption violation (PR #104741)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 19 00:29:25 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Yingwei Zheng (dtcxzyw)
<details>
<summary>Changes</summary>
This patch extends [D34590](https://reviews.llvm.org/D34590) to check assumption violations.
---
Full diff: https://github.com/llvm/llvm-project/pull/104741.diff
7 Files Affected:
- (modified) clang/lib/CodeGen/CGBuiltin.cpp (+12-6)
- (modified) clang/lib/CodeGen/CGStmt.cpp (+2-1)
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+1)
- (modified) clang/test/CodeGen/ubsan-builtin-checks.c (+17)
- (modified) compiler-rt/lib/ubsan/ubsan_handlers.cpp (+5-3)
- (modified) compiler-rt/lib/ubsan/ubsan_handlers.h (+1)
- (modified) compiler-rt/test/ubsan/TestCases/Misc/builtins.cpp (+14-2)
``````````diff
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index f424ddaa175400..83da5d7d75be3b 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -1996,16 +1996,21 @@ struct CallObjCArcUse final : EHScopeStack::Cleanup {
Value *CodeGenFunction::EmitCheckedArgForBuiltin(const Expr *E,
BuiltinCheckKind Kind) {
- assert((Kind == BCK_CLZPassedZero || Kind == BCK_CTZPassedZero)
- && "Unsupported builtin check kind");
+ assert((Kind == BCK_CLZPassedZero || Kind == BCK_CTZPassedZero ||
+ Kind == BCK_AssumePassedFalse) &&
+ "Unsupported builtin check kind");
- Value *ArgValue = EmitScalarExpr(E);
+ Value *ArgValue =
+ Kind == BCK_AssumePassedFalse ? EvaluateExprAsBool(E) : EmitScalarExpr(E);
if (!SanOpts.has(SanitizerKind::Builtin))
return ArgValue;
SanitizerScope SanScope(this);
- Value *Cond = Builder.CreateICmpNE(
- ArgValue, llvm::Constant::getNullValue(ArgValue->getType()));
+ Value *Cond =
+ Kind == BCK_AssumePassedFalse
+ ? ArgValue
+ : Builder.CreateICmpNE(
+ ArgValue, llvm::Constant::getNullValue(ArgValue->getType()));
EmitCheck(std::make_pair(Cond, SanitizerKind::Builtin),
SanitizerHandler::InvalidBuiltin,
{EmitCheckSourceLocation(E->getExprLoc()),
@@ -3424,7 +3429,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
if (E->getArg(0)->HasSideEffects(getContext()))
return RValue::get(nullptr);
- Value *ArgValue = EmitScalarExpr(E->getArg(0));
+ Value *ArgValue =
+ EmitCheckedArgForBuiltin(E->getArg(0), BCK_AssumePassedFalse);
Function *FnAssume = CGM.getIntrinsic(Intrinsic::assume);
Builder.CreateCall(FnAssume, ArgValue);
return RValue::get(nullptr);
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 7158a06e6bc3b3..291639346d8952 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -754,7 +754,8 @@ void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
const Expr *Assumption = cast<CXXAssumeAttr>(A)->getAssumption();
if (getLangOpts().CXXAssumptions &&
!Assumption->HasSideEffects(getContext())) {
- llvm::Value *AssumptionVal = EvaluateExprAsBool(Assumption);
+ llvm::Value *AssumptionVal =
+ EmitCheckedArgForBuiltin(Assumption, BCK_AssumePassedFalse);
Builder.CreateAssumption(AssumptionVal);
}
} break;
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 57e0b7f91e9bf8..99db330f3316e5 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -5070,6 +5070,7 @@ class CodeGenFunction : public CodeGenTypeCache {
enum BuiltinCheckKind {
BCK_CTZPassedZero,
BCK_CLZPassedZero,
+ BCK_AssumePassedFalse,
};
/// Emits an argument for a call to a builtin. If the builtin sanitizer is
diff --git a/clang/test/CodeGen/ubsan-builtin-checks.c b/clang/test/CodeGen/ubsan-builtin-checks.c
index c7f6078f903bad..8535ec915ac346 100644
--- a/clang/test/CodeGen/ubsan-builtin-checks.c
+++ b/clang/test/CodeGen/ubsan-builtin-checks.c
@@ -51,3 +51,20 @@ void check_clz(int n) {
// CHECK: call void @__ubsan_handle_invalid_builtin
__builtin_clzg((unsigned int)n);
}
+
+// CHECK: define{{.*}} void @check_assume
+void check_assume(int n) {
+ // CHECK: [[TOBOOL:%.*]] = icmp ne i32 [[N:%.*]], 0
+ // CHECK-NEXT: br i1 [[TOBOOL]]
+ //
+ // Handler block:
+ // CHECK: call void @__ubsan_handle_invalid_builtin
+ // CHECK-NEXT: unreachable
+ //
+ // Continuation block:
+ // CHECK: call void @llvm.assume(i1 [[TOBOOL]])
+ __builtin_assume(n);
+
+ // CHECK: call void @__ubsan_handle_invalid_builtin
+ __attribute__((assume(n)));
+}
diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.cpp b/compiler-rt/lib/ubsan/ubsan_handlers.cpp
index 27d01653f088da..44aec6b8b05cd2 100644
--- a/compiler-rt/lib/ubsan/ubsan_handlers.cpp
+++ b/compiler-rt/lib/ubsan/ubsan_handlers.cpp
@@ -633,9 +633,11 @@ static void handleInvalidBuiltin(InvalidBuiltinData *Data, ReportOptions Opts) {
ScopedReport R(Opts, Loc, ET);
- Diag(Loc, DL_Error, ET,
- "passing zero to %0, which is not a valid argument")
- << ((Data->Kind == BCK_CTZPassedZero) ? "ctz()" : "clz()");
+ if (Data->Kind == BCK_AssumePassedFalse)
+ Diag(Loc, DL_Error, ET, "assumption is violated during execution");
+ else
+ Diag(Loc, DL_Error, ET, "passing zero to %0, which is not a valid argument")
+ << ((Data->Kind == BCK_CTZPassedZero) ? "ctz()" : "clz()");
}
void __ubsan::__ubsan_handle_invalid_builtin(InvalidBuiltinData *Data) {
diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.h b/compiler-rt/lib/ubsan/ubsan_handlers.h
index bae661a56833dd..4ffa1439a1323f 100644
--- a/compiler-rt/lib/ubsan/ubsan_handlers.h
+++ b/compiler-rt/lib/ubsan/ubsan_handlers.h
@@ -159,6 +159,7 @@ RECOVERABLE(implicit_conversion, ImplicitConversionData *Data, ValueHandle Src,
enum BuiltinCheckKind : unsigned char {
BCK_CTZPassedZero,
BCK_CLZPassedZero,
+ BCK_AssumePassedFalse,
};
struct InvalidBuiltinData {
diff --git a/compiler-rt/test/ubsan/TestCases/Misc/builtins.cpp b/compiler-rt/test/ubsan/TestCases/Misc/builtins.cpp
index f8f564cb7baae2..3ebc8094298a0a 100644
--- a/compiler-rt/test/ubsan/TestCases/Misc/builtins.cpp
+++ b/compiler-rt/test/ubsan/TestCases/Misc/builtins.cpp
@@ -1,8 +1,8 @@
// REQUIRES: target={{x86_64.*}}
//
-// RUN: %clangxx -fsanitize=builtin -w %s -O3 -o %t
+// RUN: %clangxx -fsanitize=builtin -fno-inline -w %s -O3 -o %t
// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER
-// RUN: %clangxx -fsanitize=builtin -fno-sanitize-recover=builtin -w %s -O3 -o %t.abort
+// RUN: %clangxx -fsanitize=builtin -fno-inline -fno-sanitize-recover=builtin -w %s -O3 -o %t.abort
// RUN: not %run %t.abort 2>&1 | FileCheck %s --check-prefix=ABORT
void check_ctz(int n) {
@@ -28,8 +28,20 @@ void check_clz(int n) {
__builtin_clzll(n);
}
+void check_assume(int n) {
+ // RECOVER: builtins.cpp:[[@LINE+1]]:20: runtime error: assumption is violated during execution
+ __builtin_assume(n);
+}
+
+void check_assume_attr(int n) {
+ // RECOVER: builtins.cpp:[[@LINE+1]]:25: runtime error: assumption is violated during execution
+ __attribute__((assume(n)));
+}
+
int main() {
check_ctz(0);
check_clz(0);
+ check_assume(0);
+ check_assume_attr(0);
return 0;
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/104741
More information about the cfe-commits
mailing list