MacOSXAPIChecker.cpp revision ec8605f1d7ec846dbf51047bfd5c56d32d1ff91c
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- C++ -*-// 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The LLVM Compiler Infrastructure 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file is distributed under the University of Illinois Open Source 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// License. See LICENSE.TXT for details. 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This defines MacOSXAPIChecker, which is an assortment of checks on calls 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to various, widely used Mac OS X functions. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to here, using the new Checker interface. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)//===----------------------------------------------------------------------===// 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ClangSACheckers.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/Checker.h" 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/CheckerManager.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "clang/Basic/TargetInfo.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/ADT/SmallString.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/ADT/StringSwitch.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "llvm/Support/raw_ostream.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using namespace clang; 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using namespace ento; 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class MacOSXAPIChecker : public Checker< check::PreStmt<CallExpr> > { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enum SubChecks { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DispatchOnce = 0, 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DispatchOnceF, 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) NumChecks 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mutable BugType *BTypes[NumChecks]; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public: 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MacOSXAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); } 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~MacOSXAPIChecker() { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (unsigned i=0; i != NumChecks; ++i) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete BTypes[i]; 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} //end anonymous namespace 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// dispatch_once and dispatch_once_f 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BugType *&BT, const IdentifierInfo *FI) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!BT) { 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) llvm::SmallString<128> S; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) llvm::raw_svector_ostream os(S); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os << "Improper use of '" << FI->getName() << '\''; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BT = new BugType(os.str(), "Mac OS X API"); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (CE->getNumArgs() < 1) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if the first argument is stack allocated. If so, issue a warning 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // because that's likely to be bad news. 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GRState *state = C.getState(); 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion(); 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExplodedNode *N = C.generateSink(state); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!N) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) llvm::SmallString<256> S; 82a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch llvm::raw_svector_ostream os(S); 83a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch os << "Call to '" << FI->getName() << "' uses"; 84a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (const VarRegion *VR = dyn_cast<VarRegion>(R)) 85a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch os << " the local variable '" << VR->getDecl()->getName() << '\''; 863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) else 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os << " stack allocated memory"; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os << " for the predicate value. Using such transient memory for " 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "the predicate is potentially dangerous."; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace())) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os << " Perhaps you intended to declare the variable as 'static'?"; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N); 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) report->addRange(CE->getArg(0)->getSourceRange()); 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) C.EmitReport(report); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Central dispatch function. 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT, 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const IdentifierInfo *FI); 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) class SubCheck { 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SubChecker SC; 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BugType **BT; 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {} 110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) SubCheck() : SC(NULL), BT(NULL) {} 1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) void run(CheckerContext &C, const CallExpr *CE, 1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const IdentifierInfo *FI) const { 114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (SC) 1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SC(C, CE, *BT, FI); 1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) } 117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch }; 1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} // end anonymous namespace 1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE, 1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci CheckerContext &C) const { 1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // FIXME: Mostly copy and paste from UnixAPIChecker. Should refactor. 1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const GRState *state = C.getState(); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Expr *Callee = CE->getCallee(); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const FunctionTextRegion *Fn = 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion()); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!Fn) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const IdentifierInfo *FI = Fn->getDecl()->getIdentifier(); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!FI) 1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return; 1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) const SubCheck &SC = 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) llvm::StringSwitch<SubCheck>(FI->getName()) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) .Case("dispatch_once", SubCheck(CheckDispatchOnce, BTypes[DispatchOnce])) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) .Case("dispatch_once_f", SubCheck(CheckDispatchOnce, 1395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu BTypes[DispatchOnceF])) 1405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu .Default(SubCheck()); 1415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SC.run(C, CE, FI); 14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Registration. 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//===----------------------------------------------------------------------===// 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ento::registerMacOSXAPIChecker(CheckerManager &mgr) { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mgr.registerChecker<MacOSXAPIChecker>(); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 152ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch