summaryrefslogtreecommitdiff
path: root/clang/lib/Analysis/UnsafeBufferUsage.cpp
diff options
context:
space:
mode:
authorZiqing Luo <ziqing_luo@apple.com>2025-11-17 13:43:53 -0800
committerGitHub <noreply@github.com>2025-11-17 13:43:53 -0800
commit3f60d220514c4be00e548a17a85c2fa8fa89cc35 (patch)
treee38dbeeda2a4848304632b587f2f501b8edaea0b /clang/lib/Analysis/UnsafeBufferUsage.cpp
parent92c8c87c49100e3f14e3ec46abf47f27191f8b53 (diff)
[-Wunsafe-buffer-usage] Fold the expression "cond ? E1 : E2" when checking safe patterns, if "cond" is a constant (#167989)
In `-Wunsafe-buffer-usage`, many safe pattern checks can benefit from constant folding. This commit improves null-terminated pointer checks by folding conditional expressions. rdar://159374822 --------- Co-authored-by: Balázs Benics <benicsbalazs@gmail.com>
Diffstat (limited to 'clang/lib/Analysis/UnsafeBufferUsage.cpp')
-rw-r--r--clang/lib/Analysis/UnsafeBufferUsage.cpp26
1 files changed, 21 insertions, 5 deletions
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index f5a368636c43..da155d31d4a8 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -781,9 +781,25 @@ struct LibcFunNamePrefixSuffixParser {
}
};
+// Constant fold a conditional expression 'cond ? A : B' to
+// - 'A', if 'cond' has constant true value;
+// - 'B', if 'cond' has constant false value.
+static const Expr *tryConstantFoldConditionalExpr(const Expr *E,
+ const ASTContext &Ctx) {
+ // FIXME: more places can use this function
+ if (const auto *CE = dyn_cast<ConditionalOperator>(E)) {
+ bool CondEval;
+
+ if (CE->getCond()->EvaluateAsBooleanCondition(CondEval, Ctx))
+ return CondEval ? CE->getLHS() : CE->getRHS();
+ }
+ return E;
+}
+
// A pointer type expression is known to be null-terminated, if it has the
// form: E.c_str(), for any expression E of `std::string` type.
-static bool isNullTermPointer(const Expr *Ptr) {
+static bool isNullTermPointer(const Expr *Ptr, ASTContext &Ctx) {
+ Ptr = tryConstantFoldConditionalExpr(Ptr, Ctx);
if (isa<clang::StringLiteral>(Ptr->IgnoreParenImpCasts()))
return true;
if (isa<PredefinedExpr>(Ptr->IgnoreParenImpCasts()))
@@ -874,7 +890,7 @@ static bool hasUnsafeFormatOrSArg(const CallExpr *Call, const Expr *&UnsafeArg,
const Expr *Arg = Call->getArg(ArgIdx);
- if (isNullTermPointer(Arg))
+ if (isNullTermPointer(Arg, Ctx))
// If Arg is a null-terminated pointer, it is safe anyway.
return true; // continue parsing
@@ -922,8 +938,8 @@ static bool hasUnsafeFormatOrSArg(const CallExpr *Call, const Expr *&UnsafeArg,
// (including the format argument) is unsafe pointer.
return llvm::any_of(
llvm::make_range(Call->arg_begin() + FmtArgIdx, Call->arg_end()),
- [&UnsafeArg](const Expr *Arg) -> bool {
- if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg)) {
+ [&UnsafeArg, &Ctx](const Expr *Arg) -> bool {
+ if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg, Ctx)) {
UnsafeArg = Arg;
return true;
}
@@ -1175,7 +1191,7 @@ static bool hasUnsafePrintfStringArg(const CallExpr &Node, ASTContext &Ctx,
// We don't really recognize this "normal" printf, the only thing we
// can do is to require all pointers to be null-terminated:
for (const auto *Arg : Node.arguments())
- if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg)) {
+ if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg, Ctx)) {
Result.addNode(Tag, DynTypedNode::create(*Arg));
return true;
}