30#include "llvm/ADT/STLExtras.h"
31#include "llvm/Support/FormatVariadic.h"
41const char *ErrnoVarName =
"errno";
44const char *ErrnoLocationFuncNames[] = {
"__errno_location",
"___errno",
45 "__errno",
"_errno",
"__error"};
48 :
public Checker<check::ASTDecl<TranslationUnitDecl>, check::BeginFunction,
49 check::LiveSymbols, eval::Call> {
58 mutable const Decl *ErrnoDecl =
nullptr;
81 auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
82 auto Found = llvm::find_if(LookupRes, [&ACtx](
const Decl *D) {
83 if (
auto *VD = dyn_cast<VarDecl>(D))
84 return ACtx.getSourceManager().isInSystemHeader(VD->getLocation()) &&
85 VD->hasExternalStorage() &&
86 VD->getType().getCanonicalType() == ACtx.IntTy;
89 if (Found == LookupRes.end())
92 return cast<VarDecl>(*Found);
100 for (StringRef ErrnoName : ErrnoLocationFuncNames) {
105 auto Found = llvm::find_if(LookupRes, [&ACtx](
const Decl *D) {
106 if (
auto *FD = dyn_cast<FunctionDecl>(D))
108 FD->isExternC() && FD->getNumParams() == 0 &&
109 FD->getReturnType().getCanonicalType() ==
113 if (Found == LookupRes.end())
116 return cast<FunctionDecl>(*Found);
139 if (
const auto *ErrnoVar = dyn_cast_or_null<VarDecl>(ErrnoDecl)) {
145 State->getRegion(ErrnoVar,
C.getLocationContext());
146 assert(ErrnoR &&
"Memory region should exist for the 'errno' variable.");
147 State = State->set<ErrnoRegion>(ErrnoR);
150 C.addTransition(State);
151 }
else if (ErrnoDecl) {
152 assert(isa<FunctionDecl>(ErrnoDecl) &&
"Invalid errno location function.");
167 nullptr,
C.getLocationContext(),
175 State = State->set<ErrnoRegion>(ErrnoR);
178 C.addTransition(State);
185 if (ErrnoLocationCalls.contains(Call)) {
188 const MemRegion *ErrnoR = State->get<ErrnoRegion>();
192 State = State->BindExpr(
Call.getOriginExpr(),
C.getLocationContext(),
194 C.addTransition(State);
204 if (
const auto *ErrnoR = State->get<ErrnoRegion>())
210namespace errno_modeling {
213 const MemRegion *ErrnoR = State->get<ErrnoRegion>();
216 QualType IntTy = State->getAnalysisManager().getASTContext().IntTy;
217 return State->getSVal(ErrnoR, IntTy);
223 const MemRegion *ErrnoR = State->get<ErrnoRegion>();
229 return State->set<ErrnoState>(EState);
234 const MemRegion *ErrnoR = State->get<ErrnoRegion>();
237 State = State->bindLoc(
239 C.getSValBuilder().makeIntVal(
Value,
C.getASTContext().IntTy),
240 C.getLocationContext());
241 return State->set<ErrnoState>(EState);
245 const MemRegion *ErrnoR = State->get<ErrnoRegion>();
252 return State->get<ErrnoState>();
256 return State->set<ErrnoState>(EState);
264 if (
const auto *VD = dyn_cast_or_null<VarDecl>(D))
266 return II->getName() == ErrnoVarName;
267 if (
const auto *FD = dyn_cast_or_null<FunctionDecl>(D))
269 return llvm::is_contained(ErrnoLocationFuncNames, II->getName());
277 BR.markNotInteresting(ErrnoR);
295 .castAs<DefinedOrUnknownSVal>();
296 State = State->assume(Cond,
true);
304 const Expr *InvalE) {
305 const MemRegion *ErrnoR = State->get<ErrnoRegion>();
308 State = State->invalidateRegions(ErrnoR, InvalE,
C.blockCount(),
309 C.getLocationContext(),
false);
318 "'errno' may be undefined after successful call to '{0}'", Fn));
322 llvm::StringRef Fn) {
324 C, llvm::formatv(
"'{0}' indicates failure only by setting 'errno'", Fn));
335bool ento::shouldRegisterErrnoModeling(
const CheckerManager &mgr) {
static const FunctionDecl * getErrnoFunc(ASTContext &ACtx)
Search for a function with a specific name that is used to return a pointer to "errno".
static const VarDecl * getErrnoVar(ASTContext &ACtx)
Store a MemRegion that contains the 'errno' integer value.
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
TranslationUnitDecl * getTranslationUnitDecl() const
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue=true) const
Return the uniqued reference to the type for an lvalue reference to the specified type.
lookup_result lookup(DeclarationName Name) const
lookup - Find the declarations (if any) with the given Name in this context.
Decl - This represents one declaration (or definition), e.g.
This represents one expression.
Represents a function declaration or definition.
One of these records is kept for each identifier that is lexed.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
A (possibly-)qualified type.
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
The top declaration context.
Represents a variable declaration or definition.
ASTContext & getASTContext() override
BugReporter is a utility class for generating PathDiagnostics for analysis.
An immutable set of CallDescriptions.
Represents an abstract call to a function or method along a particular path.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
const ElementRegion * getElementRegion(QualType elementType, NonLoc Idx, const SubRegion *superRegion, ASTContext &Ctx)
getElementRegion - Retrieve the memory region associated with the associated element type,...
const GlobalsSpaceRegion * getGlobalsRegion(MemRegion::Kind K=MemRegion::GlobalInternalSpaceRegionKind, const CodeTextRegion *R=nullptr)
getGlobalsRegion - Retrieve the memory region associated with global variables.
const SymbolicRegion * getSymbolicRegion(SymbolRef Sym, const MemSpaceRegion *MemSpace=nullptr)
Retrieve or create a "symbolic" memory region.
MemRegion - The root abstract class for all memory regions.
MemSpaceRegion - A memory region that represents a "memory space"; for example, the set of global var...
The tag upon which the TagVisitor reacts.
const ExplodedNode * getErrorNode() const
bool isInteresting(SymbolRef sym) const
const SymbolConjured * conjureSymbol(const Stmt *stmt, const LocationContext *LCtx, QualType type, unsigned visitCount, const void *symbolTag=nullptr)
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
QualType getConditionType() const
NonLoc makeZeroArrayIndex()
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
A symbol representing the result of an expression in the case when we do not know anything about what...
A class responsible for cleaning up unused symbols.
void markLive(SymbolRef sym)
Unconditionally marks a symbol as live.
std::optional< Loc > getErrnoLoc(ProgramStateRef State)
Returns the location that points to the MemoryRegion where the 'errno' value is stored.
ProgramStateRef setErrnoValue(ProgramStateRef State, const LocationContext *LCtx, SVal Value, ErrnoCheckState EState)
Set value of 'errno' to any SVal, if possible.
bool isErrno(const Decl *D)
Determine if a Decl node related to 'errno'.
const NoteTag * getNoteTagForStdSuccess(CheckerContext &C, llvm::StringRef Fn)
Generate the note tag that can be applied at the state generated by setErrnoForStdSuccess .
const NoteTag * getNoteTagForStdMustBeChecked(CheckerContext &C, llvm::StringRef Fn)
Generate the note tag that can be applied at the state generated by setErrnoStdMustBeChecked .
ProgramStateRef clearErrnoState(ProgramStateRef State)
Clear state of errno (make it irrelevant).
ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State, CheckerContext &C)
Set errno state for the common case when a standard function is successful.
ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState)
Set the errno check state, do not modify the errno value.
const NoteTag * getErrnoNoteTag(CheckerContext &C, const std::string &Message)
Create a NoteTag that displays the message if the 'errno' memory region is marked as interesting,...
ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State, CheckerContext &C, const Expr *InvalE)
Set errno state for the common case when a standard function indicates failure only by errno.
ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C, NonLoc ErrnoSym)
Set errno state for the common case when a standard function fails.
std::optional< SVal > getErrnoValue(ProgramStateRef State)
Returns the value of 'errno', if 'errno' was found in the AST.
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...
bool Call(InterpState &S, CodePtr OpPC, const Function *Func)
@ C
Languages that the frontend can parse and compile.