25 #include "llvm/ADT/SmallString.h" 26 #include "llvm/Support/raw_ostream.h" 28 using namespace clang;
39 class NSErrorMethodChecker
40 :
public Checker< check::ASTDecl<ObjCMethodDecl> > {
44 NSErrorMethodChecker() : II(nullptr) {}
47 AnalysisManager &mgr, BugReporter &BR)
const;
53 BugReporter &BR)
const {
62 bool hasNSError =
false;
71 const char *err =
"Method accepting NSError** " 72 "should have a non-void return value to indicate whether or not an " 74 PathDiagnosticLocation L =
76 BR.EmitBasicReport(D,
this,
"Bad return type when passing NSError**",
77 "Coding conventions (Apple)", err, L);
86 class CFErrorFunctionChecker
87 :
public Checker< check::ASTDecl<FunctionDecl> > {
91 CFErrorFunctionChecker() : II(nullptr) {}
94 AnalysisManager &mgr, BugReporter &BR)
const;
98 void CFErrorFunctionChecker::checkASTDecl(
const FunctionDecl *D,
100 BugReporter &BR)
const {
109 bool hasCFError =
false;
118 const char *err =
"Function accepting CFErrorRef* " 119 "should have a non-void return value to indicate whether or not an " 121 PathDiagnosticLocation L =
123 BR.EmitBasicReport(D,
this,
"Bad return type when passing CFErrorRef*",
124 "Coding conventions (Apple)", err, L);
134 class NSErrorDerefBug :
public BugType {
136 NSErrorDerefBug(
const CheckerBase *Checker)
137 : BugType(Checker,
"NSError** null dereference",
138 "Coding conventions (Apple)") {}
141 class CFErrorDerefBug :
public BugType {
143 CFErrorDerefBug(
const CheckerBase *Checker)
144 : BugType(Checker,
"CFErrorRef* null dereference",
145 "Coding conventions (Apple)") {}
151 class NSOrCFErrorDerefChecker
152 :
public Checker< check::Location,
153 check::Event<ImplicitNullDerefEvent> > {
155 mutable std::unique_ptr<NSErrorDerefBug> NSBT;
156 mutable std::unique_ptr<CFErrorDerefBug> CFBT;
158 bool ShouldCheckNSError, ShouldCheckCFError;
159 NSOrCFErrorDerefChecker() : NSErrorII(nullptr), CFErrorII(nullptr),
160 ShouldCheckNSError(0), ShouldCheckCFError(0) { }
162 void checkLocation(SVal loc,
bool isLoad,
const Stmt *S,
163 CheckerContext &C)
const;
164 void checkEvent(ImplicitNullDerefEvent event)
const;
172 template <
typename T>
175 if (
const unsigned *attachedFlags = state->get<T>(sym))
176 return *attachedFlags;
180 template <
typename T>
184 C.addTransition(state->set<T>(sym,
true));
190 const MemRegion* R =
X->getRegion();
191 if (
const VarRegion *VR = R->getAs<VarRegion>())
192 if (
const StackArgumentsSpaceRegion *
193 stackReg = dyn_cast<StackArgumentsSpaceRegion>(VR->getMemorySpace()))
194 if (stackReg->getStackFrame() == SFC)
195 return VR->getValueType();
201 void NSOrCFErrorDerefChecker::checkLocation(SVal loc,
bool isLoad,
203 CheckerContext &C)
const {
206 if (loc.isUndef() || !loc.getAs<Loc>())
225 CFErrorII = &Ctx.
Idents.
get(
"CFErrorRef");
227 if (ShouldCheckNSError &&
IsNSError(parmT, NSErrorII)) {
228 setFlag<NSErrorOut>(
state, state->getSVal(loc.castAs<Loc>()), C);
232 if (ShouldCheckCFError &&
IsCFError(parmT, CFErrorII)) {
233 setFlag<CFErrorOut>(
state, state->getSVal(loc.castAs<Loc>()), C);
238 void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event)
const {
242 SVal loc =
event.Location;
244 BugReporter &BR = *
event.BR;
246 bool isNSError = hasFlag<NSErrorOut>(loc,
state);
247 bool isCFError =
false;
249 isCFError = hasFlag<CFErrorOut>(loc,
state);
251 if (!(isNSError || isCFError))
256 llvm::raw_svector_ostream os(Buf);
258 os <<
"Potential null dereference. According to coding standards ";
260 ?
"in 'Creating and Returning NSError Objects' the parameter" 261 :
"documented in CoreFoundation/CFError.h the parameter");
263 os <<
" may be null";
265 BugType *bug =
nullptr;
268 NSBT.reset(
new NSErrorDerefBug(
this));
273 CFBT.reset(
new CFErrorDerefBug(
this));
276 BR.emitReport(llvm::make_unique<BugReport>(*bug, os.str(),
event.SinkNode));
302 if (!PPT)
return false;
305 if (!TT)
return false;
310 void ento::registerNSOrCFErrorDerefChecker(CheckerManager &mgr) {
311 mgr.registerChecker<NSOrCFErrorDerefChecker>();
314 bool ento::shouldRegisterNSOrCFErrorDerefChecker(
const LangOptions &LO) {
318 void ento::registerNSErrorChecker(CheckerManager &mgr) {
319 mgr.registerChecker<NSErrorMethodChecker>();
320 NSOrCFErrorDerefChecker *checker = mgr.getChecker<NSOrCFErrorDerefChecker>();
321 checker->ShouldCheckNSError =
true;
324 bool ento::shouldRegisterNSErrorChecker(
const LangOptions &LO) {
328 void ento::registerCFErrorChecker(CheckerManager &mgr) {
329 mgr.registerChecker<CFErrorFunctionChecker>();
330 NSOrCFErrorDerefChecker *checker = mgr.getChecker<NSOrCFErrorDerefChecker>();
331 checker->ShouldCheckCFError =
true;
334 bool ento::shouldRegisterCFErrorChecker(
const LangOptions &LO) {
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 ...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
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