RegionStore/BasicStore: do not return UndefinedVal for accesses to concrete addresses...
[clang.git] / lib / Checker / BasicObjCFoundationChecks.cpp
blob00b524a9bee62312667dba2c154e10fa14fc05c2
1 //== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*--
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines BasicObjCFoundationChecks, a class that encapsulates
11 // a set of simple checks to run on Objective-C code using Apple's Foundation
12 // classes.
14 //===----------------------------------------------------------------------===//
16 #include "BasicObjCFoundationChecks.h"
18 #include "clang/Checker/PathSensitive/ExplodedGraph.h"
19 #include "clang/Checker/PathSensitive/CheckerVisitor.h"
20 #include "clang/Checker/PathSensitive/GRExprEngine.h"
21 #include "clang/Checker/PathSensitive/GRState.h"
22 #include "clang/Checker/BugReporter/BugType.h"
23 #include "clang/Checker/PathSensitive/MemRegion.h"
24 #include "clang/Checker/PathSensitive/CheckerVisitor.h"
25 #include "clang/Checker/Checkers/LocalCheckers.h"
26 #include "clang/AST/DeclObjC.h"
27 #include "clang/AST/Expr.h"
28 #include "clang/AST/ExprObjC.h"
29 #include "clang/AST/ASTContext.h"
31 using namespace clang;
33 namespace {
34 class APIMisuse : public BugType {
35 public:
36 APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
38 } // end anonymous namespace
40 //===----------------------------------------------------------------------===//
41 // Utility functions.
42 //===----------------------------------------------------------------------===//
44 static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
45 QualType T;
46 switch (ME->getReceiverKind()) {
47 case ObjCMessageExpr::Instance:
48 T = ME->getInstanceReceiver()->getType();
49 break;
51 case ObjCMessageExpr::SuperInstance:
52 T = ME->getSuperType();
53 break;
55 case ObjCMessageExpr::Class:
56 case ObjCMessageExpr::SuperClass:
57 return 0;
60 if (const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>())
61 return PT->getInterfaceType();
63 return NULL;
66 static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
67 if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME))
68 return ReceiverType->getDecl()->getIdentifier()->getNameStart();
69 return NULL;
72 static bool isNSString(llvm::StringRef ClassName) {
73 return ClassName == "NSString" || ClassName == "NSMutableString";
76 static inline bool isNil(SVal X) {
77 return isa<loc::ConcreteInt>(X);
80 //===----------------------------------------------------------------------===//
81 // NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
82 //===----------------------------------------------------------------------===//
84 namespace {
85 class NilArgChecker : public CheckerVisitor<NilArgChecker> {
86 APIMisuse *BT;
87 void WarnNilArg(CheckerContext &C, const ObjCMessageExpr* ME, unsigned Arg);
88 public:
89 NilArgChecker() : BT(0) {}
90 static void *getTag() { static int x = 0; return &x; }
91 void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
95 void NilArgChecker::WarnNilArg(CheckerContext &C,
96 const clang::ObjCMessageExpr *ME,
97 unsigned int Arg)
99 if (!BT)
100 BT = new APIMisuse("nil argument");
102 if (ExplodedNode *N = C.GenerateSink()) {
103 llvm::SmallString<128> sbuf;
104 llvm::raw_svector_ostream os(sbuf);
105 os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
106 << ME->getSelector().getAsString() << "' cannot be nil";
108 RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
109 R->addRange(ME->getArg(Arg)->getSourceRange());
110 C.EmitReport(R);
114 void NilArgChecker::PreVisitObjCMessageExpr(CheckerContext &C,
115 const ObjCMessageExpr *ME)
117 const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
118 if (!ReceiverType)
119 return;
121 if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
122 Selector S = ME->getSelector();
124 if (S.isUnarySelector())
125 return;
127 // FIXME: This is going to be really slow doing these checks with
128 // lexical comparisons.
130 std::string NameStr = S.getAsString();
131 llvm::StringRef Name(NameStr);
132 assert(!Name.empty());
134 // FIXME: Checking for initWithFormat: will not work in most cases
135 // yet because [NSString alloc] returns id, not NSString*. We will
136 // need support for tracking expected-type information in the analyzer
137 // to find these errors.
138 if (Name == "caseInsensitiveCompare:" ||
139 Name == "compare:" ||
140 Name == "compare:options:" ||
141 Name == "compare:options:range:" ||
142 Name == "compare:options:range:locale:" ||
143 Name == "componentsSeparatedByCharactersInSet:" ||
144 Name == "initWithFormat:") {
145 if (isNil(C.getState()->getSVal(ME->getArg(0))))
146 WarnNilArg(C, ME, 0);
151 //===----------------------------------------------------------------------===//
152 // Error reporting.
153 //===----------------------------------------------------------------------===//
155 namespace {
156 class CFNumberCreateChecker : public CheckerVisitor<CFNumberCreateChecker> {
157 APIMisuse* BT;
158 IdentifierInfo* II;
159 public:
160 CFNumberCreateChecker() : BT(0), II(0) {}
161 ~CFNumberCreateChecker() {}
162 static void *getTag() { static int x = 0; return &x; }
163 void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
164 private:
165 void EmitError(const TypedRegion* R, const Expr* Ex,
166 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
168 } // end anonymous namespace
170 enum CFNumberType {
171 kCFNumberSInt8Type = 1,
172 kCFNumberSInt16Type = 2,
173 kCFNumberSInt32Type = 3,
174 kCFNumberSInt64Type = 4,
175 kCFNumberFloat32Type = 5,
176 kCFNumberFloat64Type = 6,
177 kCFNumberCharType = 7,
178 kCFNumberShortType = 8,
179 kCFNumberIntType = 9,
180 kCFNumberLongType = 10,
181 kCFNumberLongLongType = 11,
182 kCFNumberFloatType = 12,
183 kCFNumberDoubleType = 13,
184 kCFNumberCFIndexType = 14,
185 kCFNumberNSIntegerType = 15,
186 kCFNumberCGFloatType = 16
189 namespace {
190 template<typename T>
191 class Optional {
192 bool IsKnown;
193 T Val;
194 public:
195 Optional() : IsKnown(false), Val(0) {}
196 Optional(const T& val) : IsKnown(true), Val(val) {}
198 bool isKnown() const { return IsKnown; }
200 const T& getValue() const {
201 assert (isKnown());
202 return Val;
205 operator const T&() const {
206 return getValue();
211 static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
212 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
214 if (i < kCFNumberCharType)
215 return FixedSize[i-1];
217 QualType T;
219 switch (i) {
220 case kCFNumberCharType: T = Ctx.CharTy; break;
221 case kCFNumberShortType: T = Ctx.ShortTy; break;
222 case kCFNumberIntType: T = Ctx.IntTy; break;
223 case kCFNumberLongType: T = Ctx.LongTy; break;
224 case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
225 case kCFNumberFloatType: T = Ctx.FloatTy; break;
226 case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
227 case kCFNumberCFIndexType:
228 case kCFNumberNSIntegerType:
229 case kCFNumberCGFloatType:
230 // FIXME: We need a way to map from names to Type*.
231 default:
232 return Optional<uint64_t>();
235 return Ctx.getTypeSize(T);
238 #if 0
239 static const char* GetCFNumberTypeStr(uint64_t i) {
240 static const char* Names[] = {
241 "kCFNumberSInt8Type",
242 "kCFNumberSInt16Type",
243 "kCFNumberSInt32Type",
244 "kCFNumberSInt64Type",
245 "kCFNumberFloat32Type",
246 "kCFNumberFloat64Type",
247 "kCFNumberCharType",
248 "kCFNumberShortType",
249 "kCFNumberIntType",
250 "kCFNumberLongType",
251 "kCFNumberLongLongType",
252 "kCFNumberFloatType",
253 "kCFNumberDoubleType",
254 "kCFNumberCFIndexType",
255 "kCFNumberNSIntegerType",
256 "kCFNumberCGFloatType"
259 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
261 #endif
263 void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
264 const CallExpr *CE)
266 const Expr* Callee = CE->getCallee();
267 const GRState *state = C.getState();
268 SVal CallV = state->getSVal(Callee);
269 const FunctionDecl* FD = CallV.getAsFunctionDecl();
271 if (!FD)
272 return;
274 ASTContext &Ctx = C.getASTContext();
275 if (!II)
276 II = &Ctx.Idents.get("CFNumberCreate");
278 if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
279 return;
281 // Get the value of the "theType" argument.
282 SVal TheTypeVal = state->getSVal(CE->getArg(1));
284 // FIXME: We really should allow ranges of valid theType values, and
285 // bifurcate the state appropriately.
286 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
287 if (!V)
288 return;
290 uint64_t NumberKind = V->getValue().getLimitedValue();
291 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
293 // FIXME: In some cases we can emit an error.
294 if (!TargetSize.isKnown())
295 return;
297 // Look at the value of the integer being passed by reference. Essentially
298 // we want to catch cases where the value passed in is not equal to the
299 // size of the type being created.
300 SVal TheValueExpr = state->getSVal(CE->getArg(2));
302 // FIXME: Eventually we should handle arbitrary locations. We can do this
303 // by having an enhanced memory model that does low-level typing.
304 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
305 if (!LV)
306 return;
308 const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts());
309 if (!R)
310 return;
312 QualType T = Ctx.getCanonicalType(R->getValueType());
314 // FIXME: If the pointee isn't an integer type, should we flag a warning?
315 // People can do weird stuff with pointers.
317 if (!T->isIntegerType())
318 return;
320 uint64_t SourceSize = Ctx.getTypeSize(T);
322 // CHECK: is SourceSize == TargetSize
323 if (SourceSize == TargetSize)
324 return;
326 // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
327 // otherwise generate a regular node.
329 // FIXME: We can actually create an abstract "CFNumber" object that has
330 // the bits initialized to the provided values.
332 if (ExplodedNode *N = SourceSize < TargetSize ? C.GenerateSink()
333 : C.GenerateNode()) {
334 llvm::SmallString<128> sbuf;
335 llvm::raw_svector_ostream os(sbuf);
337 os << (SourceSize == 8 ? "An " : "A ")
338 << SourceSize << " bit integer is used to initialize a CFNumber "
339 "object that represents "
340 << (TargetSize == 8 ? "an " : "a ")
341 << TargetSize << " bit integer. ";
343 if (SourceSize < TargetSize)
344 os << (TargetSize - SourceSize)
345 << " bits of the CFNumber value will be garbage." ;
346 else
347 os << (SourceSize - TargetSize)
348 << " bits of the input integer will be lost.";
350 if (!BT)
351 BT = new APIMisuse("Bad use of CFNumberCreate");
353 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
354 report->addRange(CE->getArg(2)->getSourceRange());
355 C.EmitReport(report);
359 //===----------------------------------------------------------------------===//
360 // CFRetain/CFRelease checking for null arguments.
361 //===----------------------------------------------------------------------===//
363 namespace {
364 class CFRetainReleaseChecker : public CheckerVisitor<CFRetainReleaseChecker> {
365 APIMisuse *BT;
366 IdentifierInfo *Retain, *Release;
367 public:
368 CFRetainReleaseChecker(): BT(0), Retain(0), Release(0) {}
369 static void *getTag() { static int x = 0; return &x; }
370 void PreVisitCallExpr(CheckerContext& C, const CallExpr* CE);
372 } // end anonymous namespace
375 void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
376 const CallExpr* CE) {
377 // If the CallExpr doesn't have exactly 1 argument just give up checking.
378 if (CE->getNumArgs() != 1)
379 return;
381 // Get the function declaration of the callee.
382 const GRState* state = C.getState();
383 SVal X = state->getSVal(CE->getCallee());
384 const FunctionDecl* FD = X.getAsFunctionDecl();
386 if (!FD)
387 return;
389 if (!BT) {
390 ASTContext &Ctx = C.getASTContext();
391 Retain = &Ctx.Idents.get("CFRetain");
392 Release = &Ctx.Idents.get("CFRelease");
393 BT = new APIMisuse("null passed to CFRetain/CFRelease");
396 // Check if we called CFRetain/CFRelease.
397 const IdentifierInfo *FuncII = FD->getIdentifier();
398 if (!(FuncII == Retain || FuncII == Release))
399 return;
401 // FIXME: The rest of this just checks that the argument is non-null.
402 // It should probably be refactored and combined with AttrNonNullChecker.
404 // Get the argument's value.
405 const Expr *Arg = CE->getArg(0);
406 SVal ArgVal = state->getSVal(Arg);
407 DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
408 if (!DefArgVal)
409 return;
411 // Get a NULL value.
412 ValueManager &ValMgr = C.getValueManager();
413 DefinedSVal Zero = cast<DefinedSVal>(ValMgr.makeZeroVal(Arg->getType()));
415 // Make an expression asserting that they're equal.
416 SValuator &SVator = ValMgr.getSValuator();
417 DefinedOrUnknownSVal ArgIsNull = SVator.EvalEQ(state, Zero, *DefArgVal);
419 // Are they equal?
420 const GRState *stateTrue, *stateFalse;
421 llvm::tie(stateTrue, stateFalse) = state->Assume(ArgIsNull);
423 if (stateTrue && !stateFalse) {
424 ExplodedNode *N = C.GenerateSink(stateTrue);
425 if (!N)
426 return;
428 const char *description = (FuncII == Retain)
429 ? "Null pointer argument in call to CFRetain"
430 : "Null pointer argument in call to CFRelease";
432 EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N);
433 report->addRange(Arg->getSourceRange());
434 report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg);
435 C.EmitReport(report);
436 return;
439 // From here on, we know the argument is non-null.
440 C.addTransition(stateFalse);
443 //===----------------------------------------------------------------------===//
444 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
445 //===----------------------------------------------------------------------===//
447 namespace {
448 class ClassReleaseChecker : public CheckerVisitor<ClassReleaseChecker> {
449 Selector releaseS;
450 Selector retainS;
451 Selector autoreleaseS;
452 Selector drainS;
453 BugType *BT;
454 public:
455 ClassReleaseChecker()
456 : BT(0) {}
458 static void *getTag() { static int x = 0; return &x; }
460 void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
464 void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
465 const ObjCMessageExpr *ME) {
467 if (!BT) {
468 BT = new APIMisuse("message incorrectly sent to class instead of class "
469 "instance");
471 ASTContext &Ctx = C.getASTContext();
472 releaseS = GetNullarySelector("release", Ctx);
473 retainS = GetNullarySelector("retain", Ctx);
474 autoreleaseS = GetNullarySelector("autorelease", Ctx);
475 drainS = GetNullarySelector("drain", Ctx);
478 ObjCInterfaceDecl *Class = 0;
480 switch (ME->getReceiverKind()) {
481 case ObjCMessageExpr::Class:
482 Class = ME->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
483 break;
484 case ObjCMessageExpr::SuperClass:
485 Class = ME->getSuperType()->getAs<ObjCObjectType>()->getInterface();
486 break;
487 case ObjCMessageExpr::Instance:
488 case ObjCMessageExpr::SuperInstance:
489 return;
492 Selector S = ME->getSelector();
493 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
494 return;
496 if (ExplodedNode *N = C.GenerateNode()) {
497 llvm::SmallString<200> buf;
498 llvm::raw_svector_ostream os(buf);
500 os << "The '" << S.getAsString() << "' message should be sent to instances "
501 "of class '" << Class->getName()
502 << "' and not the class directly";
504 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
505 report->addRange(ME->getSourceRange());
506 C.EmitReport(report);
510 //===----------------------------------------------------------------------===//
511 // Check registration.
512 //===----------------------------------------------------------------------===//
514 void clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) {
515 Eng.registerCheck(new NilArgChecker());
516 Eng.registerCheck(new CFNumberCreateChecker());
517 RegisterNSErrorChecks(Eng.getBugReporter(), Eng, D);
518 RegisterNSAutoreleasePoolChecks(Eng);
519 Eng.registerCheck(new CFRetainReleaseChecker());
520 Eng.registerCheck(new ClassReleaseChecker());