MacOSXAPIChecker.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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 Apple APIs.
  12. //
  13. // FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated
  14. // to here, using the new Checker interface.
  15. //
  16. //===----------------------------------------------------------------------===//
  17. #include "ClangSACheckers.h"
  18. #include "clang/Basic/TargetInfo.h"
  19. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  20. #include "clang/StaticAnalyzer/Core/Checker.h"
  21. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  22. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  23. #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
  24. #include "llvm/ADT/SmallString.h"
  25. #include "llvm/ADT/StringSwitch.h"
  26. #include "llvm/Support/raw_ostream.h"
  27. using namespace clang;
  28. using namespace ento;
  29. namespace {
  30. class MacOSXAPIChecker : public Checker< check::PreStmt<CallExpr> > {
  31. mutable std::unique_ptr<BugType> BT_dispatchOnce;
  32. public:
  33. void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
  34. void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
  35. StringRef FName) const;
  36. typedef void (MacOSXAPIChecker::*SubChecker)(CheckerContext &,
  37. const CallExpr *,
  38. StringRef FName) const;
  39. };
  40. } //end anonymous namespace
  41. //===----------------------------------------------------------------------===//
  42. // dispatch_once and dispatch_once_f
  43. //===----------------------------------------------------------------------===//
  44. void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
  45. StringRef FName) const {
  46. if (CE->getNumArgs() < 1)
  47. return;
  48. // Check if the first argument is stack allocated. If so, issue a warning
  49. // because that's likely to be bad news.
  50. ProgramStateRef state = C.getState();
  51. const MemRegion *R =
  52. state->getSVal(CE->getArg(0), C.getLocationContext()).getAsRegion();
  53. if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
  54. return;
  55. ExplodedNode *N = C.generateSink(state);
  56. if (!N)
  57. return;
  58. if (!BT_dispatchOnce)
  59. BT_dispatchOnce.reset(new BugType(this, "Improper use of 'dispatch_once'",
  60. "API Misuse (Apple)"));
  61. // Handle _dispatch_once. In some versions of the OS X SDK we have the case
  62. // that dispatch_once is a macro that wraps a call to _dispatch_once.
  63. // _dispatch_once is then a function which then calls the real dispatch_once.
  64. // Users do not care; they just want the warning at the top-level call.
  65. if (CE->getLocStart().isMacroID()) {
  66. StringRef TrimmedFName = FName.ltrim("_");
  67. if (TrimmedFName != FName)
  68. FName = TrimmedFName;
  69. }
  70. SmallString<256> S;
  71. llvm::raw_svector_ostream os(S);
  72. os << "Call to '" << FName << "' uses";
  73. if (const VarRegion *VR = dyn_cast<VarRegion>(R))
  74. os << " the local variable '" << VR->getDecl()->getName() << '\'';
  75. else
  76. os << " stack allocated memory";
  77. os << " for the predicate value. Using such transient memory for "
  78. "the predicate is potentially dangerous.";
  79. if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
  80. os << " Perhaps you intended to declare the variable as 'static'?";
  81. auto report = llvm::make_unique<BugReport>(*BT_dispatchOnce, os.str(), N);
  82. report->addRange(CE->getArg(0)->getSourceRange());
  83. C.emitReport(std::move(report));
  84. }
  85. //===----------------------------------------------------------------------===//
  86. // Central dispatch function.
  87. //===----------------------------------------------------------------------===//
  88. void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE,
  89. CheckerContext &C) const {
  90. StringRef Name = C.getCalleeName(CE);
  91. if (Name.empty())
  92. return;
  93. SubChecker SC =
  94. llvm::StringSwitch<SubChecker>(Name)
  95. .Cases("dispatch_once",
  96. "_dispatch_once",
  97. "dispatch_once_f",
  98. &MacOSXAPIChecker::CheckDispatchOnce)
  99. .Default(nullptr);
  100. if (SC)
  101. (this->*SC)(C, CE, Name);
  102. }
  103. //===----------------------------------------------------------------------===//
  104. // Registration.
  105. //===----------------------------------------------------------------------===//
  106. void ento::registerMacOSXAPIChecker(CheckerManager &mgr) {
  107. mgr.registerChecker<MacOSXAPIChecker>();
  108. }