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