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