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