25#include "llvm/ADT/StringExtras.h"
31class NonNullParamChecker
32 :
public Checker<check::PreCall, check::BeginFunction,
33 EventDispatcher<ImplicitNullDerefEvent>> {
34 const BugType BTAttrNonNull{
35 this,
"Argument with 'nonnull' attribute passed null",
"API"};
36 const BugType BTNullRefArg{
this,
"Dereference of null pointer"};
39 void checkPreCall(
const CallEvent &
Call, CheckerContext &
C)
const;
40 void checkBeginFunction(CheckerContext &
C)
const;
42 std::unique_ptr<PathSensitiveBugReport>
43 genReportNullAttrNonNull(
const ExplodedNode *ErrorN,
const Expr *ArgE,
44 unsigned IdxOfArg)
const;
45 std::unique_ptr<PathSensitiveBugReport>
46 genReportReferenceToNullPointer(
const ExplodedNode *ErrorN,
47 const Expr *ArgE)
const;
50template <
class CallType>
51void setBitsAccordingToFunctionAttributes(
const CallType &
Call,
52 llvm::SmallBitVector &AttrNonNull) {
66 unsigned IdxAST = Idx.getASTIndex();
67 if (IdxAST >= AttrNonNull.size())
69 AttrNonNull.set(IdxAST);
74template <
class CallType>
75void setBitsAccordingToParameterAttributes(
const CallType &
Call,
76 llvm::SmallBitVector &AttrNonNull) {
87template <
class CallType>
88llvm::SmallBitVector getNonNullAttrsImpl(
const CallType &
Call,
89 unsigned ExpectedSize) {
90 llvm::SmallBitVector AttrNonNull(ExpectedSize);
92 setBitsAccordingToFunctionAttributes(
Call, AttrNonNull);
93 setBitsAccordingToParameterAttributes(
Call, AttrNonNull);
100 return getNonNullAttrsImpl(
Call,
Call.getNumArgs());
104llvm::SmallBitVector getNonNullAttrs(
const AnyCall &
Call) {
105 return getNonNullAttrsImpl(
Call,
Call.param_size());
114 llvm::SmallBitVector AttrNonNull = getNonNullAttrs(
Call);
115 unsigned NumArgs =
Call.getNumArgs();
118 ArrayRef<ParmVarDecl *> parms =
Call.parameters();
120 for (
unsigned idx = 0; idx < NumArgs; ++idx) {
122 bool HasParam = idx < parms.size();
126 bool HasRefTypeParam =
127 HasParam ? parms[idx]->getType()->isReferenceType() :
false;
128 bool ExpectedToBeNonNull = AttrNonNull.test(idx);
130 if (!ExpectedToBeNonNull && !HasRefTypeParam)
134 const Expr *ArgE =
Call.getArgExpr(idx);
135 SVal
V =
Call.getArgSVal(idx);
136 auto DV =
V.getAs<DefinedSVal>();
140 assert(!HasRefTypeParam ||
isa<Loc>(*DV));
143 if (ExpectedToBeNonNull && !
isa<Loc>(*DV)) {
152 !UT->getDecl()->getMostRecentDecl()->hasAttr<TransparentUnionAttr>())
155 auto CSV = DV->getAs<nonloc::CompoundVal>();
162 DV =
V.getAs<DefinedSVal>();
163 assert(++CSV->begin() == CSV->end());
170 if (
const auto *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
171 if (
const auto *IE = dyn_cast<InitListExpr>(CE->getInitializer()))
172 ArgE = dyn_cast<Expr>(*(IE->begin()));
175 ConstraintManager &CM =
C.getConstraintManager();
177 std::tie(stateNotNull, stateNull) = CM.
assumeDual(state, *DV);
181 if (stateNull && !stateNotNull) {
182 if (ExplodedNode *errorNode =
C.generateErrorNode(stateNull)) {
184 std::unique_ptr<BugReport> R;
185 if (ExpectedToBeNonNull)
186 R = genReportNullAttrNonNull(errorNode, ArgE, idx + 1);
187 else if (HasRefTypeParam)
188 R = genReportReferenceToNullPointer(errorNode, ArgE);
191 R->addRange(
Call.getArgSourceRange(idx));
194 C.emitReport(std::move(R));
202 if (ExplodedNode *N =
C.generateSink(stateNull,
C.getPredecessor())) {
203 ImplicitNullDerefEvent
event = {
204 V,
false, N, &
C.getBugReporter(),
206 dispatchEvent(event);
212 state = stateNotNull;
217 C.addTransition(state);
236void NonNullParamChecker::checkBeginFunction(CheckerContext &Context)
const {
239 if (!Context.inTopFrame())
242 const LocationContext *LocContext = Context.getLocationContext();
252 llvm::SmallBitVector ParameterNonNullMarks = getNonNullAttrs(*AbstractCall);
254 for (
const ParmVarDecl *
Parameter : AbstractCall->parameters()) {
256 if (!ParameterNonNullMarks.test(
Parameter->getFunctionScopeIndex()))
262 if (!
Parameter->getType()->isPointerType())
265 Loc ParameterLoc = State->getLValue(
Parameter, LocContext);
268 State->getSVal(ParameterLoc).castAs<DefinedOrUnknownSVal>();
276 Context.addTransition(State);
279std::unique_ptr<PathSensitiveBugReport>
280NonNullParamChecker::genReportNullAttrNonNull(
const ExplodedNode *ErrorNode,
282 unsigned IdxOfArg)
const {
283 llvm::SmallString<256> SBuf;
284 llvm::raw_svector_ostream
OS(SBuf);
285 OS <<
"Null pointer passed to "
286 << IdxOfArg << llvm::getOrdinalSuffix(IdxOfArg)
287 <<
" parameter expecting 'nonnull'";
290 std::make_unique<PathSensitiveBugReport>(BTAttrNonNull, SBuf, ErrorNode);
297std::unique_ptr<PathSensitiveBugReport>
298NonNullParamChecker::genReportReferenceToNullPointer(
299 const ExplodedNode *ErrorNode,
const Expr *ArgE)
const {
300 auto R = std::make_unique<PathSensitiveBugReport>(
301 BTNullRefArg,
"Forming reference to null pointer", ErrorNode);
311void ento::registerNonNullParamChecker(CheckerManager &mgr) {
315bool ento::shouldRegisterNonNullParamChecker(
const CheckerManager &mgr) {
An instance of this class corresponds to a call.
static std::optional< AnyCall > forDecl(const Decl *D)
If D is a callable (Objective-C method or a function), return a constructed AnyCall object.
Decl - This represents one declaration (or definition), e.g.
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const
const Decl * getDecl() const
A single parameter index whose accessors require each use to make explicit the parameter index encodi...
Represents a parameter to a function.
const RecordType * getAsUnionType() const
NOTE: getAs*ArrayType are methods on ASTContext.
Represents an abstract call to a function or method along a particular path.
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
ProgramStatePair assumeDual(ProgramStateRef State, DefinedSVal Cond)
Returns a pair of states (StTrue, StFalse) where the given condition is assumed to be true or false,...
const Expr * getDerefExpr(const Stmt *S)
Given that expression S represents a pointer that would be dereferenced, try to find a sub-expression...
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
@ NonNull
Values of this type can never be null.
@ Parameter
The parameter type of a method or function.
const FunctionProtoType * T