30class NonNullParamChecker
31 :
public Checker<check::PreCall, check::BeginFunction,
32 EventDispatcher<ImplicitNullDerefEvent>> {
33 const BugType BTAttrNonNull{
34 this,
"Argument with 'nonnull' attribute passed null",
"API"};
35 const BugType BTNullRefArg{
this,
"Dereference of null pointer"};
38 void checkPreCall(
const CallEvent &
Call, CheckerContext &
C)
const;
39 void checkBeginFunction(CheckerContext &
C)
const;
41 std::unique_ptr<PathSensitiveBugReport>
42 genReportNullAttrNonNull(
const ExplodedNode *ErrorN,
const Expr *ArgE,
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) {
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();
117 ArrayRef<ParmVarDecl *> parms =
Call.parameters();
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);
134 SVal
V =
Call.getArgSVal(idx);
135 auto DV =
V.getAs<DefinedSVal>();
139 assert(!HasRefTypeParam ||
isa<Loc>(*DV));
142 if (ExpectedToBeNonNull && !
isa<Loc>(*DV)) {
151 !UT->getDecl()->getMostRecentDecl()->hasAttr<TransparentUnionAttr>())
154 auto CSV = DV->getAs<nonloc::CompoundVal>();
161 DV =
V.getAs<DefinedSVal>();
162 assert(++CSV->begin() == CSV->end());
169 if (
const auto *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
170 if (
const auto *IE = dyn_cast<InitListExpr>(CE->getInitializer()))
171 ArgE = dyn_cast<Expr>(*(IE->begin()));
174 ConstraintManager &CM =
C.getConstraintManager();
176 std::tie(stateNotNull, stateNull) = CM.
assumeDual(state, *DV);
180 if (stateNull && !stateNotNull) {
181 if (ExplodedNode *errorNode =
C.generateErrorNode(stateNull)) {
183 std::unique_ptr<BugReport>
R;
184 if (ExpectedToBeNonNull)
185 R = genReportNullAttrNonNull(errorNode, ArgE, idx + 1);
186 else if (HasRefTypeParam)
187 R = genReportReferenceToNullPointer(errorNode, ArgE);
190 R->addRange(
Call.getArgSourceRange(idx));
193 C.emitReport(std::move(R));
201 if (ExplodedNode *N =
C.generateSink(stateNull,
C.getPredecessor())) {
202 ImplicitNullDerefEvent
event = {
203 V,
false, N, &
C.getBugReporter(),
205 dispatchEvent(event);
211 state = stateNotNull;
216 C.addTransition(state);
235void NonNullParamChecker::checkBeginFunction(CheckerContext &Context)
const {
238 if (!Context.inTopFrame())
241 const StackFrame *SF = Context.getStackFrame();
251 llvm::SmallBitVector ParameterNonNullMarks = getNonNullAttrs(*AbstractCall);
253 for (
const ParmVarDecl *
Parameter : AbstractCall->parameters()) {
255 if (!ParameterNonNullMarks.test(
Parameter->getFunctionScopeIndex()))
261 if (!
Parameter->getType()->isPointerType())
264 Loc ParameterLoc = State->getLValue(
Parameter, SF);
267 State->getSVal(ParameterLoc).castAs<DefinedOrUnknownSVal>();
275 Context.addTransition(State);
278std::unique_ptr<PathSensitiveBugReport>
279NonNullParamChecker::genReportNullAttrNonNull(
const ExplodedNode *ErrorNode,
281 unsigned IdxOfArg)
const {
282 auto R = std::make_unique<PathSensitiveBugReport>(
284 "Null pointer passed to " + Twine(IdxOfArg) +
285 llvm::getOrdinalSuffix(IdxOfArg) +
" parameter expecting 'nonnull'",
293std::unique_ptr<PathSensitiveBugReport>
294NonNullParamChecker::genReportReferenceToNullPointer(
295 const ExplodedNode *ErrorNode,
const Expr *ArgE)
const {
296 auto R = std::make_unique<PathSensitiveBugReport>(
297 BTNullRefArg,
"Forming reference to null pointer", ErrorNode);
307void ento::registerNonNullParamChecker(CheckerManager &mgr) {
311bool 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
A single parameter index whose accessors require each use to make explicit the parameter index encodi...
Represents a parameter to a function.
const Decl * getDecl() const
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
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.