MacOSXAPIChecker.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- 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 defines MacOSXAPIChecker, which is an assortment of checks on calls
  11. // to various, widely used Mac OS X functions.
  12. //
  13. // FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated
  14. // to here, using the new Checker interface.
  15. //
  16. //===----------------------------------------------------------------------===//
  17. #include "InternalChecks.h"
  18. #include "clang/Basic/TargetInfo.h"
  19. #include "clang/StaticAnalyzer/BugReporter/BugType.h"
  20. #include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
  21. #include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
  22. #include "llvm/ADT/SmallString.h"
  23. #include "llvm/ADT/StringSwitch.h"
  24. #include "llvm/Support/raw_ostream.h"
  25. using namespace clang;
  26. using namespace ento;
  27. namespace {
  28. class MacOSXAPIChecker : public CheckerVisitor<MacOSXAPIChecker> {
  29. enum SubChecks {
  30. DispatchOnce = 0,
  31. DispatchOnceF,
  32. NumChecks
  33. };
  34. BugType *BTypes[NumChecks];
  35. public:
  36. MacOSXAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
  37. static void *getTag() { static unsigned tag = 0; return &tag; }
  38. void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
  39. };
  40. } //end anonymous namespace
  41. void ento::RegisterMacOSXAPIChecker(ExprEngine &Eng) {
  42. if (Eng.getContext().Target.getTriple().getVendor() == llvm::Triple::Apple)
  43. Eng.registerCheck(new MacOSXAPIChecker());
  44. }
  45. //===----------------------------------------------------------------------===//
  46. // dispatch_once and dispatch_once_f
  47. //===----------------------------------------------------------------------===//
  48. static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
  49. BugType *&BT, const IdentifierInfo *FI) {
  50. if (!BT) {
  51. llvm::SmallString<128> S;
  52. llvm::raw_svector_ostream os(S);
  53. os << "Improper use of '" << FI->getName() << '\'';
  54. BT = new BugType(os.str(), "Mac OS X API");
  55. }
  56. if (CE->getNumArgs() < 1)
  57. return;
  58. // Check if the first argument is stack allocated. If so, issue a warning
  59. // because that's likely to be bad news.
  60. const GRState *state = C.getState();
  61. const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
  62. if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
  63. return;
  64. ExplodedNode *N = C.generateSink(state);
  65. if (!N)
  66. return;
  67. llvm::SmallString<256> S;
  68. llvm::raw_svector_ostream os(S);
  69. os << "Call to '" << FI->getName() << "' uses";
  70. if (const VarRegion *VR = dyn_cast<VarRegion>(R))
  71. os << " the local variable '" << VR->getDecl()->getName() << '\'';
  72. else
  73. os << " stack allocated memory";
  74. os << " for the predicate value. Using such transient memory for "
  75. "the predicate is potentially dangerous.";
  76. if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
  77. os << " Perhaps you intended to declare the variable as 'static'?";
  78. EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
  79. report->addRange(CE->getArg(0)->getSourceRange());
  80. C.EmitReport(report);
  81. }
  82. //===----------------------------------------------------------------------===//
  83. // Central dispatch function.
  84. //===----------------------------------------------------------------------===//
  85. typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT,
  86. const IdentifierInfo *FI);
  87. namespace {
  88. class SubCheck {
  89. SubChecker SC;
  90. BugType **BT;
  91. public:
  92. SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {}
  93. SubCheck() : SC(NULL), BT(NULL) {}
  94. void run(CheckerContext &C, const CallExpr *CE,
  95. const IdentifierInfo *FI) const {
  96. if (SC)
  97. SC(C, CE, *BT, FI);
  98. }
  99. };
  100. } // end anonymous namespace
  101. void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
  102. // FIXME: Mostly copy and paste from UnixAPIChecker. Should refactor.
  103. const GRState *state = C.getState();
  104. const Expr *Callee = CE->getCallee();
  105. const FunctionTextRegion *Fn =
  106. dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
  107. if (!Fn)
  108. return;
  109. const IdentifierInfo *FI = Fn->getDecl()->getIdentifier();
  110. if (!FI)
  111. return;
  112. const SubCheck &SC =
  113. llvm::StringSwitch<SubCheck>(FI->getName())
  114. .Case("dispatch_once", SubCheck(CheckDispatchOnce, BTypes[DispatchOnce]))
  115. .Case("dispatch_once_f", SubCheck(CheckDispatchOnce,
  116. BTypes[DispatchOnceF]))
  117. .Default(SubCheck());
  118. SC.run(C, CE, FI);
  119. }