https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/104741
>From fdadb0fdc2288b18d4dfe4f4510d057a7552ee39 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng <dtcxzyw2...@gmail.com> Date: Mon, 19 Aug 2024 15:22:39 +0800 Subject: [PATCH 1/4] [UBSan] Diagnose assumption violation --- clang/lib/CodeGen/CGBuiltin.cpp | 18 ++++++++++++------ clang/lib/CodeGen/CGStmt.cpp | 3 ++- clang/lib/CodeGen/CodeGenFunction.h | 1 + clang/test/CodeGen/ubsan-builtin-checks.c | 17 +++++++++++++++++ compiler-rt/lib/ubsan/ubsan_handlers.cpp | 9 ++++++--- compiler-rt/lib/ubsan/ubsan_handlers.h | 1 + .../test/ubsan/TestCases/Misc/builtins.cpp | 16 ++++++++++++++-- 7 files changed, 53 insertions(+), 12 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 942468204f054c..7e93e46d3f92b9 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -1997,16 +1997,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()), @@ -3428,7 +3433,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 623857b43a5575..470ba3af0edc9b 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 && Builder.GetInsertBlock() && !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 2df17e83bae2ee..aa312e055ce71f 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -5084,6 +5084,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 9dbe8e6c0c1745..bc8fc02d4d203e 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.cpp +++ b/compiler-rt/lib/ubsan/ubsan_handlers.cpp @@ -633,9 +633,12 @@ static void handleInvalidBuiltin(InvalidBuiltinData *Data, ReportOptions Opts) { ScopedReport R(Opts, Loc, ET); - Diag(Loc, DL_Error, ET, - "passing zero to __builtin_%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 __builtin_%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 a635f7fcc686ed..2702065bce0678 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; } >From 6cce5061d91345182b295696cc2f2abb84ff39a5 Mon Sep 17 00:00:00 2001 From: Vitaly Buka <vitalyb...@google.com> Date: Tue, 24 Sep 2024 15:54:18 -0700 Subject: [PATCH 2/4] Extract EmitCheckedArgForAssume --- clang/lib/CodeGen/CGBuiltin.cpp | 33 ++++++++++++++++++----------- clang/lib/CodeGen/CGStmt.cpp | 3 +-- clang/lib/CodeGen/CodeGenFunction.h | 4 ++++ 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 7e93e46d3f92b9..ac7b54a32c8009 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -1997,21 +1997,16 @@ struct CallObjCArcUse final : EHScopeStack::Cleanup { Value *CodeGenFunction::EmitCheckedArgForBuiltin(const Expr *E, BuiltinCheckKind Kind) { - assert((Kind == BCK_CLZPassedZero || Kind == BCK_CTZPassedZero || - Kind == BCK_AssumePassedFalse) && - "Unsupported builtin check kind"); + assert((Kind == BCK_CLZPassedZero || Kind == BCK_CTZPassedZero) + && "Unsupported builtin check kind"); - Value *ArgValue = - Kind == BCK_AssumePassedFalse ? EvaluateExprAsBool(E) : EmitScalarExpr(E); + Value *ArgValue = EmitScalarExpr(E); if (!SanOpts.has(SanitizerKind::Builtin)) return ArgValue; SanitizerScope SanScope(this); - Value *Cond = - Kind == BCK_AssumePassedFalse - ? ArgValue - : Builder.CreateICmpNE( - ArgValue, llvm::Constant::getNullValue(ArgValue->getType())); + Value *Cond = Builder.CreateICmpNE( + ArgValue, llvm::Constant::getNullValue(ArgValue->getType())); EmitCheck(std::make_pair(Cond, SanitizerKind::Builtin), SanitizerHandler::InvalidBuiltin, {EmitCheckSourceLocation(E->getExprLoc()), @@ -2020,6 +2015,21 @@ Value *CodeGenFunction::EmitCheckedArgForBuiltin(const Expr *E, return ArgValue; } +Value *CodeGenFunction::EmitCheckedArgForAssume(const Expr *E) { + Value *ArgValue = EvaluateExprAsBool(E); + if (!SanOpts.has(SanitizerKind::Builtin)) + return ArgValue; + + SanitizerScope SanScope(this); + EmitCheck( + std::make_pair(ArgValue, SanitizerKind::Builtin), + SanitizerHandler::InvalidBuiltin, + {EmitCheckSourceLocation(E->getExprLoc()), + llvm::ConstantInt::get(Builder.getInt8Ty(), BCK_AssumePassedFalse)}, + std::nullopt); + return ArgValue; +} + static Value *EmitAbs(CodeGenFunction &CGF, Value *ArgValue, bool HasNSW) { return CGF.Builder.CreateBinaryIntrinsic( Intrinsic::abs, ArgValue, @@ -3433,8 +3443,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, if (E->getArg(0)->HasSideEffects(getContext())) return RValue::get(nullptr); - Value *ArgValue = - EmitCheckedArgForBuiltin(E->getArg(0), BCK_AssumePassedFalse); + Value *ArgValue = EmitCheckedArgForAssume(E->getArg(0)); 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 470ba3af0edc9b..9bf15fca0de489 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -754,8 +754,7 @@ void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) { const Expr *Assumption = cast<CXXAssumeAttr>(A)->getAssumption(); if (getLangOpts().CXXAssumptions && Builder.GetInsertBlock() && !Assumption->HasSideEffects(getContext())) { - llvm::Value *AssumptionVal = - EmitCheckedArgForBuiltin(Assumption, BCK_AssumePassedFalse); + llvm::Value *AssumptionVal = EmitCheckedArgForAssume(Assumption); Builder.CreateAssumption(AssumptionVal); } } break; diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index aa312e055ce71f..d4e46f77868eca 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -5091,6 +5091,10 @@ class CodeGenFunction : public CodeGenTypeCache { /// enabled, a runtime check specified by \p Kind is also emitted. llvm::Value *EmitCheckedArgForBuiltin(const Expr *E, BuiltinCheckKind Kind); + /// Emits an argument for a call to a `__builtin_assume`. If the builtin + /// sanitizer is enabled, a runtime check is also emitted. + llvm::Value *EmitCheckedArgForAssume(const Expr *E); + /// Emit a description of a type in a format suitable for passing to /// a runtime sanitizer handler. llvm::Constant *EmitCheckTypeDescriptor(QualType T); >From 7bcaa3bb81e54edc440abc2b4d5ac85289c6b522 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng <dtcxzyw2...@gmail.com> Date: Wed, 25 Sep 2024 12:58:16 +0800 Subject: [PATCH 3/4] format --- clang/lib/CodeGen/CGBuiltin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index ac7b54a32c8009..7bbf22569e73ca 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -1997,8 +1997,8 @@ 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) && + "Unsupported builtin check kind"); Value *ArgValue = EmitScalarExpr(E); if (!SanOpts.has(SanitizerKind::Builtin)) >From 78c2bcc6a5e2cc0181cd210414401d4f738b9954 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng <dtcxzyw2...@gmail.com> Date: Wed, 25 Sep 2024 13:10:31 +0800 Subject: [PATCH 4/4] Format --- compiler-rt/lib/ubsan/ubsan_handlers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.cpp b/compiler-rt/lib/ubsan/ubsan_handlers.cpp index bc8fc02d4d203e..a419cf0b2b5557 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.cpp +++ b/compiler-rt/lib/ubsan/ubsan_handlers.cpp @@ -637,7 +637,7 @@ static void handleInvalidBuiltin(InvalidBuiltinData *Data, ReportOptions Opts) { Diag(Loc, DL_Error, ET, "assumption is violated during execution"); else Diag(Loc, DL_Error, ET, - "passing zero to __builtin_%0(), which is not a valid argument") + "passing zero to __builtin_%0(), which is not a valid argument") << ((Data->Kind == BCK_CTZPassedZero) ? "ctz" : "clz"); } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits