1e5dd7070Spatrick //===--- NonNullParamChecker.cpp - Undefined arguments checker -*- C++ -*--===// 2e5dd7070Spatrick // 3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information. 5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e5dd7070Spatrick // 7e5dd7070Spatrick //===----------------------------------------------------------------------===// 8e5dd7070Spatrick // 9e5dd7070Spatrick // This defines NonNullParamChecker, which checks for arguments expected not to 10e5dd7070Spatrick // be null due to: 11e5dd7070Spatrick // - the corresponding parameters being declared to have nonnull attribute 12e5dd7070Spatrick // - the corresponding parameters being references; since the call would form 13e5dd7070Spatrick // a reference to a null pointer 14e5dd7070Spatrick // 15e5dd7070Spatrick //===----------------------------------------------------------------------===// 16e5dd7070Spatrick 17e5dd7070Spatrick #include "clang/AST/Attr.h" 18*ec727ea7Spatrick #include "clang/Analysis/AnyCall.h" 19*ec727ea7Spatrick #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 20e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 21e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Checker.h" 22e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/CheckerManager.h" 23e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 24e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 25*ec727ea7Spatrick #include "llvm/ADT/StringExtras.h" 26e5dd7070Spatrick 27e5dd7070Spatrick using namespace clang; 28e5dd7070Spatrick using namespace ento; 29e5dd7070Spatrick 30e5dd7070Spatrick namespace { 31e5dd7070Spatrick class NonNullParamChecker 32*ec727ea7Spatrick : public Checker<check::PreCall, check::BeginFunction, 33*ec727ea7Spatrick EventDispatcher<ImplicitNullDerefEvent>> { 34e5dd7070Spatrick mutable std::unique_ptr<BugType> BTAttrNonNull; 35e5dd7070Spatrick mutable std::unique_ptr<BugType> BTNullRefArg; 36e5dd7070Spatrick 37e5dd7070Spatrick public: 38e5dd7070Spatrick void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 39*ec727ea7Spatrick void checkBeginFunction(CheckerContext &C) const; 40e5dd7070Spatrick 41e5dd7070Spatrick std::unique_ptr<PathSensitiveBugReport> 42*ec727ea7Spatrick genReportNullAttrNonNull(const ExplodedNode *ErrorN, const Expr *ArgE, 43e5dd7070Spatrick unsigned IdxOfArg) const; 44e5dd7070Spatrick std::unique_ptr<PathSensitiveBugReport> 45e5dd7070Spatrick genReportReferenceToNullPointer(const ExplodedNode *ErrorN, 46e5dd7070Spatrick const Expr *ArgE) const; 47e5dd7070Spatrick }; 48e5dd7070Spatrick 49*ec727ea7Spatrick template <class CallType> 50*ec727ea7Spatrick void setBitsAccordingToFunctionAttributes(const CallType &Call, 51*ec727ea7Spatrick llvm::SmallBitVector &AttrNonNull) { 52e5dd7070Spatrick const Decl *FD = Call.getDecl(); 53*ec727ea7Spatrick 54e5dd7070Spatrick for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) { 55e5dd7070Spatrick if (!NonNull->args_size()) { 56*ec727ea7Spatrick // Lack of attribute parameters means that all of the parameters are 57*ec727ea7Spatrick // implicitly marked as non-null. 58*ec727ea7Spatrick AttrNonNull.set(); 59e5dd7070Spatrick break; 60e5dd7070Spatrick } 61*ec727ea7Spatrick 62e5dd7070Spatrick for (const ParamIdx &Idx : NonNull->args()) { 63*ec727ea7Spatrick // 'nonnull' attribute's parameters are 1-based and should be adjusted to 64*ec727ea7Spatrick // match actual AST parameter/argument indices. 65e5dd7070Spatrick unsigned IdxAST = Idx.getASTIndex(); 66*ec727ea7Spatrick if (IdxAST >= AttrNonNull.size()) 67e5dd7070Spatrick continue; 68e5dd7070Spatrick AttrNonNull.set(IdxAST); 69e5dd7070Spatrick } 70e5dd7070Spatrick } 71*ec727ea7Spatrick } 72*ec727ea7Spatrick 73*ec727ea7Spatrick template <class CallType> 74*ec727ea7Spatrick void setBitsAccordingToParameterAttributes(const CallType &Call, 75*ec727ea7Spatrick llvm::SmallBitVector &AttrNonNull) { 76*ec727ea7Spatrick for (const ParmVarDecl *Parameter : Call.parameters()) { 77*ec727ea7Spatrick unsigned ParameterIndex = Parameter->getFunctionScopeIndex(); 78*ec727ea7Spatrick if (ParameterIndex == AttrNonNull.size()) 79*ec727ea7Spatrick break; 80*ec727ea7Spatrick 81*ec727ea7Spatrick if (Parameter->hasAttr<NonNullAttr>()) 82*ec727ea7Spatrick AttrNonNull.set(ParameterIndex); 83*ec727ea7Spatrick } 84*ec727ea7Spatrick } 85*ec727ea7Spatrick 86*ec727ea7Spatrick template <class CallType> 87*ec727ea7Spatrick llvm::SmallBitVector getNonNullAttrsImpl(const CallType &Call, 88*ec727ea7Spatrick unsigned ExpectedSize) { 89*ec727ea7Spatrick llvm::SmallBitVector AttrNonNull(ExpectedSize); 90*ec727ea7Spatrick 91*ec727ea7Spatrick setBitsAccordingToFunctionAttributes(Call, AttrNonNull); 92*ec727ea7Spatrick setBitsAccordingToParameterAttributes(Call, AttrNonNull); 93*ec727ea7Spatrick 94e5dd7070Spatrick return AttrNonNull; 95e5dd7070Spatrick } 96e5dd7070Spatrick 97*ec727ea7Spatrick /// \return Bitvector marking non-null attributes. 98*ec727ea7Spatrick llvm::SmallBitVector getNonNullAttrs(const CallEvent &Call) { 99*ec727ea7Spatrick return getNonNullAttrsImpl(Call, Call.getNumArgs()); 100*ec727ea7Spatrick } 101*ec727ea7Spatrick 102*ec727ea7Spatrick /// \return Bitvector marking non-null attributes. 103*ec727ea7Spatrick llvm::SmallBitVector getNonNullAttrs(const AnyCall &Call) { 104*ec727ea7Spatrick return getNonNullAttrsImpl(Call, Call.param_size()); 105*ec727ea7Spatrick } 106*ec727ea7Spatrick } // end anonymous namespace 107*ec727ea7Spatrick 108e5dd7070Spatrick void NonNullParamChecker::checkPreCall(const CallEvent &Call, 109e5dd7070Spatrick CheckerContext &C) const { 110e5dd7070Spatrick if (!Call.getDecl()) 111e5dd7070Spatrick return; 112e5dd7070Spatrick 113e5dd7070Spatrick llvm::SmallBitVector AttrNonNull = getNonNullAttrs(Call); 114e5dd7070Spatrick unsigned NumArgs = Call.getNumArgs(); 115e5dd7070Spatrick 116e5dd7070Spatrick ProgramStateRef state = C.getState(); 117e5dd7070Spatrick ArrayRef<ParmVarDecl *> parms = Call.parameters(); 118e5dd7070Spatrick 119e5dd7070Spatrick for (unsigned idx = 0; idx < NumArgs; ++idx) { 120e5dd7070Spatrick // For vararg functions, a corresponding parameter decl may not exist. 121e5dd7070Spatrick bool HasParam = idx < parms.size(); 122e5dd7070Spatrick 123e5dd7070Spatrick // Check if the parameter is a reference. We want to report when reference 124e5dd7070Spatrick // to a null pointer is passed as a parameter. 125*ec727ea7Spatrick bool HasRefTypeParam = 126e5dd7070Spatrick HasParam ? parms[idx]->getType()->isReferenceType() : false; 127*ec727ea7Spatrick bool ExpectedToBeNonNull = AttrNonNull.test(idx); 128e5dd7070Spatrick 129*ec727ea7Spatrick if (!ExpectedToBeNonNull && !HasRefTypeParam) 130e5dd7070Spatrick continue; 131e5dd7070Spatrick 132e5dd7070Spatrick // If the value is unknown or undefined, we can't perform this check. 133e5dd7070Spatrick const Expr *ArgE = Call.getArgExpr(idx); 134e5dd7070Spatrick SVal V = Call.getArgSVal(idx); 135e5dd7070Spatrick auto DV = V.getAs<DefinedSVal>(); 136e5dd7070Spatrick if (!DV) 137e5dd7070Spatrick continue; 138e5dd7070Spatrick 139*ec727ea7Spatrick assert(!HasRefTypeParam || DV->getAs<Loc>()); 140e5dd7070Spatrick 141e5dd7070Spatrick // Process the case when the argument is not a location. 142*ec727ea7Spatrick if (ExpectedToBeNonNull && !DV->getAs<Loc>()) { 143e5dd7070Spatrick // If the argument is a union type, we want to handle a potential 144e5dd7070Spatrick // transparent_union GCC extension. 145e5dd7070Spatrick if (!ArgE) 146e5dd7070Spatrick continue; 147e5dd7070Spatrick 148e5dd7070Spatrick QualType T = ArgE->getType(); 149e5dd7070Spatrick const RecordType *UT = T->getAsUnionType(); 150e5dd7070Spatrick if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>()) 151e5dd7070Spatrick continue; 152e5dd7070Spatrick 153e5dd7070Spatrick auto CSV = DV->getAs<nonloc::CompoundVal>(); 154e5dd7070Spatrick 155e5dd7070Spatrick // FIXME: Handle LazyCompoundVals? 156e5dd7070Spatrick if (!CSV) 157e5dd7070Spatrick continue; 158e5dd7070Spatrick 159e5dd7070Spatrick V = *(CSV->begin()); 160e5dd7070Spatrick DV = V.getAs<DefinedSVal>(); 161e5dd7070Spatrick assert(++CSV->begin() == CSV->end()); 162e5dd7070Spatrick // FIXME: Handle (some_union){ some_other_union_val }, which turns into 163e5dd7070Spatrick // a LazyCompoundVal inside a CompoundVal. 164e5dd7070Spatrick if (!V.getAs<Loc>()) 165e5dd7070Spatrick continue; 166e5dd7070Spatrick 167e5dd7070Spatrick // Retrieve the corresponding expression. 168e5dd7070Spatrick if (const auto *CE = dyn_cast<CompoundLiteralExpr>(ArgE)) 169e5dd7070Spatrick if (const auto *IE = dyn_cast<InitListExpr>(CE->getInitializer())) 170e5dd7070Spatrick ArgE = dyn_cast<Expr>(*(IE->begin())); 171e5dd7070Spatrick } 172e5dd7070Spatrick 173e5dd7070Spatrick ConstraintManager &CM = C.getConstraintManager(); 174e5dd7070Spatrick ProgramStateRef stateNotNull, stateNull; 175e5dd7070Spatrick std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV); 176e5dd7070Spatrick 177e5dd7070Spatrick // Generate an error node. Check for a null node in case 178e5dd7070Spatrick // we cache out. 179e5dd7070Spatrick if (stateNull && !stateNotNull) { 180e5dd7070Spatrick if (ExplodedNode *errorNode = C.generateErrorNode(stateNull)) { 181e5dd7070Spatrick 182e5dd7070Spatrick std::unique_ptr<BugReport> R; 183*ec727ea7Spatrick if (ExpectedToBeNonNull) 184e5dd7070Spatrick R = genReportNullAttrNonNull(errorNode, ArgE, idx + 1); 185*ec727ea7Spatrick else if (HasRefTypeParam) 186e5dd7070Spatrick R = genReportReferenceToNullPointer(errorNode, ArgE); 187e5dd7070Spatrick 188e5dd7070Spatrick // Highlight the range of the argument that was null. 189e5dd7070Spatrick R->addRange(Call.getArgSourceRange(idx)); 190e5dd7070Spatrick 191e5dd7070Spatrick // Emit the bug report. 192e5dd7070Spatrick C.emitReport(std::move(R)); 193e5dd7070Spatrick } 194e5dd7070Spatrick 195e5dd7070Spatrick // Always return. Either we cached out or we just emitted an error. 196e5dd7070Spatrick return; 197e5dd7070Spatrick } 198e5dd7070Spatrick 199e5dd7070Spatrick if (stateNull) { 200e5dd7070Spatrick if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) { 201e5dd7070Spatrick ImplicitNullDerefEvent event = { 202e5dd7070Spatrick V, false, N, &C.getBugReporter(), 203*ec727ea7Spatrick /*IsDirectDereference=*/HasRefTypeParam}; 204e5dd7070Spatrick dispatchEvent(event); 205e5dd7070Spatrick } 206e5dd7070Spatrick } 207e5dd7070Spatrick 208e5dd7070Spatrick // If a pointer value passed the check we should assume that it is 209e5dd7070Spatrick // indeed not null from this point forward. 210e5dd7070Spatrick state = stateNotNull; 211e5dd7070Spatrick } 212e5dd7070Spatrick 213e5dd7070Spatrick // If we reach here all of the arguments passed the nonnull check. 214e5dd7070Spatrick // If 'state' has been updated generated a new node. 215e5dd7070Spatrick C.addTransition(state); 216e5dd7070Spatrick } 217e5dd7070Spatrick 218*ec727ea7Spatrick /// We want to trust developer annotations and consider all 'nonnull' parameters 219*ec727ea7Spatrick /// as non-null indeed. Each marked parameter will get a corresponding 220*ec727ea7Spatrick /// constraint. 221*ec727ea7Spatrick /// 222*ec727ea7Spatrick /// This approach will not only help us to get rid of some false positives, but 223*ec727ea7Spatrick /// remove duplicates and shorten warning traces as well. 224*ec727ea7Spatrick /// 225*ec727ea7Spatrick /// \code 226*ec727ea7Spatrick /// void foo(int *x) [[gnu::nonnull]] { 227*ec727ea7Spatrick /// // . . . 228*ec727ea7Spatrick /// *x = 42; // we don't want to consider this as an error... 229*ec727ea7Spatrick /// // . . . 230*ec727ea7Spatrick /// } 231*ec727ea7Spatrick /// 232*ec727ea7Spatrick /// foo(nullptr); // ...and report here instead 233*ec727ea7Spatrick /// \endcode 234*ec727ea7Spatrick void NonNullParamChecker::checkBeginFunction(CheckerContext &Context) const { 235*ec727ea7Spatrick // Planned assumption makes sense only for top-level functions. 236*ec727ea7Spatrick // Inlined functions will get similar constraints as part of 'checkPreCall'. 237*ec727ea7Spatrick if (!Context.inTopFrame()) 238*ec727ea7Spatrick return; 239*ec727ea7Spatrick 240*ec727ea7Spatrick const LocationContext *LocContext = Context.getLocationContext(); 241*ec727ea7Spatrick 242*ec727ea7Spatrick const Decl *FD = LocContext->getDecl(); 243*ec727ea7Spatrick // AnyCall helps us here to avoid checking for FunctionDecl and ObjCMethodDecl 244*ec727ea7Spatrick // separately and aggregates interfaces of these classes. 245*ec727ea7Spatrick auto AbstractCall = AnyCall::forDecl(FD); 246*ec727ea7Spatrick if (!AbstractCall) 247*ec727ea7Spatrick return; 248*ec727ea7Spatrick 249*ec727ea7Spatrick ProgramStateRef State = Context.getState(); 250*ec727ea7Spatrick llvm::SmallBitVector ParameterNonNullMarks = getNonNullAttrs(*AbstractCall); 251*ec727ea7Spatrick 252*ec727ea7Spatrick for (const ParmVarDecl *Parameter : AbstractCall->parameters()) { 253*ec727ea7Spatrick // 1. Check parameter if it is annotated as non-null 254*ec727ea7Spatrick if (!ParameterNonNullMarks.test(Parameter->getFunctionScopeIndex())) 255*ec727ea7Spatrick continue; 256*ec727ea7Spatrick 257*ec727ea7Spatrick // 2. Check that parameter is a pointer. 258*ec727ea7Spatrick // Nonnull attribute can be applied to non-pointers (by default 259*ec727ea7Spatrick // __attribute__(nonnull) implies "all parameters"). 260*ec727ea7Spatrick if (!Parameter->getType()->isPointerType()) 261*ec727ea7Spatrick continue; 262*ec727ea7Spatrick 263*ec727ea7Spatrick Loc ParameterLoc = State->getLValue(Parameter, LocContext); 264*ec727ea7Spatrick // We never consider top-level function parameters undefined. 265*ec727ea7Spatrick auto StoredVal = 266*ec727ea7Spatrick State->getSVal(ParameterLoc).castAs<DefinedOrUnknownSVal>(); 267*ec727ea7Spatrick 268*ec727ea7Spatrick // 3. Assume that it is indeed non-null 269*ec727ea7Spatrick if (ProgramStateRef NewState = State->assume(StoredVal, true)) { 270*ec727ea7Spatrick State = NewState; 271*ec727ea7Spatrick } 272*ec727ea7Spatrick } 273*ec727ea7Spatrick 274*ec727ea7Spatrick Context.addTransition(State); 275*ec727ea7Spatrick } 276*ec727ea7Spatrick 277e5dd7070Spatrick std::unique_ptr<PathSensitiveBugReport> 278e5dd7070Spatrick NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode, 279e5dd7070Spatrick const Expr *ArgE, 280e5dd7070Spatrick unsigned IdxOfArg) const { 281e5dd7070Spatrick // Lazily allocate the BugType object if it hasn't already been 282e5dd7070Spatrick // created. Ownership is transferred to the BugReporter object once 283e5dd7070Spatrick // the BugReport is passed to 'EmitWarning'. 284e5dd7070Spatrick if (!BTAttrNonNull) 285e5dd7070Spatrick BTAttrNonNull.reset(new BugType( 286e5dd7070Spatrick this, "Argument with 'nonnull' attribute passed null", "API")); 287e5dd7070Spatrick 288e5dd7070Spatrick llvm::SmallString<256> SBuf; 289e5dd7070Spatrick llvm::raw_svector_ostream OS(SBuf); 290e5dd7070Spatrick OS << "Null pointer passed to " 291e5dd7070Spatrick << IdxOfArg << llvm::getOrdinalSuffix(IdxOfArg) 292e5dd7070Spatrick << " parameter expecting 'nonnull'"; 293e5dd7070Spatrick 294e5dd7070Spatrick auto R = 295e5dd7070Spatrick std::make_unique<PathSensitiveBugReport>(*BTAttrNonNull, SBuf, ErrorNode); 296e5dd7070Spatrick if (ArgE) 297e5dd7070Spatrick bugreporter::trackExpressionValue(ErrorNode, ArgE, *R); 298e5dd7070Spatrick 299e5dd7070Spatrick return R; 300e5dd7070Spatrick } 301e5dd7070Spatrick 302e5dd7070Spatrick std::unique_ptr<PathSensitiveBugReport> 303e5dd7070Spatrick NonNullParamChecker::genReportReferenceToNullPointer( 304e5dd7070Spatrick const ExplodedNode *ErrorNode, const Expr *ArgE) const { 305e5dd7070Spatrick if (!BTNullRefArg) 306e5dd7070Spatrick BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer")); 307e5dd7070Spatrick 308e5dd7070Spatrick auto R = std::make_unique<PathSensitiveBugReport>( 309e5dd7070Spatrick *BTNullRefArg, "Forming reference to null pointer", ErrorNode); 310e5dd7070Spatrick if (ArgE) { 311e5dd7070Spatrick const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE); 312e5dd7070Spatrick if (!ArgEDeref) 313e5dd7070Spatrick ArgEDeref = ArgE; 314e5dd7070Spatrick bugreporter::trackExpressionValue(ErrorNode, ArgEDeref, *R); 315e5dd7070Spatrick } 316e5dd7070Spatrick return R; 317e5dd7070Spatrick 318e5dd7070Spatrick } 319e5dd7070Spatrick 320e5dd7070Spatrick void ento::registerNonNullParamChecker(CheckerManager &mgr) { 321e5dd7070Spatrick mgr.registerChecker<NonNullParamChecker>(); 322e5dd7070Spatrick } 323e5dd7070Spatrick 324*ec727ea7Spatrick bool ento::shouldRegisterNonNullParamChecker(const CheckerManager &mgr) { 325e5dd7070Spatrick return true; 326e5dd7070Spatrick } 327