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)) {
151 if (!UT || !UT->getOriginalDecl()
152 ->getMostRecentDecl()
153 ->hasAttr<TransparentUnionAttr>())
156 auto CSV = DV->getAs<nonloc::CompoundVal>();
163 DV =
V.getAs<DefinedSVal>();
164 assert(++CSV->begin() == CSV->end());
171 if (
const auto *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
172 if (
const auto *IE = dyn_cast<InitListExpr>(CE->getInitializer()))
173 ArgE = dyn_cast<Expr>(*(IE->begin()));
176 ConstraintManager &CM =
C.getConstraintManager();
178 std::tie(stateNotNull, stateNull) = CM.
assumeDual(state, *DV);
182 if (stateNull && !stateNotNull) {
183 if (ExplodedNode *errorNode =
C.generateErrorNode(stateNull)) {
185 std::unique_ptr<BugReport> R;
186 if (ExpectedToBeNonNull)
187 R = genReportNullAttrNonNull(errorNode, ArgE, idx + 1);
188 else if (HasRefTypeParam)
189 R = genReportReferenceToNullPointer(errorNode, ArgE);
192 R->addRange(
Call.getArgSourceRange(idx));
195 C.emitReport(std::move(R));
203 if (ExplodedNode *N =
C.generateSink(stateNull,
C.getPredecessor())) {
204 ImplicitNullDerefEvent
event = {
205 V,
false, N, &
C.getBugReporter(),
207 dispatchEvent(event);
213 state = stateNotNull;
218 C.addTransition(state);
237void NonNullParamChecker::checkBeginFunction(CheckerContext &Context)
const {
240 if (!Context.inTopFrame())
243 const LocationContext *LocContext = Context.getLocationContext();
253 llvm::SmallBitVector ParameterNonNullMarks = getNonNullAttrs(*AbstractCall);
255 for (
const ParmVarDecl *
Parameter : AbstractCall->parameters()) {
257 if (!ParameterNonNullMarks.test(
Parameter->getFunctionScopeIndex()))
263 if (!
Parameter->getType()->isPointerType())
266 Loc ParameterLoc = State->getLValue(
Parameter, LocContext);
269 State->getSVal(ParameterLoc).castAs<DefinedOrUnknownSVal>();
277 Context.addTransition(State);
280std::unique_ptr<PathSensitiveBugReport>
281NonNullParamChecker::genReportNullAttrNonNull(
const ExplodedNode *ErrorNode,
283 unsigned IdxOfArg)
const {
284 llvm::SmallString<256> SBuf;
285 llvm::raw_svector_ostream
OS(SBuf);
286 OS <<
"Null pointer passed to "
287 << IdxOfArg << llvm::getOrdinalSuffix(IdxOfArg)
288 <<
" parameter expecting 'nonnull'";
291 std::make_unique<PathSensitiveBugReport>(BTAttrNonNull, SBuf, ErrorNode);
298std::unique_ptr<PathSensitiveBugReport>
299NonNullParamChecker::genReportReferenceToNullPointer(
300 const ExplodedNode *ErrorNode,
const Expr *ArgE)
const {
301 auto R = std::make_unique<PathSensitiveBugReport>(
302 BTNullRefArg,
"Forming reference to null pointer", ErrorNode);
312void ento::registerNonNullParamChecker(CheckerManager &mgr) {
316bool 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