25 using namespace clang;
29 class NonNullParamChecker
30 :
public Checker< check::PreCall, EventDispatcher<ImplicitNullDerefEvent> > {
31 mutable std::unique_ptr<BugType> BTAttrNonNull;
32 mutable std::unique_ptr<BugType> BTNullRefArg;
36 void checkPreCall(
const CallEvent &Call, CheckerContext &C)
const;
38 std::unique_ptr<PathSensitiveBugReport>
39 genReportNullAttrNonNull(
const ExplodedNode *ErrorN,
41 unsigned IdxOfArg)
const;
42 std::unique_ptr<PathSensitiveBugReport>
43 genReportReferenceToNullPointer(
const ExplodedNode *ErrorN,
44 const Expr *ArgE)
const;
50 const Decl *FD = Call.getDecl();
51 unsigned NumArgs = Call.getNumArgs();
52 llvm::SmallBitVector AttrNonNull(NumArgs);
55 AttrNonNull.set(0, NumArgs);
59 unsigned IdxAST = Idx.getASTIndex();
60 if (IdxAST >= NumArgs)
62 AttrNonNull.set(IdxAST);
68 void NonNullParamChecker::checkPreCall(
const CallEvent &Call,
69 CheckerContext &C)
const {
74 unsigned NumArgs = Call.getNumArgs();
79 for (
unsigned idx = 0; idx < NumArgs; ++idx) {
81 bool HasParam = idx < parms.size();
85 bool haveRefTypeParam =
86 HasParam ? parms[idx]->getType()->isReferenceType() :
false;
87 bool haveAttrNonNull = AttrNonNull[idx];
90 if (!haveAttrNonNull && HasParam)
91 haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>();
93 if (!haveAttrNonNull && !haveRefTypeParam)
97 const Expr *ArgE = Call.getArgExpr(idx);
98 SVal
V = Call.getArgSVal(idx);
99 auto DV = V.getAs<DefinedSVal>();
103 assert(!haveRefTypeParam || DV->getAs<Loc>());
106 if (haveAttrNonNull && !DV->getAs<Loc>()) {
117 auto CSV = DV->
getAs<nonloc::CompoundVal>();
124 DV = V.getAs<DefinedSVal>();
125 assert(++CSV->begin() == CSV->end());
132 if (
const auto *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
133 if (
const auto *IE = dyn_cast<InitListExpr>(CE->getInitializer()))
134 ArgE = dyn_cast<
Expr>(*(IE->begin()));
137 ConstraintManager &CM = C.getConstraintManager();
139 std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
143 if (stateNull && !stateNotNull) {
144 if (ExplodedNode *errorNode = C.generateErrorNode(stateNull)) {
146 std::unique_ptr<BugReport> R;
148 R = genReportNullAttrNonNull(errorNode, ArgE, idx + 1);
149 else if (haveRefTypeParam)
150 R = genReportReferenceToNullPointer(errorNode, ArgE);
153 R->addRange(Call.getArgSourceRange(idx));
156 C.emitReport(std::move(R));
164 if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) {
165 ImplicitNullDerefEvent
event = {
166 V,
false, N, &C.getBugReporter(),
168 dispatchEvent(event);
174 state = stateNotNull;
179 C.addTransition(state);
182 std::unique_ptr<PathSensitiveBugReport>
183 NonNullParamChecker::genReportNullAttrNonNull(
const ExplodedNode *ErrorNode,
185 unsigned IdxOfArg)
const {
190 BTAttrNonNull.reset(
new BugType(
191 this,
"Argument with 'nonnull' attribute passed null",
"API"));
194 llvm::raw_svector_ostream
OS(SBuf);
195 OS <<
"Null pointer passed to " 196 << IdxOfArg << llvm::getOrdinalSuffix(IdxOfArg)
197 <<
" parameter expecting 'nonnull'";
200 std::make_unique<PathSensitiveBugReport>(*BTAttrNonNull, SBuf, ErrorNode);
202 bugreporter::trackExpressionValue(ErrorNode, ArgE, *R);
207 std::unique_ptr<PathSensitiveBugReport>
208 NonNullParamChecker::genReportReferenceToNullPointer(
209 const ExplodedNode *ErrorNode,
const Expr *ArgE)
const {
211 BTNullRefArg.reset(
new BuiltinBug(
this,
"Dereference of null pointer"));
213 auto R = std::make_unique<PathSensitiveBugReport>(
214 *BTNullRefArg,
"Forming reference to null pointer", ErrorNode);
216 const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
219 bugreporter::trackExpressionValue(ErrorNode, ArgEDeref, *R);
225 void ento::registerNonNullParamChecker(CheckerManager &mgr) {
226 mgr.registerChecker<NonNullParamChecker>();
229 bool ento::shouldRegisterNonNullParamChecker(
const LangOptions &LO) {
A (possibly-)qualified type.
Decl - This represents one declaration (or definition), e.g.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const RecordType * getAsUnionType() const
NOTE: getAs*ArrayType are methods on ASTContext.
const T * getAs() const
Member-template getAs<specific type>'.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
Values of this type can never be null.
A single parameter index whose accessors require each use to make explicit the parameter index encodi...
This represents one expression.
static llvm::SmallBitVector getNonNullAttrs(const CallEvent &Call)
RecordDecl * getDecl() const
Dataflow Directional Tag Classes.
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const