26 using namespace clang;
30 class NonNullParamChecker
31 :
public Checker< check::PreCall, EventDispatcher<ImplicitNullDerefEvent> > {
32 mutable std::unique_ptr<BugType> BTAttrNonNull;
33 mutable std::unique_ptr<BugType> BTNullRefArg;
37 void checkPreCall(
const CallEvent &Call, CheckerContext &C)
const;
39 std::unique_ptr<BugReport>
40 genReportNullAttrNonNull(
const ExplodedNode *ErrorN,
const Expr *ArgE)
const;
41 std::unique_ptr<BugReport>
42 genReportReferenceToNullPointer(
const ExplodedNode *ErrorN,
43 const Expr *ArgE)
const;
49 const Decl *FD = Call.getDecl();
50 unsigned NumArgs = Call.getNumArgs();
51 llvm::SmallBitVector AttrNonNull(NumArgs);
54 AttrNonNull.set(0, NumArgs);
58 unsigned IdxAST = Idx.getASTIndex();
59 if (IdxAST >= NumArgs)
61 AttrNonNull.set(IdxAST);
67 void NonNullParamChecker::checkPreCall(
const CallEvent &Call,
68 CheckerContext &C)
const {
73 unsigned NumArgs = Call.getNumArgs();
78 for (
unsigned idx = 0; idx < NumArgs; ++idx) {
80 bool HasParam = idx < parms.size();
84 bool haveRefTypeParam =
85 HasParam ? parms[idx]->getType()->isReferenceType() :
false;
86 bool haveAttrNonNull = AttrNonNull[idx];
89 if (!haveAttrNonNull && HasParam)
90 haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>();
92 if (!haveAttrNonNull && !haveRefTypeParam)
96 const Expr *ArgE = Call.getArgExpr(idx);
97 SVal V = Call.getArgSVal(idx);
98 auto DV = V.getAs<DefinedSVal>();
102 assert(!haveRefTypeParam || DV->getAs<Loc>());
105 if (haveAttrNonNull && !DV->getAs<Loc>()) {
116 auto CSV = DV->
getAs<nonloc::CompoundVal>();
123 DV = V.getAs<DefinedSVal>();
124 assert(++CSV->begin() == CSV->end());
131 if (
const auto *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
132 if (
const auto *IE = dyn_cast<InitListExpr>(CE->getInitializer()))
133 ArgE = dyn_cast<
Expr>(*(IE->begin()));
136 ConstraintManager &CM = C.getConstraintManager();
138 std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
142 if (stateNull && !stateNotNull) {
143 if (ExplodedNode *errorNode = C.generateErrorNode(stateNull)) {
145 std::unique_ptr<BugReport> R;
147 R = genReportNullAttrNonNull(errorNode, ArgE);
148 else if (haveRefTypeParam)
149 R = genReportReferenceToNullPointer(errorNode, ArgE);
152 R->addRange(Call.getArgSourceRange(idx));
155 C.emitReport(std::move(R));
163 if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) {
164 ImplicitNullDerefEvent
event = {
165 V,
false, N, &C.getBugReporter(),
167 dispatchEvent(event);
173 state = stateNotNull;
178 C.addTransition(state);
181 std::unique_ptr<BugReport>
182 NonNullParamChecker::genReportNullAttrNonNull(
const ExplodedNode *ErrorNode,
183 const Expr *ArgE)
const {
188 BTAttrNonNull.reset(
new BugType(
189 this,
"Argument with 'nonnull' attribute passed null",
"API"));
191 auto R = llvm::make_unique<BugReport>(
193 "Null pointer passed as an argument to a 'nonnull' parameter", ErrorNode);
195 bugreporter::trackExpressionValue(ErrorNode, ArgE, *R);
200 std::unique_ptr<BugReport> NonNullParamChecker::genReportReferenceToNullPointer(
201 const ExplodedNode *ErrorNode,
const Expr *ArgE)
const {
203 BTNullRefArg.reset(
new BuiltinBug(
this,
"Dereference of null pointer"));
205 auto R = llvm::make_unique<BugReport>(
206 *BTNullRefArg,
"Forming reference to null pointer", ErrorNode);
208 const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
211 bugreporter::trackExpressionValue(ErrorNode, ArgEDeref, *R);
217 void ento::registerNonNullParamChecker(CheckerManager &mgr) {
218 mgr.registerChecker<NonNullParamChecker>();
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>'.
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...
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const