https://github.com/pskrgag created
https://github.com/llvm/llvm-project/pull/136589
According to
https://clang.llvm.org/docs/LanguageExtensions.html#checked-arithmetic-builtins,
result of builtin_*_overflow functions will be initialized even in case of
overflow. Align analyzer logic to docs and always initialize 3rd argument of
such builtins.
Closes #136292
>From 0b457d93ca69598b6245c1ce2086ae117134dede Mon Sep 17 00:00:00 2001
From: Pavel Skripkin
Date: Sun, 20 Apr 2025 10:14:41 -0400
Subject: [PATCH] [clang][analyzer] Fix error path of builtin overflow
(#136345)
According to
https://clang.llvm.org/docs/LanguageExtensions.html#checked-arithmetic-builtins,
result of builtin_*_overflow functions will be initialized even in case
of overflow. Align analyzer logic to docs and always initialize 3rd
argument of such builtins.
Closes #136292
---
.../Checkers/BuiltinFunctionChecker.cpp | 86 +++
clang/test/Analysis/builtin_overflow.c| 6 +-
clang/test/Analysis/builtin_overflow_notes.c | 10 ++-
3 files changed, 58 insertions(+), 44 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index cfdd3c9faa360..bcc4ca77f5887 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -97,10 +97,14 @@ class BuiltinFunctionChecker : public Checker {
void handleOverflowBuiltin(const CallEvent &Call, CheckerContext &C,
BinaryOperator::Opcode Op,
QualType ResultType) const;
- const NoteTag *createBuiltinNoOverflowNoteTag(CheckerContext &C,
-bool BothFeasible, SVal Arg1,
-SVal Arg2, SVal Result) const;
- const NoteTag *createBuiltinOverflowNoteTag(CheckerContext &C) const;
+ const NoteTag *createBuiltinOverflowNoteTag(CheckerContext &C,
+ bool BothFeasible, SVal Arg1,
+ SVal Arg2, SVal Result) const;
+ ProgramStateRef initStateAftetBuiltinOverflow(CheckerContext &C,
+ProgramStateRef State,
+const CallEvent &Call,
+SVal RetCal,
+bool IsOverflow) const;
std::pair checkOverflow(CheckerContext &C, SVal RetVal,
QualType Res) const;
@@ -122,30 +126,24 @@ class BuiltinFunctionChecker : public Checker
{
} // namespace
-const NoteTag *BuiltinFunctionChecker::createBuiltinNoOverflowNoteTag(
-CheckerContext &C, bool BothFeasible, SVal Arg1, SVal Arg2,
-SVal Result) const {
- return C.getNoteTag([Result, Arg1, Arg2, BothFeasible](
- PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
+const NoteTag *BuiltinFunctionChecker::createBuiltinOverflowNoteTag(
+CheckerContext &C, bool overflow, SVal Arg1, SVal Arg2, SVal Result) const
{
+ return C.getNoteTag([Result, Arg1, Arg2, overflow](PathSensitiveBugReport
&BR,
+ llvm::raw_ostream &OS) {
if (!BR.isInteresting(Result))
return;
-// Propagate interestingness to input argumets if result is interesting.
+// Propagate interestingness to input arguments if result is interesting.
BR.markInteresting(Arg1);
BR.markInteresting(Arg2);
-if (BothFeasible)
+if (overflow)
+ OS << "Assuming overflow";
+else
OS << "Assuming no overflow";
});
}
-const NoteTag *
-BuiltinFunctionChecker::createBuiltinOverflowNoteTag(CheckerContext &C) const {
- return C.getNoteTag([](PathSensitiveBugReport &BR,
- llvm::raw_ostream &OS) { OS << "Assuming overflow"; },
- /*isPrunable=*/true);
-}
-
std::pair
BuiltinFunctionChecker::checkOverflow(CheckerContext &C, SVal RetVal,
QualType Res) const {
@@ -175,6 +173,29 @@ BuiltinFunctionChecker::checkOverflow(CheckerContext &C,
SVal RetVal,
return {MayOverflow || MayUnderflow, MayNotOverflow && MayNotUnderflow};
}
+ProgramStateRef BuiltinFunctionChecker::initStateAftetBuiltinOverflow(
+CheckerContext &C, ProgramStateRef State, const CallEvent &Call,
+SVal RetVal, bool IsOverflow) const {
+ SValBuilder &SVB = C.getSValBuilder();
+ SVal Arg1 = Call.getArgSVal(0);
+ SVal Arg2 = Call.getArgSVal(1);
+ auto BoolTy = C.getASTContext().BoolTy;
+
+ ProgramStateRef NewState =
+ State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
+ SVB.makeTruthVal(IsOverflow, BoolTy));
+
+ if (auto L = Call.getArgSVal(2).getAs()) {
+NewState = NewState->bindLoc(*L, RetVal, C.getLocationContext());
+
+