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. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "BasicObjCFoundationChecks.h" 17 18 #include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h" 19 #include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h" 20 #include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h" 21 #include "clang/StaticAnalyzer/PathSensitive/GRState.h" 22 #include "clang/StaticAnalyzer/BugReporter/BugType.h" 23 #include "clang/StaticAnalyzer/PathSensitive/MemRegion.h" 24 #include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h" 25 #include "clang/StaticAnalyzer/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" 30 31 using namespace clang; 32 using namespace ento; 33 34 namespace { 35 class APIMisuse : public BugType { 36 public: 37 APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {} 38 }; 39 } // end anonymous namespace 40 41 //===----------------------------------------------------------------------===// 42 // Utility functions. 43 //===----------------------------------------------------------------------===// 44 45 static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) { 46 QualType T; 47 switch (ME->getReceiverKind()) { 48 case ObjCMessageExpr::Instance: 49 T = ME->getInstanceReceiver()->getType(); 50 break; 51 52 case ObjCMessageExpr::SuperInstance: 53 T = ME->getSuperType(); 54 break; 55 56 case ObjCMessageExpr::Class: 57 case ObjCMessageExpr::SuperClass: 58 return 0; 59 } 60 61 if (const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>()) 62 return PT->getInterfaceType(); 63 64 return NULL; 65 } 66 67 static const char* GetReceiverNameType(const ObjCMessageExpr* ME) { 68 if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME)) 69 return ReceiverType->getDecl()->getIdentifier()->getNameStart(); 70 return NULL; 71 } 72 73 static bool isNSString(llvm::StringRef ClassName) { 74 return ClassName == "NSString" || ClassName == "NSMutableString"; 75 } 76 77 static inline bool isNil(SVal X) { 78 return isa<loc::ConcreteInt>(X); 79 } 80 81 //===----------------------------------------------------------------------===// 82 // NilArgChecker - Check for prohibited nil arguments to ObjC method calls. 83 //===----------------------------------------------------------------------===// 84 85 namespace { 86 class NilArgChecker : public CheckerVisitor<NilArgChecker> { 87 APIMisuse *BT; 88 void WarnNilArg(CheckerContext &C, const ObjCMessageExpr* ME, unsigned Arg); 89 public: 90 NilArgChecker() : BT(0) {} 91 static void *getTag() { static int x = 0; return &x; } 92 void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); 93 }; 94 } 95 96 void NilArgChecker::WarnNilArg(CheckerContext &C, 97 const clang::ObjCMessageExpr *ME, 98 unsigned int Arg) 99 { 100 if (!BT) 101 BT = new APIMisuse("nil argument"); 102 103 if (ExplodedNode *N = C.generateSink()) { 104 llvm::SmallString<128> sbuf; 105 llvm::raw_svector_ostream os(sbuf); 106 os << "Argument to '" << GetReceiverNameType(ME) << "' method '" 107 << ME->getSelector().getAsString() << "' cannot be nil"; 108 109 RangedBugReport *R = new RangedBugReport(*BT, os.str(), N); 110 R->addRange(ME->getArg(Arg)->getSourceRange()); 111 C.EmitReport(R); 112 } 113 } 114 115 void NilArgChecker::PreVisitObjCMessageExpr(CheckerContext &C, 116 const ObjCMessageExpr *ME) 117 { 118 const ObjCInterfaceType *ReceiverType = GetReceiverType(ME); 119 if (!ReceiverType) 120 return; 121 122 if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) { 123 Selector S = ME->getSelector(); 124 125 if (S.isUnarySelector()) 126 return; 127 128 // FIXME: This is going to be really slow doing these checks with 129 // lexical comparisons. 130 131 std::string NameStr = S.getAsString(); 132 llvm::StringRef Name(NameStr); 133 assert(!Name.empty()); 134 135 // FIXME: Checking for initWithFormat: will not work in most cases 136 // yet because [NSString alloc] returns id, not NSString*. We will 137 // need support for tracking expected-type information in the analyzer 138 // to find these errors. 139 if (Name == "caseInsensitiveCompare:" || 140 Name == "compare:" || 141 Name == "compare:options:" || 142 Name == "compare:options:range:" || 143 Name == "compare:options:range:locale:" || 144 Name == "componentsSeparatedByCharactersInSet:" || 145 Name == "initWithFormat:") { 146 if (isNil(C.getState()->getSVal(ME->getArg(0)))) 147 WarnNilArg(C, ME, 0); 148 } 149 } 150 } 151 152 //===----------------------------------------------------------------------===// 153 // Error reporting. 154 //===----------------------------------------------------------------------===// 155 156 namespace { 157 class CFNumberCreateChecker : public CheckerVisitor<CFNumberCreateChecker> { 158 APIMisuse* BT; 159 IdentifierInfo* II; 160 public: 161 CFNumberCreateChecker() : BT(0), II(0) {} 162 ~CFNumberCreateChecker() {} 163 static void *getTag() { static int x = 0; return &x; } 164 void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); 165 private: 166 void EmitError(const TypedRegion* R, const Expr* Ex, 167 uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind); 168 }; 169 } // end anonymous namespace 170 171 enum CFNumberType { 172 kCFNumberSInt8Type = 1, 173 kCFNumberSInt16Type = 2, 174 kCFNumberSInt32Type = 3, 175 kCFNumberSInt64Type = 4, 176 kCFNumberFloat32Type = 5, 177 kCFNumberFloat64Type = 6, 178 kCFNumberCharType = 7, 179 kCFNumberShortType = 8, 180 kCFNumberIntType = 9, 181 kCFNumberLongType = 10, 182 kCFNumberLongLongType = 11, 183 kCFNumberFloatType = 12, 184 kCFNumberDoubleType = 13, 185 kCFNumberCFIndexType = 14, 186 kCFNumberNSIntegerType = 15, 187 kCFNumberCGFloatType = 16 188 }; 189 190 namespace { 191 template<typename T> 192 class Optional { 193 bool IsKnown; 194 T Val; 195 public: 196 Optional() : IsKnown(false), Val(0) {} 197 Optional(const T& val) : IsKnown(true), Val(val) {} 198 199 bool isKnown() const { return IsKnown; } 200 201 const T& getValue() const { 202 assert (isKnown()); 203 return Val; 204 } 205 206 operator const T&() const { 207 return getValue(); 208 } 209 }; 210 } 211 212 static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) { 213 static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 }; 214 215 if (i < kCFNumberCharType) 216 return FixedSize[i-1]; 217 218 QualType T; 219 220 switch (i) { 221 case kCFNumberCharType: T = Ctx.CharTy; break; 222 case kCFNumberShortType: T = Ctx.ShortTy; break; 223 case kCFNumberIntType: T = Ctx.IntTy; break; 224 case kCFNumberLongType: T = Ctx.LongTy; break; 225 case kCFNumberLongLongType: T = Ctx.LongLongTy; break; 226 case kCFNumberFloatType: T = Ctx.FloatTy; break; 227 case kCFNumberDoubleType: T = Ctx.DoubleTy; break; 228 case kCFNumberCFIndexType: 229 case kCFNumberNSIntegerType: 230 case kCFNumberCGFloatType: 231 // FIXME: We need a way to map from names to Type*. 232 default: 233 return Optional<uint64_t>(); 234 } 235 236 return Ctx.getTypeSize(T); 237 } 238 239 #if 0 240 static const char* GetCFNumberTypeStr(uint64_t i) { 241 static const char* Names[] = { 242 "kCFNumberSInt8Type", 243 "kCFNumberSInt16Type", 244 "kCFNumberSInt32Type", 245 "kCFNumberSInt64Type", 246 "kCFNumberFloat32Type", 247 "kCFNumberFloat64Type", 248 "kCFNumberCharType", 249 "kCFNumberShortType", 250 "kCFNumberIntType", 251 "kCFNumberLongType", 252 "kCFNumberLongLongType", 253 "kCFNumberFloatType", 254 "kCFNumberDoubleType", 255 "kCFNumberCFIndexType", 256 "kCFNumberNSIntegerType", 257 "kCFNumberCGFloatType" 258 }; 259 260 return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType"; 261 } 262 #endif 263 264 void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C, 265 const CallExpr *CE) 266 { 267 const Expr* Callee = CE->getCallee(); 268 const GRState *state = C.getState(); 269 SVal CallV = state->getSVal(Callee); 270 const FunctionDecl* FD = CallV.getAsFunctionDecl(); 271 272 if (!FD) 273 return; 274 275 ASTContext &Ctx = C.getASTContext(); 276 if (!II) 277 II = &Ctx.Idents.get("CFNumberCreate"); 278 279 if (FD->getIdentifier() != II || CE->getNumArgs() != 3) 280 return; 281 282 // Get the value of the "theType" argument. 283 SVal TheTypeVal = state->getSVal(CE->getArg(1)); 284 285 // FIXME: We really should allow ranges of valid theType values, and 286 // bifurcate the state appropriately. 287 nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal); 288 if (!V) 289 return; 290 291 uint64_t NumberKind = V->getValue().getLimitedValue(); 292 Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind); 293 294 // FIXME: In some cases we can emit an error. 295 if (!TargetSize.isKnown()) 296 return; 297 298 // Look at the value of the integer being passed by reference. Essentially 299 // we want to catch cases where the value passed in is not equal to the 300 // size of the type being created. 301 SVal TheValueExpr = state->getSVal(CE->getArg(2)); 302 303 // FIXME: Eventually we should handle arbitrary locations. We can do this 304 // by having an enhanced memory model that does low-level typing. 305 loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr); 306 if (!LV) 307 return; 308 309 const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts()); 310 if (!R) 311 return; 312 313 QualType T = Ctx.getCanonicalType(R->getValueType()); 314 315 // FIXME: If the pointee isn't an integer type, should we flag a warning? 316 // People can do weird stuff with pointers. 317 318 if (!T->isIntegerType()) 319 return; 320 321 uint64_t SourceSize = Ctx.getTypeSize(T); 322 323 // CHECK: is SourceSize == TargetSize 324 if (SourceSize == TargetSize) 325 return; 326 327 // Generate an error. Only generate a sink if 'SourceSize < TargetSize'; 328 // otherwise generate a regular node. 329 // 330 // FIXME: We can actually create an abstract "CFNumber" object that has 331 // the bits initialized to the provided values. 332 // 333 if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink() 334 : C.generateNode()) { 335 llvm::SmallString<128> sbuf; 336 llvm::raw_svector_ostream os(sbuf); 337 338 os << (SourceSize == 8 ? "An " : "A ") 339 << SourceSize << " bit integer is used to initialize a CFNumber " 340 "object that represents " 341 << (TargetSize == 8 ? "an " : "a ") 342 << TargetSize << " bit integer. "; 343 344 if (SourceSize < TargetSize) 345 os << (TargetSize - SourceSize) 346 << " bits of the CFNumber value will be garbage." ; 347 else 348 os << (SourceSize - TargetSize) 349 << " bits of the input integer will be lost."; 350 351 if (!BT) 352 BT = new APIMisuse("Bad use of CFNumberCreate"); 353 354 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); 355 report->addRange(CE->getArg(2)->getSourceRange()); 356 C.EmitReport(report); 357 } 358 } 359 360 //===----------------------------------------------------------------------===// 361 // CFRetain/CFRelease checking for null arguments. 362 //===----------------------------------------------------------------------===// 363 364 namespace { 365 class CFRetainReleaseChecker : public CheckerVisitor<CFRetainReleaseChecker> { 366 APIMisuse *BT; 367 IdentifierInfo *Retain, *Release; 368 public: 369 CFRetainReleaseChecker(): BT(0), Retain(0), Release(0) {} 370 static void *getTag() { static int x = 0; return &x; } 371 void PreVisitCallExpr(CheckerContext& C, const CallExpr* CE); 372 }; 373 } // end anonymous namespace 374 375 376 void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C, 377 const CallExpr* CE) { 378 // If the CallExpr doesn't have exactly 1 argument just give up checking. 379 if (CE->getNumArgs() != 1) 380 return; 381 382 // Get the function declaration of the callee. 383 const GRState* state = C.getState(); 384 SVal X = state->getSVal(CE->getCallee()); 385 const FunctionDecl* FD = X.getAsFunctionDecl(); 386 387 if (!FD) 388 return; 389 390 if (!BT) { 391 ASTContext &Ctx = C.getASTContext(); 392 Retain = &Ctx.Idents.get("CFRetain"); 393 Release = &Ctx.Idents.get("CFRelease"); 394 BT = new APIMisuse("null passed to CFRetain/CFRelease"); 395 } 396 397 // Check if we called CFRetain/CFRelease. 398 const IdentifierInfo *FuncII = FD->getIdentifier(); 399 if (!(FuncII == Retain || FuncII == Release)) 400 return; 401 402 // FIXME: The rest of this just checks that the argument is non-null. 403 // It should probably be refactored and combined with AttrNonNullChecker. 404 405 // Get the argument's value. 406 const Expr *Arg = CE->getArg(0); 407 SVal ArgVal = state->getSVal(Arg); 408 DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal); 409 if (!DefArgVal) 410 return; 411 412 // Get a NULL value. 413 SValBuilder &svalBuilder = C.getSValBuilder(); 414 DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType())); 415 416 // Make an expression asserting that they're equal. 417 DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal); 418 419 // Are they equal? 420 const GRState *stateTrue, *stateFalse; 421 llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull); 422 423 if (stateTrue && !stateFalse) { 424 ExplodedNode *N = C.generateSink(stateTrue); 425 if (!N) 426 return; 427 428 const char *description = (FuncII == Retain) 429 ? "Null pointer argument in call to CFRetain" 430 : "Null pointer argument in call to CFRelease"; 431 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; 437 } 438 439 // From here on, we know the argument is non-null. 440 C.addTransition(stateFalse); 441 } 442 443 //===----------------------------------------------------------------------===// 444 // Check for sending 'retain', 'release', or 'autorelease' directly to a Class. 445 //===----------------------------------------------------------------------===// 446 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) {} 457 458 static void *getTag() { static int x = 0; return &x; } 459 460 void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME); 461 }; 462 } 463 464 void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C, 465 const ObjCMessageExpr *ME) { 466 467 if (!BT) { 468 BT = new APIMisuse("message incorrectly sent to class instead of class " 469 "instance"); 470 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); 476 } 477 478 ObjCInterfaceDecl *Class = 0; 479 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; 490 } 491 492 Selector S = ME->getSelector(); 493 if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS)) 494 return; 495 496 if (ExplodedNode *N = C.generateNode()) { 497 llvm::SmallString<200> buf; 498 llvm::raw_svector_ostream os(buf); 499 500 os << "The '" << S.getAsString() << "' message should be sent to instances " 501 "of class '" << Class->getName() 502 << "' and not the class directly"; 503 504 RangedBugReport *report = new RangedBugReport(*BT, os.str(), N); 505 report->addRange(ME->getSourceRange()); 506 C.EmitReport(report); 507 } 508 } 509 510 //===----------------------------------------------------------------------===// 511 // Check registration. 512 //===----------------------------------------------------------------------===// 513 514 void ento::RegisterAppleChecks(ExprEngine& 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()); 521 } 522