25#include "llvm/ADT/SmallString.h"
26#include "llvm/Support/raw_ostream.h"
40class NSErrorMethodChecker
41 :
public Checker< check::ASTDecl<ObjCMethodDecl> > {
45 NSErrorMethodChecker() =
default;
55 if (!
D->isThisDeclarationADefinition())
57 if (!
D->getReturnType()->isVoidType())
63 bool hasNSError =
false;
64 for (
const auto *I :
D->parameters()) {
72 const char *err =
"Method accepting NSError** "
73 "should have a non-void return value to indicate whether or not an "
78 "Coding conventions (Apple)", err, L);
87class CFErrorFunctionChecker
88 :
public Checker< check::ASTDecl<FunctionDecl> > {
92 CFErrorFunctionChecker() : II(nullptr) {}
100 if (isa<CXXConstructorDecl>(
D))
108void CFErrorFunctionChecker::checkASTDecl(
const FunctionDecl *
D,
111 if (!
D->doesThisDeclarationHaveABody())
113 if (!
D->getReturnType()->isVoidType())
121 bool hasCFError =
false;
122 for (
auto *I :
D->parameters()) {
130 const char *err =
"Function accepting CFErrorRef* "
131 "should have a non-void return value to indicate whether or not an "
136 "Coding conventions (Apple)", err, L);
146class NSErrorDerefBug :
public BugType {
150 "Coding conventions (Apple)") {}
153class CFErrorDerefBug :
public BugType {
157 "Coding conventions (Apple)") {}
163class NSOrCFErrorDerefChecker
164 :
public Checker< check::Location,
165 check::Event<ImplicitNullDerefEvent> > {
167 mutable std::unique_ptr<NSErrorDerefBug> NSBT;
168 mutable std::unique_ptr<CFErrorDerefBug> CFBT;
170 bool ShouldCheckNSError =
false, ShouldCheckCFError =
false;
172 NSOrCFErrorDerefChecker() : NSErrorII(nullptr), CFErrorII(nullptr) {}
174 void checkLocation(
SVal loc,
bool isLoad,
const Stmt *S,
187 if (
const unsigned *attachedFlags = state->get<
T>(sym))
188 return *attachedFlags;
196 C.addTransition(state->set<
T>(sym,
true));
205 stackReg = dyn_cast<StackArgumentsSpaceRegion>(VR->getMemorySpace()))
206 if (stackReg->getStackFrame() == SFC)
207 return VR->getValueType();
213void NSOrCFErrorDerefChecker::checkLocation(
SVal loc,
bool isLoad,
218 if (loc.
isUndef() || !isa<Loc>(loc))
237 CFErrorII = &Ctx.
Idents.
get(
"CFErrorRef");
239 if (ShouldCheckNSError &&
IsNSError(parmT, NSErrorII)) {
240 setFlag<NSErrorOut>(state, state->getSVal(loc.
castAs<
Loc>()),
C);
244 if (ShouldCheckCFError &&
IsCFError(parmT, CFErrorII)) {
245 setFlag<CFErrorOut>(state, state->getSVal(loc.
castAs<
Loc>()),
C);
254 SVal loc =
event.Location;
258 bool isNSError = hasFlag<NSErrorOut>(loc, state);
259 bool isCFError =
false;
261 isCFError = hasFlag<CFErrorOut>(loc, state);
263 if (!(isNSError || isCFError))
268 llvm::raw_svector_ostream os(Buf);
270 os <<
"Potential null dereference. According to coding standards ";
272 ?
"in 'Creating and Returning NSError Objects' the parameter"
273 :
"documented in CoreFoundation/CFError.h the parameter");
275 os <<
" may be null";
280 NSBT.reset(
new NSErrorDerefBug(NSErrorName));
285 CFBT.reset(
new CFErrorDerefBug(CFErrorName));
289 std::make_unique<PathSensitiveBugReport>(*bug, os.str(), event.
SinkNode));
308 return II == ID->getIdentifier();
315 if (!PPT)
return false;
318 if (!TT)
return false;
327bool ento::shouldRegisterNSOrCFErrorDerefChecker(
const CheckerManager &mgr) {
333 NSOrCFErrorDerefChecker *checker = mgr.
getChecker<NSOrCFErrorDerefChecker>();
334 checker->ShouldCheckNSError =
true;
338bool ento::shouldRegisterNSErrorChecker(
const CheckerManager &mgr) {
344 NSOrCFErrorDerefChecker *checker = mgr.
getChecker<NSOrCFErrorDerefChecker>();
345 checker->ShouldCheckCFError =
true;
349bool ento::shouldRegisterCFErrorChecker(
const CheckerManager &mgr) {
static bool hasFlag(SVal val, ProgramStateRef state)
static bool IsCFError(QualType T, IdentifierInfo *II)
static void setFlag(ProgramStateRef state, SVal val, CheckerContext &C)
static QualType parameterTypeFromSVal(SVal val, CheckerContext &C)
static bool IsNSError(QualType T, IdentifierInfo *II)
static bool hasReservedReturnType(const FunctionDecl *D)
llvm::ImmutableMap< SymbolRef, unsigned > ErrorOutFlag
#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 ...
ASTContext & getASTContext() const LLVM_READONLY
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.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Represents an ObjC class declaration.
ObjCMethodDecl - Represents an instance or class method declaration.
Represents a pointer to an Objective C object.
ObjCInterfaceDecl * getInterfaceDecl() const
If this pointer points to an Objective @interface type, gets the declaration for that interface.
PointerType - C99 6.7.5.1 - Pointer Declarators.
QualType getPointeeType() const
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
It represents a stack frame of the call stack (based on CallEvent).
Stmt - This represents one statement.
const T * getAs() const
Member-template getAs<specific type>'.
TypedefNameDecl * getDecl() const
BugReporter is a utility class for generating PathDiagnostics for analysis.
const SourceManager & getSourceManager()
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges=std::nullopt, ArrayRef< FixItHint > Fixits=std::nullopt)
virtual void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
CheckerNameRef getCurrentCheckerName() const
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
MemRegion - The root abstract class for all memory regions.
const RegionTy * getAs() const
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
We dereferenced a location that may be null.