24#include "llvm/ADT/STLExtras.h"
29using namespace errno_modeling;
34 :
public Checker<check::Location, check::PreCall, check::RegionChanges> {
36 void checkLocation(
SVal Loc,
bool IsLoad,
const Stmt *S,
50 bool AllowErrnoReadOutsideConditions =
true;
55 const CallEvent *CallMayChangeErrno)
const;
57 BugType BT_InvalidErrnoRead{
this,
"Value of 'errno' could be undefined",
59 BugType BT_ErrnoNotChecked{
this,
"Value of 'errno' was not checked",
73 bool CondFound =
false;
74 while (S && !CondFound) {
78 const auto *ParentS = Parents[0].get<
Stmt>();
79 if (!ParentS || isa<CallExpr>(ParentS))
81 switch (ParentS->getStmtClass()) {
82 case Expr::IfStmtClass:
83 CondFound = (S == cast<IfStmt>(ParentS)->getCond());
85 case Expr::ForStmtClass:
86 CondFound = (S == cast<ForStmt>(ParentS)->getCond());
88 case Expr::DoStmtClass:
89 CondFound = (S == cast<DoStmt>(ParentS)->getCond());
91 case Expr::WhileStmtClass:
92 CondFound = (S == cast<WhileStmt>(ParentS)->getCond());
94 case Expr::SwitchStmtClass:
95 CondFound = (S == cast<SwitchStmt>(ParentS)->getCond());
97 case Expr::ConditionalOperatorClass:
98 CondFound = (S == cast<ConditionalOperator>(ParentS)->getCond());
100 case Expr::BinaryConditionalOperatorClass:
101 CondFound = (S == cast<BinaryConditionalOperator>(ParentS)->getCommon());
111void ErrnoChecker::generateErrnoNotCheckedBug(
113 const CallEvent *CallMayChangeErrno)
const {
116 llvm::raw_svector_ostream OS(StrBuf);
117 if (CallMayChangeErrno) {
118 OS <<
"Value of 'errno' was not checked and may be overwritten by "
121 dyn_cast_or_null<FunctionDecl>(CallMayChangeErrno->
getDecl());
122 assert(CallD && CallD->getIdentifier());
123 OS << CallD->getIdentifier()->getName() <<
"'";
125 OS <<
"Value of 'errno' was not checked and is overwritten here";
127 auto BR = std::make_unique<PathSensitiveBugReport>(BT_ErrnoNotChecked,
129 BR->markInteresting(ErrnoRegion);
130 C.emitReport(std::move(BR));
134void ErrnoChecker::checkLocation(
SVal Loc,
bool IsLoad,
const Stmt *S,
136 std::optional<ento::Loc> ErrnoLoc =
getErrnoLoc(
C.getState());
141 if (!L || *ErrnoLoc != *L)
153 auto BR = std::make_unique<PathSensitiveBugReport>(
155 "An undefined value may be read from 'errno'", N);
156 BR->markInteresting(ErrnoLoc->getAsRegion());
157 C.emitReport(std::move(BR));
166 C.addTransition(State);
177 ErrnoLoc->getAsRegion(),
nullptr);
183 C.addTransition(State);
193 const auto *CallF = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
197 CallF = CallF->getCanonicalDecl();
206 if (CallF->isExternC() && CallF->isGlobal() &&
207 C.getSourceManager().isInSystemHeader(CallF->getLocation()) &&
210 std::optional<ento::Loc> ErrnoLoc =
getErrnoLoc(
C.getState());
211 assert(ErrnoLoc &&
"ErrnoLoc should exist if an errno state is set.");
213 ErrnoLoc->getAsRegion(), &
Call);
223 std::optional<ento::Loc> ErrnoLoc =
getErrnoLoc(State);
226 const MemRegion *ErrnoRegion = ErrnoLoc->getAsRegion();
230 if (llvm::is_contained(Regions, ErrnoRegion))
245 Checker,
"AllowErrnoReadOutsideConditionExpressions");
static bool isInCondition(const Stmt *S, CheckerContext &C)
Check if a statement (expression) or an ancestor of it is in a condition part of a (conditional,...
static ProgramStateRef setErrnoStateIrrelevant(ProgramStateRef State)
Stores options for the analyzer from the command line.
bool getCheckerBooleanOption(StringRef CheckerName, StringRef OptionName, bool SearchInParents=false) const
Interprets an option's string value as a boolean.
Container for either a single DynTypedNode or for an ArrayRef to DynTypedNode.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
DynTypedNodeList getParents(const NodeT &Node)
Returns the parents of the given node (within the traversal scope).
Stmt - This represents one statement.
Represents an abstract call to a function or method along a particular path.
virtual const Decl * getDecl() const
Returns the declaration of the function or method that will be called.
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace() const
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
std::optional< Loc > getErrnoLoc(ProgramStateRef State)
Returns the location that points to the MemoryRegion where the 'errno' value is stored.
ProgramStateRef clearErrnoState(ProgramStateRef State)
Clear state of errno (make it irrelevant).
ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState)
Set the errno check state, do not modify the errno value.
bool isErrnoLocationCall(const CallEvent &CE)
Determine if Call is a call to an internal function that returns the location of errno (in environmen...
ErrnoCheckState
Describe how reads and writes of errno are handled by the checker.
@ MustBeChecked
Value of 'errno' should be checked to find out if a previous function call has failed.
@ Irrelevant
We do not know anything about 'errno'.
@ MustNotBeChecked
Value of 'errno' is not allowed to be read, it can contain an unspecified value.
ErrnoCheckState getErrnoState(ProgramStateRef State)
Returns the errno check state, Errno_Irrelevant if 'errno' was not found (this is not the only case f...
llvm::DenseSet< SymbolRef > InvalidatedSymbols
The JSON file list parser is used to communicate input to InstallAPI.