24#include "llvm/ADT/STLExtras.h"
34 :
public Checker<check::Location, check::PreCall, check::RegionChanges> {
36 void checkLocation(SVal Loc,
bool IsLoad,
const Stmt *S,
37 CheckerContext &)
const;
38 void checkPreCall(
const CallEvent &
Call, CheckerContext &
C)
const;
42 ArrayRef<const MemRegion *> ExplicitRegions,
43 ArrayRef<const MemRegion *> Regions,
44 const LocationContext *LCtx,
const CallEvent *
Call)
const;
49 bool AllowErrnoReadOutsideConditions =
true;
53 const MemRegion *ErrnoRegion,
54 const CallEvent *CallMayChangeErrno)
const;
56 BugType BT_InvalidErrnoRead{
this,
"Value of 'errno' could be undefined",
58 BugType BT_ErrnoNotChecked{
this,
"Value of 'errno' was not checked",
72 bool CondFound =
false;
73 while (S && !CondFound) {
77 const auto *ParentS = Parents[0].get<
Stmt>();
80 switch (ParentS->getStmtClass()) {
81 case Expr::IfStmtClass:
84 case Expr::ForStmtClass:
87 case Expr::DoStmtClass:
90 case Expr::WhileStmtClass:
93 case Expr::SwitchStmtClass:
96 case Expr::ConditionalOperatorClass:
99 case Expr::BinaryConditionalOperatorClass:
110void ErrnoChecker::generateErrnoNotCheckedBug(
112 const CallEvent *CallMayChangeErrno)
const {
113 if (ExplodedNode *N =
C.generateNonFatalErrorNode(State)) {
114 SmallString<100> StrBuf;
115 llvm::raw_svector_ostream
OS(StrBuf);
116 if (CallMayChangeErrno) {
117 OS <<
"Value of 'errno' was not checked and may be overwritten by "
120 dyn_cast_or_null<FunctionDecl>(CallMayChangeErrno->
getDecl());
121 assert(CallD && CallD->getIdentifier());
122 OS << CallD->getIdentifier()->getName() <<
"'";
124 OS <<
"Value of 'errno' was not checked and is overwritten here";
126 auto BR = std::make_unique<PathSensitiveBugReport>(BT_ErrnoNotChecked,
128 BR->markInteresting(ErrnoRegion);
129 C.emitReport(std::move(BR));
133void ErrnoChecker::checkLocation(SVal Loc,
bool IsLoad,
const Stmt *S,
134 CheckerContext &
C)
const {
135 std::optional<ento::Loc> ErrnoLoc =
getErrnoLoc(
C.getState());
139 auto L = Loc.
getAs<ento::Loc>();
140 if (!L || *ErrnoLoc != *L)
151 if (ExplodedNode *N =
C.generateErrorNode()) {
152 auto BR = std::make_unique<PathSensitiveBugReport>(
154 "An undefined value may be read from 'errno'", N);
155 BR->markInteresting(ErrnoLoc->getAsRegion());
156 C.emitReport(std::move(BR));
165 C.addTransition(State);
176 ErrnoLoc->getAsRegion(),
nullptr);
182 C.addTransition(State);
190void ErrnoChecker::checkPreCall(
const CallEvent &
Call,
191 CheckerContext &
C)
const {
192 const auto *CallF = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
196 CallF = CallF->getCanonicalDecl();
205 if (CallF->isExternC() && CallF->isGlobal() &&
206 C.getSourceManager().isInSystemHeader(CallF->getLocation()) &&
209 std::optional<ento::Loc> ErrnoLoc =
getErrnoLoc(
C.getState());
210 assert(ErrnoLoc &&
"ErrnoLoc should exist if an errno state is set.");
212 ErrnoLoc->getAsRegion(), &
Call);
219 ArrayRef<const MemRegion *> ExplicitRegions,
220 ArrayRef<const MemRegion *> Regions,
const LocationContext *LCtx,
221 const CallEvent *
Call)
const {
222 std::optional<ento::Loc> ErrnoLoc =
getErrnoLoc(State);
225 const MemRegion *ErrnoRegion = ErrnoLoc->getAsRegion();
229 if (llvm::is_contained(Regions, ErrnoRegion))
234 if (llvm::is_contained(Regions, ErrnoRegion->
getMemorySpace(State)))
240void ento::registerErrnoChecker(CheckerManager &mgr) {
243 Checker->AllowErrnoReadOutsideConditions = Opts.getCheckerBooleanOption(
244 Checker,
"AllowErrnoReadOutsideConditionExpressions");
247bool ento::shouldRegisterErrnoChecker(
const CheckerManager &mgr) {
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)
Container for either a single DynTypedNode or for an ArrayRef to DynTypedNode.
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)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace(ProgramStateRef State) const
Returns the most specific memory space for this memory region in the given ProgramStateRef.
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
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
U cast(CodeGen::Address addr)