25#include "llvm/ADT/StringExtras.h"
31class NonNullParamChecker
32 :
public Checker<check::PreCall, check::BeginFunction,
33 EventDispatcher<ImplicitNullDerefEvent>> {
34 mutable std::unique_ptr<BugType> BTAttrNonNull;
35 mutable std::unique_ptr<BugType> BTNullRefArg;
41 std::unique_ptr<PathSensitiveBugReport>
43 unsigned IdxOfArg)
const;
44 std::unique_ptr<PathSensitiveBugReport>
45 genReportReferenceToNullPointer(
const ExplodedNode *ErrorN,
46 const Expr *ArgE)
const;
49template <
class CallType>
50void setBitsAccordingToFunctionAttributes(
const CallType &
Call,
51 llvm::SmallBitVector &AttrNonNull) {
65 unsigned IdxAST = Idx.getASTIndex();
66 if (IdxAST >= AttrNonNull.size())
68 AttrNonNull.set(IdxAST);
73template <
class CallType>
74void setBitsAccordingToParameterAttributes(
const CallType &
Call,
75 llvm::SmallBitVector &AttrNonNull) {
77 unsigned ParameterIndex =
Parameter->getFunctionScopeIndex();
78 if (ParameterIndex == AttrNonNull.size())
82 AttrNonNull.set(ParameterIndex);
86template <
class CallType>
87llvm::SmallBitVector getNonNullAttrsImpl(
const CallType &
Call,
88 unsigned ExpectedSize) {
89 llvm::SmallBitVector AttrNonNull(ExpectedSize);
91 setBitsAccordingToFunctionAttributes(
Call, AttrNonNull);
92 setBitsAccordingToParameterAttributes(
Call, AttrNonNull);
99 return getNonNullAttrsImpl(
Call,
Call.getNumArgs());
103llvm::SmallBitVector getNonNullAttrs(
const AnyCall &
Call) {
104 return getNonNullAttrsImpl(
Call,
Call.param_size());
113 llvm::SmallBitVector AttrNonNull = getNonNullAttrs(
Call);
114 unsigned NumArgs =
Call.getNumArgs();
119 for (
unsigned idx = 0; idx < NumArgs; ++idx) {
121 bool HasParam = idx < parms.size();
125 bool HasRefTypeParam =
126 HasParam ? parms[idx]->getType()->isReferenceType() :
false;
127 bool ExpectedToBeNonNull = AttrNonNull.test(idx);
129 if (!ExpectedToBeNonNull && !HasRefTypeParam)
133 const Expr *ArgE =
Call.getArgExpr(idx);
139 assert(!HasRefTypeParam || isa<Loc>(*DV));
142 if (ExpectedToBeNonNull && !isa<Loc>(*DV)) {
161 assert(++CSV->begin() == CSV->end());
168 if (
const auto *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
169 if (
const auto *IE = dyn_cast<InitListExpr>(CE->getInitializer()))
170 ArgE = dyn_cast<Expr>(*(IE->begin()));
175 std::tie(stateNotNull, stateNull) = CM.
assumeDual(state, *DV);
179 if (stateNull && !stateNotNull) {
180 if (
ExplodedNode *errorNode =
C.generateErrorNode(stateNull)) {
182 std::unique_ptr<BugReport> R;
183 if (ExpectedToBeNonNull)
184 R = genReportNullAttrNonNull(errorNode, ArgE, idx + 1);
185 else if (HasRefTypeParam)
186 R = genReportReferenceToNullPointer(errorNode, ArgE);
189 R->addRange(
Call.getArgSourceRange(idx));
192 C.emitReport(std::move(R));
200 if (
ExplodedNode *N =
C.generateSink(stateNull,
C.getPredecessor())) {
202 V,
false, N, &
C.getBugReporter(),
204 dispatchEvent(event);
210 state = stateNotNull;
215 C.addTransition(state);
234void NonNullParamChecker::checkBeginFunction(
CheckerContext &Context)
const {
237 if (!Context.inTopFrame())
250 llvm::SmallBitVector ParameterNonNullMarks = getNonNullAttrs(*AbstractCall);
254 if (!ParameterNonNullMarks.test(
Parameter->getFunctionScopeIndex()))
260 if (!
Parameter->getType()->isPointerType())
263 Loc ParameterLoc = State->getLValue(
Parameter, LocContext);
274 Context.addTransition(State);
277std::unique_ptr<PathSensitiveBugReport>
278NonNullParamChecker::genReportNullAttrNonNull(
const ExplodedNode *ErrorNode,
280 unsigned IdxOfArg)
const {
285 BTAttrNonNull.reset(
new BugType(
286 this,
"Argument with 'nonnull' attribute passed null",
"API"));
289 llvm::raw_svector_ostream OS(SBuf);
290 OS <<
"Null pointer passed to "
291 << IdxOfArg << llvm::getOrdinalSuffix(IdxOfArg)
292 <<
" parameter expecting 'nonnull'";
295 std::make_unique<PathSensitiveBugReport>(*BTAttrNonNull, SBuf, ErrorNode);
302std::unique_ptr<PathSensitiveBugReport>
303NonNullParamChecker::genReportReferenceToNullPointer(
306 BTNullRefArg.reset(
new BugType(
this,
"Dereference of null pointer"));
308 auto R = std::make_unique<PathSensitiveBugReport>(
309 *BTNullRefArg,
"Forming reference to null pointer", ErrorNode);
324bool 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
This represents one expression.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
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.
A (possibly-)qualified type.
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
RecordDecl * getDecl() const
const RecordType * getAsUnionType() const
NOTE: getAs*ArrayType are methods on ASTContext.
const T * getAs() const
Member-template getAs<specific type>'.
Represents an abstract call to a function or method along a particular path.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
ProgramStatePair assumeDual(ProgramStateRef State, DefinedSVal Cond)
Returns a pair of states (StTrue, StFalse) where the given condition is assumed to be true or false,...
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
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.
@ NonNull
Values of this type can never be null.
@ Parameter
The parameter type of a method or function.
We dereferenced a location that may be null.