aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/StaticAnalyzer
diff options
context:
space:
mode:
authorBaranov Victor <bar.victor.2002@gmail.com>2025-06-24 21:18:15 +0300
committerGitHub <noreply@github.com>2025-06-24 20:18:15 +0200
commitde2ec228c03c3072782b6fbcb43388a4556b90b2 (patch)
treed658b2698f4246bda17089764f4afb1ec9a5bc2a /clang/lib/StaticAnalyzer
parent9e33cb22f991fb25d606d89c0e5a13a3ebed52fe (diff)
downloadllvm-de2ec228c03c3072782b6fbcb43388a4556b90b2.zip
llvm-de2ec228c03c3072782b6fbcb43388a4556b90b2.tar.gz
llvm-de2ec228c03c3072782b6fbcb43388a4556b90b2.tar.bz2
[analyzer] Fix crash when modelling 'getline' function in checkers (#145229)
Fixes #144884
Diffstat (limited to 'clang/lib/StaticAnalyzer')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp40
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp32
2 files changed, 47 insertions, 25 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 35e98a5..fa6e8e4 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -430,8 +430,8 @@ private:
CHECK_FN(checkGMemdup)
CHECK_FN(checkGMallocN)
CHECK_FN(checkGMallocN0)
- CHECK_FN(preGetdelim)
- CHECK_FN(checkGetdelim)
+ CHECK_FN(preGetDelimOrGetLine)
+ CHECK_FN(checkGetDelimOrGetLine)
CHECK_FN(checkReallocN)
CHECK_FN(checkOwnershipAttr)
@@ -445,15 +445,16 @@ private:
const CallDescriptionMap<CheckFn> PreFnMap{
// NOTE: the following CallDescription also matches the C++ standard
// library function std::getline(); the callback will filter it out.
- {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::preGetdelim},
- {{CDM::CLibrary, {"getdelim"}, 4}, &MallocChecker::preGetdelim},
+ {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::preGetDelimOrGetLine},
+ {{CDM::CLibrary, {"getdelim"}, 4}, &MallocChecker::preGetDelimOrGetLine},
};
const CallDescriptionMap<CheckFn> PostFnMap{
// NOTE: the following CallDescription also matches the C++ standard
// library function std::getline(); the callback will filter it out.
- {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::checkGetdelim},
- {{CDM::CLibrary, {"getdelim"}, 4}, &MallocChecker::checkGetdelim},
+ {{CDM::CLibrary, {"getline"}, 3}, &MallocChecker::checkGetDelimOrGetLine},
+ {{CDM::CLibrary, {"getdelim"}, 4},
+ &MallocChecker::checkGetDelimOrGetLine},
};
const CallDescriptionMap<CheckFn> FreeingMemFnMap{
@@ -1482,8 +1483,9 @@ static bool isFromStdNamespace(const CallEvent &Call) {
return FD->isInStdNamespace();
}
-void MallocChecker::preGetdelim(ProgramStateRef State, const CallEvent &Call,
- CheckerContext &C) const {
+void MallocChecker::preGetDelimOrGetLine(ProgramStateRef State,
+ const CallEvent &Call,
+ CheckerContext &C) const {
// Discard calls to the C++ standard library function std::getline(), which
// is completely unrelated to the POSIX getline() that we're checking.
if (isFromStdNamespace(Call))
@@ -1505,8 +1507,9 @@ void MallocChecker::preGetdelim(ProgramStateRef State, const CallEvent &Call,
C.addTransition(State);
}
-void MallocChecker::checkGetdelim(ProgramStateRef State, const CallEvent &Call,
- CheckerContext &C) const {
+void MallocChecker::checkGetDelimOrGetLine(ProgramStateRef State,
+ const CallEvent &Call,
+ CheckerContext &C) const {
// Discard calls to the C++ standard library function std::getline(), which
// is completely unrelated to the POSIX getline() that we're checking.
if (isFromStdNamespace(Call))
@@ -1518,14 +1521,19 @@ void MallocChecker::checkGetdelim(ProgramStateRef State, const CallEvent &Call,
if (!CE)
return;
- const auto LinePtr =
- getPointeeVal(Call.getArgSVal(0), State)->getAs<DefinedSVal>();
- const auto Size =
- getPointeeVal(Call.getArgSVal(1), State)->getAs<DefinedSVal>();
- if (!LinePtr || !Size || !LinePtr->getAsRegion())
+ const auto LinePtrOpt = getPointeeVal(Call.getArgSVal(0), State);
+ const auto SizeOpt = getPointeeVal(Call.getArgSVal(1), State);
+ if (!LinePtrOpt || !SizeOpt || LinePtrOpt->isUnknownOrUndef() ||
+ SizeOpt->isUnknownOrUndef())
+ return;
+
+ const auto LinePtr = LinePtrOpt->getAs<DefinedSVal>();
+ const auto Size = SizeOpt->getAs<DefinedSVal>();
+ const MemRegion *LinePtrReg = LinePtr->getAsRegion();
+ if (!LinePtrReg)
return;
- State = setDynamicExtent(State, LinePtr->getAsRegion(), *Size);
+ State = setDynamicExtent(State, LinePtrReg, *Size);
C.addTransition(MallocUpdateRefState(C, CE, State,
AllocationFamily(AF_Malloc), *LinePtr));
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 79d10d9..ce5887d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -83,7 +83,7 @@ public:
void CheckOpen(CheckerContext &C, const CallEvent &Call) const;
void CheckOpenAt(CheckerContext &C, const CallEvent &Call) const;
- void CheckGetDelim(CheckerContext &C, const CallEvent &Call) const;
+ void CheckGetDelimOrGetline(CheckerContext &C, const CallEvent &Call) const;
void CheckPthreadOnce(CheckerContext &C, const CallEvent &Call) const;
void CheckOpenVariant(CheckerContext &C, const CallEvent &Call,
@@ -128,7 +128,7 @@ ProgramStateRef UnixAPIMisuseChecker::EnsurePtrNotNull(
const StringRef PtrDescr,
std::optional<std::reference_wrapper<const BugType>> BT) const {
const auto Ptr = PtrVal.getAs<DefinedSVal>();
- if (!Ptr)
+ if (!Ptr || !PtrExpr->getType()->isPointerType())
return State;
const auto [PtrNotNull, PtrNull] = State->assume(*Ptr);
@@ -177,7 +177,7 @@ void UnixAPIMisuseChecker::checkPreCall(const CallEvent &Call,
CheckPthreadOnce(C, Call);
else if (is_contained({"getdelim", "getline"}, FName))
- CheckGetDelim(C, Call);
+ CheckGetDelimOrGetline(C, Call);
}
void UnixAPIMisuseChecker::ReportOpenBug(CheckerContext &C,
ProgramStateRef State,
@@ -332,8 +332,12 @@ ProgramStateRef UnixAPIMisuseChecker::EnsureGetdelimBufferAndSizeCorrect(
// We have a pointer to a pointer to the buffer, and a pointer to the size.
// We want what they point at.
- auto LinePtrSVal = getPointeeVal(LinePtrPtrSVal, State)->getAs<DefinedSVal>();
- auto NSVal = getPointeeVal(SizePtrSVal, State);
+ const auto LinePtrValOpt = getPointeeVal(LinePtrPtrSVal, State);
+ if (!LinePtrValOpt)
+ return nullptr;
+
+ const auto LinePtrSVal = LinePtrValOpt->getAs<DefinedSVal>();
+ const auto NSVal = getPointeeVal(SizePtrSVal, State);
if (!LinePtrSVal || !NSVal || NSVal->isUnknown())
return nullptr;
@@ -350,9 +354,16 @@ ProgramStateRef UnixAPIMisuseChecker::EnsureGetdelimBufferAndSizeCorrect(
// If it is defined, and known, its size must be less than or equal to
// the buffer size.
auto NDefSVal = NSVal->getAs<DefinedSVal>();
+ if (!NDefSVal)
+ return LinePtrNotNull;
+
auto &SVB = C.getSValBuilder();
- auto LineBufSize =
- getDynamicExtent(LinePtrNotNull, LinePtrSVal->getAsRegion(), SVB);
+
+ const MemRegion *LinePtrRegion = LinePtrSVal->getAsRegion();
+ if (!LinePtrRegion)
+ return LinePtrNotNull;
+
+ auto LineBufSize = getDynamicExtent(LinePtrNotNull, LinePtrRegion, SVB);
auto LineBufSizeGtN = SVB.evalBinOp(LinePtrNotNull, BO_GE, LineBufSize,
*NDefSVal, SVB.getConditionType())
.getAs<DefinedOrUnknownSVal>();
@@ -367,8 +378,11 @@ ProgramStateRef UnixAPIMisuseChecker::EnsureGetdelimBufferAndSizeCorrect(
return State;
}
-void UnixAPIMisuseChecker::CheckGetDelim(CheckerContext &C,
- const CallEvent &Call) const {
+void UnixAPIMisuseChecker::CheckGetDelimOrGetline(CheckerContext &C,
+ const CallEvent &Call) const {
+ if (Call.getNumArgs() < 2)
+ return;
+
ProgramStateRef State = C.getState();
// The parameter `n` must not be NULL.