UnixAPIChecker.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. //= UnixAPIChecker.h - Checks preconditions for various Unix 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 UnixAPIChecker, which is an assortment of checks on calls
  11. // to various, widely used UNIX/Posix functions.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include "ClangSACheckers.h"
  15. #include "clang/StaticAnalyzer/Core/Checker.h"
  16. #include "clang/StaticAnalyzer/Core/CheckerManager.h"
  17. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  18. #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
  19. #include "clang/Basic/TargetInfo.h"
  20. #include "llvm/ADT/Optional.h"
  21. #include "llvm/ADT/StringSwitch.h"
  22. #include <fcntl.h>
  23. using namespace clang;
  24. using namespace ento;
  25. using llvm::Optional;
  26. namespace {
  27. class UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > {
  28. mutable llvm::OwningPtr<BugType> BT_open, BT_pthreadOnce, BT_mallocZero;
  29. mutable Optional<uint64_t> Val_O_CREAT;
  30. public:
  31. void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
  32. void CheckOpen(CheckerContext &C, const CallExpr *CE) const;
  33. void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const;
  34. void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
  35. typedef void (UnixAPIChecker::*SubChecker)(CheckerContext &,
  36. const CallExpr *) const;
  37. };
  38. } //end anonymous namespace
  39. //===----------------------------------------------------------------------===//
  40. // Utility functions.
  41. //===----------------------------------------------------------------------===//
  42. static inline void LazyInitialize(llvm::OwningPtr<BugType> &BT,
  43. const char *name) {
  44. if (BT)
  45. return;
  46. BT.reset(new BugType(name, "Unix API"));
  47. }
  48. //===----------------------------------------------------------------------===//
  49. // "open" (man 2 open)
  50. //===----------------------------------------------------------------------===//
  51. void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
  52. // The definition of O_CREAT is platform specific. We need a better way
  53. // of querying this information from the checking environment.
  54. if (!Val_O_CREAT.hasValue()) {
  55. if (C.getASTContext().getTargetInfo().getTriple().getVendor()
  56. == llvm::Triple::Apple)
  57. Val_O_CREAT = 0x0200;
  58. else {
  59. // FIXME: We need a more general way of getting the O_CREAT value.
  60. // We could possibly grovel through the preprocessor state, but
  61. // that would require passing the Preprocessor object to the ExprEngine.
  62. return;
  63. }
  64. }
  65. // Look at the 'oflags' argument for the O_CREAT flag.
  66. const ProgramState *state = C.getState();
  67. if (CE->getNumArgs() < 2) {
  68. // The frontend should issue a warning for this case, so this is a sanity
  69. // check.
  70. return;
  71. }
  72. // Now check if oflags has O_CREAT set.
  73. const Expr *oflagsEx = CE->getArg(1);
  74. const SVal V = state->getSVal(oflagsEx);
  75. if (!isa<NonLoc>(V)) {
  76. // The case where 'V' can be a location can only be due to a bad header,
  77. // so in this case bail out.
  78. return;
  79. }
  80. NonLoc oflags = cast<NonLoc>(V);
  81. NonLoc ocreateFlag =
  82. cast<NonLoc>(C.getSValBuilder().makeIntVal(Val_O_CREAT.getValue(),
  83. oflagsEx->getType()));
  84. SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
  85. oflags, ocreateFlag,
  86. oflagsEx->getType());
  87. if (maskedFlagsUC.isUnknownOrUndef())
  88. return;
  89. DefinedSVal maskedFlags = cast<DefinedSVal>(maskedFlagsUC);
  90. // Check if maskedFlags is non-zero.
  91. const ProgramState *trueState, *falseState;
  92. llvm::tie(trueState, falseState) = state->assume(maskedFlags);
  93. // Only emit an error if the value of 'maskedFlags' is properly
  94. // constrained;
  95. if (!(trueState && !falseState))
  96. return;
  97. if (CE->getNumArgs() < 3) {
  98. ExplodedNode *N = C.generateSink(trueState);
  99. if (!N)
  100. return;
  101. LazyInitialize(BT_open, "Improper use of 'open'");
  102. BugReport *report =
  103. new BugReport(*BT_open,
  104. "Call to 'open' requires a third argument when "
  105. "the 'O_CREAT' flag is set", N);
  106. report->addRange(oflagsEx->getSourceRange());
  107. C.EmitReport(report);
  108. }
  109. }
  110. //===----------------------------------------------------------------------===//
  111. // pthread_once
  112. //===----------------------------------------------------------------------===//
  113. void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C,
  114. const CallExpr *CE) const {
  115. // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
  116. // They can possibly be refactored.
  117. if (CE->getNumArgs() < 1)
  118. return;
  119. // Check if the first argument is stack allocated. If so, issue a warning
  120. // because that's likely to be bad news.
  121. const ProgramState *state = C.getState();
  122. const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
  123. if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
  124. return;
  125. ExplodedNode *N = C.generateSink(state);
  126. if (!N)
  127. return;
  128. llvm::SmallString<256> S;
  129. llvm::raw_svector_ostream os(S);
  130. os << "Call to 'pthread_once' uses";
  131. if (const VarRegion *VR = dyn_cast<VarRegion>(R))
  132. os << " the local variable '" << VR->getDecl()->getName() << '\'';
  133. else
  134. os << " stack allocated memory";
  135. os << " for the \"control\" value. Using such transient memory for "
  136. "the control value is potentially dangerous.";
  137. if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
  138. os << " Perhaps you intended to declare the variable as 'static'?";
  139. LazyInitialize(BT_pthreadOnce, "Improper use of 'pthread_once'");
  140. BugReport *report = new BugReport(*BT_pthreadOnce, os.str(), N);
  141. report->addRange(CE->getArg(0)->getSourceRange());
  142. C.EmitReport(report);
  143. }
  144. //===----------------------------------------------------------------------===//
  145. // "malloc" with allocation size 0
  146. //===----------------------------------------------------------------------===//
  147. // FIXME: Eventually this should be rolled into the MallocChecker, but this
  148. // check is more basic and is valuable for widespread use.
  149. void UnixAPIChecker::CheckMallocZero(CheckerContext &C,
  150. const CallExpr *CE) const {
  151. // Sanity check that malloc takes one argument.
  152. if (CE->getNumArgs() != 1)
  153. return;
  154. // Check if the allocation size is 0.
  155. const ProgramState *state = C.getState();
  156. SVal argVal = state->getSVal(CE->getArg(0));
  157. if (argVal.isUnknownOrUndef())
  158. return;
  159. const ProgramState *trueState, *falseState;
  160. llvm::tie(trueState, falseState) = state->assume(cast<DefinedSVal>(argVal));
  161. // Is the value perfectly constrained to zero?
  162. if (falseState && !trueState) {
  163. ExplodedNode *N = C.generateSink(falseState);
  164. if (!N)
  165. return;
  166. // FIXME: Add reference to CERT advisory, and/or C99 standard in bug
  167. // output.
  168. LazyInitialize(BT_mallocZero, "Undefined allocation of 0 bytes");
  169. BugReport *report =
  170. new BugReport(*BT_mallocZero, "Call to 'malloc' has an allocation"
  171. " size of 0 bytes", N);
  172. report->addRange(CE->getArg(0)->getSourceRange());
  173. report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
  174. CE->getArg(0)));
  175. C.EmitReport(report);
  176. return;
  177. }
  178. // Assume the the value is non-zero going forward.
  179. assert(trueState);
  180. if (trueState != state) {
  181. C.addTransition(trueState);
  182. }
  183. }
  184. //===----------------------------------------------------------------------===//
  185. // Central dispatch function.
  186. //===----------------------------------------------------------------------===//
  187. void UnixAPIChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
  188. StringRef FName = C.getCalleeName(CE);
  189. if (FName.empty())
  190. return;
  191. SubChecker SC =
  192. llvm::StringSwitch<SubChecker>(FName)
  193. .Case("open", &UnixAPIChecker::CheckOpen)
  194. .Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce)
  195. .Case("malloc", &UnixAPIChecker::CheckMallocZero)
  196. .Default(NULL);
  197. if (SC)
  198. (this->*SC)(C, CE);
  199. }
  200. //===----------------------------------------------------------------------===//
  201. // Registration.
  202. //===----------------------------------------------------------------------===//
  203. void ento::registerUnixAPIChecker(CheckerManager &mgr) {
  204. mgr.registerChecker<UnixAPIChecker>();
  205. }