xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //===--- NonNullParamChecker.cpp - Undefined arguments checker -*- C++ -*--===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This defines NonNullParamChecker, which checks for arguments expected not to
107330f729Sjoerg // be null due to:
117330f729Sjoerg //   - the corresponding parameters being declared to have nonnull attribute
127330f729Sjoerg //   - the corresponding parameters being references; since the call would form
137330f729Sjoerg //     a reference to a null pointer
147330f729Sjoerg //
157330f729Sjoerg //===----------------------------------------------------------------------===//
167330f729Sjoerg 
177330f729Sjoerg #include "clang/AST/Attr.h"
18*e038c9c4Sjoerg #include "clang/Analysis/AnyCall.h"
19*e038c9c4Sjoerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
207330f729Sjoerg #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
217330f729Sjoerg #include "clang/StaticAnalyzer/Core/Checker.h"
227330f729Sjoerg #include "clang/StaticAnalyzer/Core/CheckerManager.h"
237330f729Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
247330f729Sjoerg #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
25*e038c9c4Sjoerg #include "llvm/ADT/StringExtras.h"
267330f729Sjoerg 
277330f729Sjoerg using namespace clang;
287330f729Sjoerg using namespace ento;
297330f729Sjoerg 
307330f729Sjoerg namespace {
317330f729Sjoerg class NonNullParamChecker
32*e038c9c4Sjoerg     : public Checker<check::PreCall, check::BeginFunction,
33*e038c9c4Sjoerg                      EventDispatcher<ImplicitNullDerefEvent>> {
347330f729Sjoerg   mutable std::unique_ptr<BugType> BTAttrNonNull;
357330f729Sjoerg   mutable std::unique_ptr<BugType> BTNullRefArg;
367330f729Sjoerg 
377330f729Sjoerg public:
387330f729Sjoerg   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
39*e038c9c4Sjoerg   void checkBeginFunction(CheckerContext &C) const;
407330f729Sjoerg 
417330f729Sjoerg   std::unique_ptr<PathSensitiveBugReport>
42*e038c9c4Sjoerg   genReportNullAttrNonNull(const ExplodedNode *ErrorN, const Expr *ArgE,
437330f729Sjoerg                            unsigned IdxOfArg) const;
447330f729Sjoerg   std::unique_ptr<PathSensitiveBugReport>
457330f729Sjoerg   genReportReferenceToNullPointer(const ExplodedNode *ErrorN,
467330f729Sjoerg                                   const Expr *ArgE) const;
477330f729Sjoerg };
487330f729Sjoerg 
49*e038c9c4Sjoerg template <class CallType>
setBitsAccordingToFunctionAttributes(const CallType & Call,llvm::SmallBitVector & AttrNonNull)50*e038c9c4Sjoerg void setBitsAccordingToFunctionAttributes(const CallType &Call,
51*e038c9c4Sjoerg                                           llvm::SmallBitVector &AttrNonNull) {
527330f729Sjoerg   const Decl *FD = Call.getDecl();
53*e038c9c4Sjoerg 
547330f729Sjoerg   for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
557330f729Sjoerg     if (!NonNull->args_size()) {
56*e038c9c4Sjoerg       // Lack of attribute parameters means that all of the parameters are
57*e038c9c4Sjoerg       // implicitly marked as non-null.
58*e038c9c4Sjoerg       AttrNonNull.set();
597330f729Sjoerg       break;
607330f729Sjoerg     }
61*e038c9c4Sjoerg 
627330f729Sjoerg     for (const ParamIdx &Idx : NonNull->args()) {
63*e038c9c4Sjoerg       // 'nonnull' attribute's parameters are 1-based and should be adjusted to
64*e038c9c4Sjoerg       // match actual AST parameter/argument indices.
657330f729Sjoerg       unsigned IdxAST = Idx.getASTIndex();
66*e038c9c4Sjoerg       if (IdxAST >= AttrNonNull.size())
677330f729Sjoerg         continue;
687330f729Sjoerg       AttrNonNull.set(IdxAST);
697330f729Sjoerg     }
707330f729Sjoerg   }
71*e038c9c4Sjoerg }
72*e038c9c4Sjoerg 
73*e038c9c4Sjoerg template <class CallType>
setBitsAccordingToParameterAttributes(const CallType & Call,llvm::SmallBitVector & AttrNonNull)74*e038c9c4Sjoerg void setBitsAccordingToParameterAttributes(const CallType &Call,
75*e038c9c4Sjoerg                                            llvm::SmallBitVector &AttrNonNull) {
76*e038c9c4Sjoerg   for (const ParmVarDecl *Parameter : Call.parameters()) {
77*e038c9c4Sjoerg     unsigned ParameterIndex = Parameter->getFunctionScopeIndex();
78*e038c9c4Sjoerg     if (ParameterIndex == AttrNonNull.size())
79*e038c9c4Sjoerg       break;
80*e038c9c4Sjoerg 
81*e038c9c4Sjoerg     if (Parameter->hasAttr<NonNullAttr>())
82*e038c9c4Sjoerg       AttrNonNull.set(ParameterIndex);
83*e038c9c4Sjoerg   }
84*e038c9c4Sjoerg }
85*e038c9c4Sjoerg 
86*e038c9c4Sjoerg template <class CallType>
getNonNullAttrsImpl(const CallType & Call,unsigned ExpectedSize)87*e038c9c4Sjoerg llvm::SmallBitVector getNonNullAttrsImpl(const CallType &Call,
88*e038c9c4Sjoerg                                          unsigned ExpectedSize) {
89*e038c9c4Sjoerg   llvm::SmallBitVector AttrNonNull(ExpectedSize);
90*e038c9c4Sjoerg 
91*e038c9c4Sjoerg   setBitsAccordingToFunctionAttributes(Call, AttrNonNull);
92*e038c9c4Sjoerg   setBitsAccordingToParameterAttributes(Call, AttrNonNull);
93*e038c9c4Sjoerg 
947330f729Sjoerg   return AttrNonNull;
957330f729Sjoerg }
967330f729Sjoerg 
97*e038c9c4Sjoerg /// \return Bitvector marking non-null attributes.
getNonNullAttrs(const CallEvent & Call)98*e038c9c4Sjoerg llvm::SmallBitVector getNonNullAttrs(const CallEvent &Call) {
99*e038c9c4Sjoerg   return getNonNullAttrsImpl(Call, Call.getNumArgs());
100*e038c9c4Sjoerg }
101*e038c9c4Sjoerg 
102*e038c9c4Sjoerg /// \return Bitvector marking non-null attributes.
getNonNullAttrs(const AnyCall & Call)103*e038c9c4Sjoerg llvm::SmallBitVector getNonNullAttrs(const AnyCall &Call) {
104*e038c9c4Sjoerg   return getNonNullAttrsImpl(Call, Call.param_size());
105*e038c9c4Sjoerg }
106*e038c9c4Sjoerg } // end anonymous namespace
107*e038c9c4Sjoerg 
checkPreCall(const CallEvent & Call,CheckerContext & C) const1087330f729Sjoerg void NonNullParamChecker::checkPreCall(const CallEvent &Call,
1097330f729Sjoerg                                        CheckerContext &C) const {
1107330f729Sjoerg   if (!Call.getDecl())
1117330f729Sjoerg     return;
1127330f729Sjoerg 
1137330f729Sjoerg   llvm::SmallBitVector AttrNonNull = getNonNullAttrs(Call);
1147330f729Sjoerg   unsigned NumArgs = Call.getNumArgs();
1157330f729Sjoerg 
1167330f729Sjoerg   ProgramStateRef state = C.getState();
1177330f729Sjoerg   ArrayRef<ParmVarDecl *> parms = Call.parameters();
1187330f729Sjoerg 
1197330f729Sjoerg   for (unsigned idx = 0; idx < NumArgs; ++idx) {
1207330f729Sjoerg     // For vararg functions, a corresponding parameter decl may not exist.
1217330f729Sjoerg     bool HasParam = idx < parms.size();
1227330f729Sjoerg 
1237330f729Sjoerg     // Check if the parameter is a reference. We want to report when reference
1247330f729Sjoerg     // to a null pointer is passed as a parameter.
125*e038c9c4Sjoerg     bool HasRefTypeParam =
1267330f729Sjoerg         HasParam ? parms[idx]->getType()->isReferenceType() : false;
127*e038c9c4Sjoerg     bool ExpectedToBeNonNull = AttrNonNull.test(idx);
1287330f729Sjoerg 
129*e038c9c4Sjoerg     if (!ExpectedToBeNonNull && !HasRefTypeParam)
1307330f729Sjoerg       continue;
1317330f729Sjoerg 
1327330f729Sjoerg     // If the value is unknown or undefined, we can't perform this check.
1337330f729Sjoerg     const Expr *ArgE = Call.getArgExpr(idx);
1347330f729Sjoerg     SVal V = Call.getArgSVal(idx);
1357330f729Sjoerg     auto DV = V.getAs<DefinedSVal>();
1367330f729Sjoerg     if (!DV)
1377330f729Sjoerg       continue;
1387330f729Sjoerg 
139*e038c9c4Sjoerg     assert(!HasRefTypeParam || DV->getAs<Loc>());
1407330f729Sjoerg 
1417330f729Sjoerg     // Process the case when the argument is not a location.
142*e038c9c4Sjoerg     if (ExpectedToBeNonNull && !DV->getAs<Loc>()) {
1437330f729Sjoerg       // If the argument is a union type, we want to handle a potential
1447330f729Sjoerg       // transparent_union GCC extension.
1457330f729Sjoerg       if (!ArgE)
1467330f729Sjoerg         continue;
1477330f729Sjoerg 
1487330f729Sjoerg       QualType T = ArgE->getType();
1497330f729Sjoerg       const RecordType *UT = T->getAsUnionType();
1507330f729Sjoerg       if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
1517330f729Sjoerg         continue;
1527330f729Sjoerg 
1537330f729Sjoerg       auto CSV = DV->getAs<nonloc::CompoundVal>();
1547330f729Sjoerg 
1557330f729Sjoerg       // FIXME: Handle LazyCompoundVals?
1567330f729Sjoerg       if (!CSV)
1577330f729Sjoerg         continue;
1587330f729Sjoerg 
1597330f729Sjoerg       V = *(CSV->begin());
1607330f729Sjoerg       DV = V.getAs<DefinedSVal>();
1617330f729Sjoerg       assert(++CSV->begin() == CSV->end());
1627330f729Sjoerg       // FIXME: Handle (some_union){ some_other_union_val }, which turns into
1637330f729Sjoerg       // a LazyCompoundVal inside a CompoundVal.
1647330f729Sjoerg       if (!V.getAs<Loc>())
1657330f729Sjoerg         continue;
1667330f729Sjoerg 
1677330f729Sjoerg       // Retrieve the corresponding expression.
1687330f729Sjoerg       if (const auto *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
1697330f729Sjoerg         if (const auto *IE = dyn_cast<InitListExpr>(CE->getInitializer()))
1707330f729Sjoerg           ArgE = dyn_cast<Expr>(*(IE->begin()));
1717330f729Sjoerg     }
1727330f729Sjoerg 
1737330f729Sjoerg     ConstraintManager &CM = C.getConstraintManager();
1747330f729Sjoerg     ProgramStateRef stateNotNull, stateNull;
1757330f729Sjoerg     std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
1767330f729Sjoerg 
1777330f729Sjoerg     // Generate an error node.  Check for a null node in case
1787330f729Sjoerg     // we cache out.
1797330f729Sjoerg     if (stateNull && !stateNotNull) {
1807330f729Sjoerg       if (ExplodedNode *errorNode = C.generateErrorNode(stateNull)) {
1817330f729Sjoerg 
1827330f729Sjoerg         std::unique_ptr<BugReport> R;
183*e038c9c4Sjoerg         if (ExpectedToBeNonNull)
1847330f729Sjoerg           R = genReportNullAttrNonNull(errorNode, ArgE, idx + 1);
185*e038c9c4Sjoerg         else if (HasRefTypeParam)
1867330f729Sjoerg           R = genReportReferenceToNullPointer(errorNode, ArgE);
1877330f729Sjoerg 
1887330f729Sjoerg         // Highlight the range of the argument that was null.
1897330f729Sjoerg         R->addRange(Call.getArgSourceRange(idx));
1907330f729Sjoerg 
1917330f729Sjoerg         // Emit the bug report.
1927330f729Sjoerg         C.emitReport(std::move(R));
1937330f729Sjoerg       }
1947330f729Sjoerg 
1957330f729Sjoerg       // Always return.  Either we cached out or we just emitted an error.
1967330f729Sjoerg       return;
1977330f729Sjoerg     }
1987330f729Sjoerg 
1997330f729Sjoerg     if (stateNull) {
2007330f729Sjoerg       if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) {
2017330f729Sjoerg         ImplicitNullDerefEvent event = {
2027330f729Sjoerg             V, false, N, &C.getBugReporter(),
203*e038c9c4Sjoerg             /*IsDirectDereference=*/HasRefTypeParam};
2047330f729Sjoerg         dispatchEvent(event);
2057330f729Sjoerg       }
2067330f729Sjoerg     }
2077330f729Sjoerg 
2087330f729Sjoerg     // If a pointer value passed the check we should assume that it is
2097330f729Sjoerg     // indeed not null from this point forward.
2107330f729Sjoerg     state = stateNotNull;
2117330f729Sjoerg   }
2127330f729Sjoerg 
2137330f729Sjoerg   // If we reach here all of the arguments passed the nonnull check.
2147330f729Sjoerg   // If 'state' has been updated generated a new node.
2157330f729Sjoerg   C.addTransition(state);
2167330f729Sjoerg }
2177330f729Sjoerg 
218*e038c9c4Sjoerg /// We want to trust developer annotations and consider all 'nonnull' parameters
219*e038c9c4Sjoerg /// as non-null indeed. Each marked parameter will get a corresponding
220*e038c9c4Sjoerg /// constraint.
221*e038c9c4Sjoerg ///
222*e038c9c4Sjoerg /// This approach will not only help us to get rid of some false positives, but
223*e038c9c4Sjoerg /// remove duplicates and shorten warning traces as well.
224*e038c9c4Sjoerg ///
225*e038c9c4Sjoerg /// \code
226*e038c9c4Sjoerg ///   void foo(int *x) [[gnu::nonnull]] {
227*e038c9c4Sjoerg ///     // . . .
228*e038c9c4Sjoerg ///     *x = 42;    // we don't want to consider this as an error...
229*e038c9c4Sjoerg ///     // . . .
230*e038c9c4Sjoerg ///   }
231*e038c9c4Sjoerg ///
232*e038c9c4Sjoerg ///   foo(nullptr); // ...and report here instead
233*e038c9c4Sjoerg /// \endcode
checkBeginFunction(CheckerContext & Context) const234*e038c9c4Sjoerg void NonNullParamChecker::checkBeginFunction(CheckerContext &Context) const {
235*e038c9c4Sjoerg   // Planned assumption makes sense only for top-level functions.
236*e038c9c4Sjoerg   // Inlined functions will get similar constraints as part of 'checkPreCall'.
237*e038c9c4Sjoerg   if (!Context.inTopFrame())
238*e038c9c4Sjoerg     return;
239*e038c9c4Sjoerg 
240*e038c9c4Sjoerg   const LocationContext *LocContext = Context.getLocationContext();
241*e038c9c4Sjoerg 
242*e038c9c4Sjoerg   const Decl *FD = LocContext->getDecl();
243*e038c9c4Sjoerg   // AnyCall helps us here to avoid checking for FunctionDecl and ObjCMethodDecl
244*e038c9c4Sjoerg   // separately and aggregates interfaces of these classes.
245*e038c9c4Sjoerg   auto AbstractCall = AnyCall::forDecl(FD);
246*e038c9c4Sjoerg   if (!AbstractCall)
247*e038c9c4Sjoerg     return;
248*e038c9c4Sjoerg 
249*e038c9c4Sjoerg   ProgramStateRef State = Context.getState();
250*e038c9c4Sjoerg   llvm::SmallBitVector ParameterNonNullMarks = getNonNullAttrs(*AbstractCall);
251*e038c9c4Sjoerg 
252*e038c9c4Sjoerg   for (const ParmVarDecl *Parameter : AbstractCall->parameters()) {
253*e038c9c4Sjoerg     // 1. Check parameter if it is annotated as non-null
254*e038c9c4Sjoerg     if (!ParameterNonNullMarks.test(Parameter->getFunctionScopeIndex()))
255*e038c9c4Sjoerg       continue;
256*e038c9c4Sjoerg 
257*e038c9c4Sjoerg     // 2. Check that parameter is a pointer.
258*e038c9c4Sjoerg     //    Nonnull attribute can be applied to non-pointers (by default
259*e038c9c4Sjoerg     //    __attribute__(nonnull) implies "all parameters").
260*e038c9c4Sjoerg     if (!Parameter->getType()->isPointerType())
261*e038c9c4Sjoerg       continue;
262*e038c9c4Sjoerg 
263*e038c9c4Sjoerg     Loc ParameterLoc = State->getLValue(Parameter, LocContext);
264*e038c9c4Sjoerg     // We never consider top-level function parameters undefined.
265*e038c9c4Sjoerg     auto StoredVal =
266*e038c9c4Sjoerg         State->getSVal(ParameterLoc).castAs<DefinedOrUnknownSVal>();
267*e038c9c4Sjoerg 
268*e038c9c4Sjoerg     // 3. Assume that it is indeed non-null
269*e038c9c4Sjoerg     if (ProgramStateRef NewState = State->assume(StoredVal, true)) {
270*e038c9c4Sjoerg       State = NewState;
271*e038c9c4Sjoerg     }
272*e038c9c4Sjoerg   }
273*e038c9c4Sjoerg 
274*e038c9c4Sjoerg   Context.addTransition(State);
275*e038c9c4Sjoerg }
276*e038c9c4Sjoerg 
2777330f729Sjoerg std::unique_ptr<PathSensitiveBugReport>
genReportNullAttrNonNull(const ExplodedNode * ErrorNode,const Expr * ArgE,unsigned IdxOfArg) const2787330f729Sjoerg NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode,
2797330f729Sjoerg                                               const Expr *ArgE,
2807330f729Sjoerg                                               unsigned IdxOfArg) const {
2817330f729Sjoerg   // Lazily allocate the BugType object if it hasn't already been
2827330f729Sjoerg   // created. Ownership is transferred to the BugReporter object once
2837330f729Sjoerg   // the BugReport is passed to 'EmitWarning'.
2847330f729Sjoerg   if (!BTAttrNonNull)
2857330f729Sjoerg     BTAttrNonNull.reset(new BugType(
2867330f729Sjoerg         this, "Argument with 'nonnull' attribute passed null", "API"));
2877330f729Sjoerg 
2887330f729Sjoerg   llvm::SmallString<256> SBuf;
2897330f729Sjoerg   llvm::raw_svector_ostream OS(SBuf);
2907330f729Sjoerg   OS << "Null pointer passed to "
2917330f729Sjoerg      << IdxOfArg << llvm::getOrdinalSuffix(IdxOfArg)
2927330f729Sjoerg      << " parameter expecting 'nonnull'";
2937330f729Sjoerg 
2947330f729Sjoerg   auto R =
2957330f729Sjoerg       std::make_unique<PathSensitiveBugReport>(*BTAttrNonNull, SBuf, ErrorNode);
2967330f729Sjoerg   if (ArgE)
2977330f729Sjoerg     bugreporter::trackExpressionValue(ErrorNode, ArgE, *R);
2987330f729Sjoerg 
2997330f729Sjoerg   return R;
3007330f729Sjoerg }
3017330f729Sjoerg 
3027330f729Sjoerg std::unique_ptr<PathSensitiveBugReport>
genReportReferenceToNullPointer(const ExplodedNode * ErrorNode,const Expr * ArgE) const3037330f729Sjoerg NonNullParamChecker::genReportReferenceToNullPointer(
3047330f729Sjoerg     const ExplodedNode *ErrorNode, const Expr *ArgE) const {
3057330f729Sjoerg   if (!BTNullRefArg)
3067330f729Sjoerg     BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer"));
3077330f729Sjoerg 
3087330f729Sjoerg   auto R = std::make_unique<PathSensitiveBugReport>(
3097330f729Sjoerg       *BTNullRefArg, "Forming reference to null pointer", ErrorNode);
3107330f729Sjoerg   if (ArgE) {
3117330f729Sjoerg     const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
3127330f729Sjoerg     if (!ArgEDeref)
3137330f729Sjoerg       ArgEDeref = ArgE;
3147330f729Sjoerg     bugreporter::trackExpressionValue(ErrorNode, ArgEDeref, *R);
3157330f729Sjoerg   }
3167330f729Sjoerg   return R;
3177330f729Sjoerg 
3187330f729Sjoerg }
3197330f729Sjoerg 
registerNonNullParamChecker(CheckerManager & mgr)3207330f729Sjoerg void ento::registerNonNullParamChecker(CheckerManager &mgr) {
3217330f729Sjoerg   mgr.registerChecker<NonNullParamChecker>();
3227330f729Sjoerg }
3237330f729Sjoerg 
shouldRegisterNonNullParamChecker(const CheckerManager & mgr)324*e038c9c4Sjoerg bool ento::shouldRegisterNonNullParamChecker(const CheckerManager &mgr) {
3257330f729Sjoerg   return true;
3267330f729Sjoerg }
327