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<BugReport>
39 genReportNullAttrNonNull(
const ExplodedNode *ErrorN,
const Expr *ArgE)
const;
40 std::unique_ptr<BugReport>
41 genReportReferenceToNullPointer(
const ExplodedNode *ErrorN,
42 const Expr *ArgE)
const;
48 const Decl *FD = Call.getDecl();
49 unsigned NumArgs = Call.getNumArgs();
50 llvm::SmallBitVector AttrNonNull(NumArgs);
53 AttrNonNull.set(0, NumArgs);
57 unsigned IdxAST = Idx.getASTIndex();
58 if (IdxAST >= NumArgs)
60 AttrNonNull.set(IdxAST);
66 void NonNullParamChecker::checkPreCall(
const CallEvent &Call,
67 CheckerContext &C)
const {
72 unsigned NumArgs = Call.getNumArgs();
77 for (
unsigned idx = 0; idx < NumArgs; ++idx) {
79 bool HasParam = idx < parms.size();
83 bool haveRefTypeParam =
84 HasParam ? parms[idx]->getType()->isReferenceType() :
false;
85 bool haveAttrNonNull = AttrNonNull[idx];
88 if (!haveAttrNonNull && HasParam)
89 haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>();
91 if (!haveAttrNonNull && !haveRefTypeParam)
95 const Expr *ArgE = Call.getArgExpr(idx);
96 SVal
V = Call.getArgSVal(idx);
97 auto DV = V.getAs<DefinedSVal>();
101 assert(!haveRefTypeParam || DV->getAs<Loc>());
104 if (haveAttrNonNull && !DV->getAs<Loc>()) {
115 auto CSV = DV->
getAs<nonloc::CompoundVal>();
122 DV = V.getAs<DefinedSVal>();
123 assert(++CSV->begin() == CSV->end());
130 if (
const auto *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
131 if (
const auto *IE = dyn_cast<InitListExpr>(CE->getInitializer()))
132 ArgE = dyn_cast<
Expr>(*(IE->begin()));
135 ConstraintManager &CM = C.getConstraintManager();
137 std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
141 if (stateNull && !stateNotNull) {
142 if (ExplodedNode *errorNode = C.generateErrorNode(stateNull)) {
144 std::unique_ptr<BugReport> R;
146 R = genReportNullAttrNonNull(errorNode, ArgE);
147 else if (haveRefTypeParam)
148 R = genReportReferenceToNullPointer(errorNode, ArgE);
151 R->addRange(Call.getArgSourceRange(idx));
154 C.emitReport(std::move(R));
162 if (ExplodedNode *N = C.generateSink(stateNull, C.getPredecessor())) {
163 ImplicitNullDerefEvent
event = {
164 V,
false, N, &C.getBugReporter(),
166 dispatchEvent(event);
172 state = stateNotNull;
177 C.addTransition(state);
180 std::unique_ptr<BugReport>
181 NonNullParamChecker::genReportNullAttrNonNull(
const ExplodedNode *ErrorNode,
182 const Expr *ArgE)
const {
187 BTAttrNonNull.reset(
new BugType(
188 this,
"Argument with 'nonnull' attribute passed null",
"API"));
190 auto R = llvm::make_unique<BugReport>(
192 "Null pointer passed as an argument to a 'nonnull' parameter", ErrorNode);
194 bugreporter::trackExpressionValue(ErrorNode, ArgE, *R);
199 std::unique_ptr<BugReport> NonNullParamChecker::genReportReferenceToNullPointer(
200 const ExplodedNode *ErrorNode,
const Expr *ArgE)
const {
202 BTNullRefArg.reset(
new BuiltinBug(
this,
"Dereference of null pointer"));
204 auto R = llvm::make_unique<BugReport>(
205 *BTNullRefArg,
"Forming reference to null pointer", ErrorNode);
207 const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
210 bugreporter::trackExpressionValue(ErrorNode, ArgEDeref, *R);
216 void ento::registerNonNullParamChecker(CheckerManager &mgr) {
217 mgr.registerChecker<NonNullParamChecker>();
220 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...
llvm::iterator_range< specific_attr_iterator< T > > specific_attrs() const