26 #include "llvm/ADT/SmallString.h" 27 #include "llvm/Support/raw_ostream.h" 29 using namespace clang;
40 class NSErrorMethodChecker
41 :
public Checker< check::ASTDecl<ObjCMethodDecl> > {
45 NSErrorMethodChecker() : II(nullptr) {}
48 AnalysisManager &mgr, BugReporter &BR)
const;
54 BugReporter &BR)
const {
63 bool hasNSError =
false;
72 const char *err =
"Method accepting NSError** " 73 "should have a non-void return value to indicate whether or not an " 75 PathDiagnosticLocation L =
77 BR.EmitBasicReport(D,
this,
"Bad return type when passing NSError**",
78 "Coding conventions (Apple)", err, L);
87 class CFErrorFunctionChecker
88 :
public Checker< check::ASTDecl<FunctionDecl> > {
92 CFErrorFunctionChecker() : II(nullptr) {}
95 AnalysisManager &mgr, BugReporter &BR)
const;
99 void CFErrorFunctionChecker::checkASTDecl(
const FunctionDecl *D,
100 AnalysisManager &mgr,
101 BugReporter &BR)
const {
110 bool hasCFError =
false;
119 const char *err =
"Function accepting CFErrorRef* " 120 "should have a non-void return value to indicate whether or not an " 122 PathDiagnosticLocation L =
124 BR.EmitBasicReport(D,
this,
"Bad return type when passing CFErrorRef*",
125 "Coding conventions (Apple)", err, L);
135 class NSErrorDerefBug :
public BugType {
137 NSErrorDerefBug(
const CheckerBase *Checker)
138 : BugType(Checker,
"NSError** null dereference",
139 "Coding conventions (Apple)") {}
142 class CFErrorDerefBug :
public BugType {
144 CFErrorDerefBug(
const CheckerBase *Checker)
145 : BugType(Checker,
"CFErrorRef* null dereference",
146 "Coding conventions (Apple)") {}
152 class NSOrCFErrorDerefChecker
153 :
public Checker< check::Location,
154 check::Event<ImplicitNullDerefEvent> > {
156 mutable std::unique_ptr<NSErrorDerefBug> NSBT;
157 mutable std::unique_ptr<CFErrorDerefBug> CFBT;
159 bool ShouldCheckNSError, ShouldCheckCFError;
160 NSOrCFErrorDerefChecker() : NSErrorII(nullptr), CFErrorII(nullptr),
161 ShouldCheckNSError(0), ShouldCheckCFError(0) { }
163 void checkLocation(SVal loc,
bool isLoad,
const Stmt *S,
164 CheckerContext &C)
const;
165 void checkEvent(ImplicitNullDerefEvent event)
const;
173 template <
typename T>
176 if (
const unsigned *attachedFlags = state->get<T>(sym))
177 return *attachedFlags;
181 template <
typename T>
185 C.addTransition(state->set<T>(sym,
true));
191 const MemRegion* R =
X->getRegion();
192 if (
const VarRegion *VR = R->getAs<VarRegion>())
193 if (
const StackArgumentsSpaceRegion *
194 stackReg = dyn_cast<StackArgumentsSpaceRegion>(VR->getMemorySpace()))
195 if (stackReg->getStackFrame() == SFC)
196 return VR->getValueType();
202 void NSOrCFErrorDerefChecker::checkLocation(SVal loc,
bool isLoad,
204 CheckerContext &C)
const {
207 if (loc.isUndef() || !loc.getAs<Loc>())
226 CFErrorII = &Ctx.
Idents.
get(
"CFErrorRef");
228 if (ShouldCheckNSError &&
IsNSError(parmT, NSErrorII)) {
229 setFlag<NSErrorOut>(
state, state->getSVal(loc.castAs<Loc>()), C);
233 if (ShouldCheckCFError &&
IsCFError(parmT, CFErrorII)) {
234 setFlag<CFErrorOut>(
state, state->getSVal(loc.castAs<Loc>()), C);
239 void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event)
const {
243 SVal loc =
event.Location;
245 BugReporter &BR = *
event.BR;
247 bool isNSError = hasFlag<NSErrorOut>(loc,
state);
248 bool isCFError =
false;
250 isCFError = hasFlag<CFErrorOut>(loc,
state);
252 if (!(isNSError || isCFError))
257 llvm::raw_svector_ostream os(Buf);
259 os <<
"Potential null dereference. According to coding standards ";
261 ?
"in 'Creating and Returning NSError Objects' the parameter" 262 :
"documented in CoreFoundation/CFError.h the parameter");
264 os <<
" may be null";
266 BugType *bug =
nullptr;
269 NSBT.reset(
new NSErrorDerefBug(
this));
274 CFBT.reset(
new CFErrorDerefBug(
this));
277 BR.emitReport(llvm::make_unique<BugReport>(*bug, os.str(),
event.SinkNode));
303 if (!PPT)
return false;
306 if (!TT)
return false;
311 void ento::registerNSErrorChecker(CheckerManager &mgr) {
312 mgr.registerChecker<NSErrorMethodChecker>();
313 NSOrCFErrorDerefChecker *checker =
314 mgr.registerChecker<NSOrCFErrorDerefChecker>();
315 checker->ShouldCheckNSError =
true;
318 void ento::registerCFErrorChecker(CheckerManager &mgr) {
319 mgr.registerChecker<CFErrorFunctionChecker>();
320 NSOrCFErrorDerefChecker *checker =
321 mgr.registerChecker<NSOrCFErrorDerefChecker>();
322 checker->ShouldCheckCFError =
true;
Represents a function declaration or definition.
bool isThisDeclarationADefinition() const
Returns whether this specific method is a definition.
PointerType - C99 6.7.5.1 - Pointer Declarators.
QualType getPointeeType() const
A (possibly-)qualified type.
const SymExpr * SymbolRef
Stmt - This represents one statement.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
static bool IsCFError(QualType T, IdentifierInfo *II)
QualType getReturnType() const
const T * getAs() const
Member-template getAs<specific type>'.
ObjCMethodDecl - Represents an instance or class method declaration.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
One of these records is kept for each identifier that is lexed.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
ArrayRef< ParmVarDecl * > parameters() const
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
llvm::ImmutableMap< SymbolRef, unsigned > ErrorOutFlag
Represents an ObjC class declaration.
QualType getReturnType() const
static void setFlag(ProgramStateRef state, SVal val, CheckerContext &C)
bool isNull() const
Return true if this QualType doesn't point to a type yet.
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a type named NameTy...
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
ASTContext & getASTContext() const LLVM_READONLY
static bool hasFlag(SVal val, ProgramStateRef state)
Dataflow Directional Tag Classes.
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...
const StackFrameContext * getStackFrame() const
TypedefNameDecl * getDecl() const
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
bool doesThisDeclarationHaveABody() const
Returns whether this specific declaration of the function has a body.
static bool IsNSError(QualType T, IdentifierInfo *II)
static QualType parameterTypeFromSVal(SVal val, CheckerContext &C)
ArrayRef< ParmVarDecl * > parameters() const