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