NonNullParamChecker.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. //===--- NonNullParamChecker.cpp - Undefined arguments checker -*- 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 NonNullParamChecker, which checks for arguments expected not to
  11. // be null due to:
  12. // - the corresponding parameters being declared to have nonnull attribute
  13. // - the corresponding parameters being references; since the call would form
  14. // a reference to a null pointer
  15. //
  16. //===----------------------------------------------------------------------===//
  17. #include "ClangSACheckers.h"
  18. #include "clang/AST/Attr.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/CallEvent.h"
  23. #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
  24. using namespace clang;
  25. using namespace ento;
  26. namespace {
  27. class NonNullParamChecker
  28. : public Checker< check::PreCall > {
  29. mutable std::unique_ptr<BugType> BTAttrNonNull;
  30. mutable std::unique_ptr<BugType> BTNullRefArg;
  31. public:
  32. void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
  33. std::unique_ptr<BugReport>
  34. genReportNullAttrNonNull(const ExplodedNode *ErrorN, const Expr *ArgE) const;
  35. std::unique_ptr<BugReport>
  36. genReportReferenceToNullPointer(const ExplodedNode *ErrorN,
  37. const Expr *ArgE) const;
  38. };
  39. } // end anonymous namespace
  40. void NonNullParamChecker::checkPreCall(const CallEvent &Call,
  41. CheckerContext &C) const {
  42. const Decl *FD = Call.getDecl();
  43. if (!FD)
  44. return;
  45. // Merge all non-null attributes
  46. unsigned NumArgs = Call.getNumArgs();
  47. llvm::SmallBitVector AttrNonNull(NumArgs);
  48. for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
  49. if (!NonNull->args_size()) {
  50. AttrNonNull.set(0, NumArgs);
  51. break;
  52. }
  53. for (unsigned Val : NonNull->args()) {
  54. if (Val >= NumArgs)
  55. continue;
  56. AttrNonNull.set(Val);
  57. }
  58. }
  59. ProgramStateRef state = C.getState();
  60. CallEvent::param_type_iterator TyI = Call.param_type_begin(),
  61. TyE = Call.param_type_end();
  62. for (unsigned idx = 0; idx < NumArgs; ++idx) {
  63. // Check if the parameter is a reference. We want to report when reference
  64. // to a null pointer is passed as a paramter.
  65. bool haveRefTypeParam = false;
  66. if (TyI != TyE) {
  67. haveRefTypeParam = (*TyI)->isReferenceType();
  68. TyI++;
  69. }
  70. bool haveAttrNonNull = AttrNonNull[idx];
  71. if (!haveAttrNonNull) {
  72. // Check if the parameter is also marked 'nonnull'.
  73. ArrayRef<ParmVarDecl*> parms = Call.parameters();
  74. if (idx < parms.size())
  75. haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>();
  76. }
  77. if (!haveRefTypeParam && !haveAttrNonNull)
  78. continue;
  79. // If the value is unknown or undefined, we can't perform this check.
  80. const Expr *ArgE = Call.getArgExpr(idx);
  81. SVal V = Call.getArgSVal(idx);
  82. Optional<DefinedSVal> DV = V.getAs<DefinedSVal>();
  83. if (!DV)
  84. continue;
  85. // Process the case when the argument is not a location.
  86. assert(!haveRefTypeParam || DV->getAs<Loc>());
  87. if (haveAttrNonNull && !DV->getAs<Loc>()) {
  88. // If the argument is a union type, we want to handle a potential
  89. // transparent_union GCC extension.
  90. if (!ArgE)
  91. continue;
  92. QualType T = ArgE->getType();
  93. const RecordType *UT = T->getAsUnionType();
  94. if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
  95. continue;
  96. if (Optional<nonloc::CompoundVal> CSV =
  97. DV->getAs<nonloc::CompoundVal>()) {
  98. nonloc::CompoundVal::iterator CSV_I = CSV->begin();
  99. assert(CSV_I != CSV->end());
  100. V = *CSV_I;
  101. DV = V.getAs<DefinedSVal>();
  102. assert(++CSV_I == CSV->end());
  103. // FIXME: Handle (some_union){ some_other_union_val }, which turns into
  104. // a LazyCompoundVal inside a CompoundVal.
  105. if (!V.getAs<Loc>())
  106. continue;
  107. // Retrieve the corresponding expression.
  108. if (const CompoundLiteralExpr *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
  109. if (const InitListExpr *IE =
  110. dyn_cast<InitListExpr>(CE->getInitializer()))
  111. ArgE = dyn_cast<Expr>(*(IE->begin()));
  112. } else {
  113. // FIXME: Handle LazyCompoundVals?
  114. continue;
  115. }
  116. }
  117. ConstraintManager &CM = C.getConstraintManager();
  118. ProgramStateRef stateNotNull, stateNull;
  119. std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
  120. if (stateNull && !stateNotNull) {
  121. // Generate an error node. Check for a null node in case
  122. // we cache out.
  123. if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
  124. std::unique_ptr<BugReport> R;
  125. if (haveAttrNonNull)
  126. R = genReportNullAttrNonNull(errorNode, ArgE);
  127. else if (haveRefTypeParam)
  128. R = genReportReferenceToNullPointer(errorNode, ArgE);
  129. // Highlight the range of the argument that was null.
  130. R->addRange(Call.getArgSourceRange(idx));
  131. // Emit the bug report.
  132. C.emitReport(std::move(R));
  133. }
  134. // Always return. Either we cached out or we just emitted an error.
  135. return;
  136. }
  137. // If a pointer value passed the check we should assume that it is
  138. // indeed not null from this point forward.
  139. assert(stateNotNull);
  140. state = stateNotNull;
  141. }
  142. // If we reach here all of the arguments passed the nonnull check.
  143. // If 'state' has been updated generated a new node.
  144. C.addTransition(state);
  145. }
  146. std::unique_ptr<BugReport>
  147. NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode,
  148. const Expr *ArgE) const {
  149. // Lazily allocate the BugType object if it hasn't already been
  150. // created. Ownership is transferred to the BugReporter object once
  151. // the BugReport is passed to 'EmitWarning'.
  152. if (!BTAttrNonNull)
  153. BTAttrNonNull.reset(new BugType(
  154. this, "Argument with 'nonnull' attribute passed null", "API"));
  155. auto R = llvm::make_unique<BugReport>(
  156. *BTAttrNonNull,
  157. "Null pointer passed as an argument to a 'nonnull' parameter", ErrorNode);
  158. if (ArgE)
  159. bugreporter::trackNullOrUndefValue(ErrorNode, ArgE, *R);
  160. return R;
  161. }
  162. std::unique_ptr<BugReport> NonNullParamChecker::genReportReferenceToNullPointer(
  163. const ExplodedNode *ErrorNode, const Expr *ArgE) const {
  164. if (!BTNullRefArg)
  165. BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer"));
  166. auto R = llvm::make_unique<BugReport>(
  167. *BTNullRefArg, "Forming reference to null pointer", ErrorNode);
  168. if (ArgE) {
  169. const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
  170. if (!ArgEDeref)
  171. ArgEDeref = ArgE;
  172. bugreporter::trackNullOrUndefValue(ErrorNode,
  173. ArgEDeref,
  174. *R);
  175. }
  176. return R;
  177. }
  178. void ento::registerNonNullParamChecker(CheckerManager &mgr) {
  179. mgr.registerChecker<NonNullParamChecker>();
  180. }