1f4a2713aSLionel Sambuc //===--- NonNullParamChecker.cpp - Undefined arguments checker -*- C++ -*--===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc // The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // This defines NonNullParamChecker, which checks for arguments expected not to
11f4a2713aSLionel Sambuc // be null due to:
12f4a2713aSLionel Sambuc // - the corresponding parameters being declared to have nonnull attribute
13f4a2713aSLionel Sambuc // - the corresponding parameters being references; since the call would form
14f4a2713aSLionel Sambuc // a reference to a null pointer
15f4a2713aSLionel Sambuc //
16f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
17f4a2713aSLionel Sambuc
18f4a2713aSLionel Sambuc #include "ClangSACheckers.h"
19f4a2713aSLionel Sambuc #include "clang/AST/Attr.h"
20f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
21f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/Checker.h"
22f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/CheckerManager.h"
23f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
24f4a2713aSLionel Sambuc #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
25f4a2713aSLionel Sambuc
26f4a2713aSLionel Sambuc using namespace clang;
27f4a2713aSLionel Sambuc using namespace ento;
28f4a2713aSLionel Sambuc
29f4a2713aSLionel Sambuc namespace {
30f4a2713aSLionel Sambuc class NonNullParamChecker
31f4a2713aSLionel Sambuc : public Checker< check::PreCall > {
32*0a6a1f1dSLionel Sambuc mutable std::unique_ptr<BugType> BTAttrNonNull;
33*0a6a1f1dSLionel Sambuc mutable std::unique_ptr<BugType> BTNullRefArg;
34*0a6a1f1dSLionel Sambuc
35f4a2713aSLionel Sambuc public:
36f4a2713aSLionel Sambuc
37f4a2713aSLionel Sambuc void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
38f4a2713aSLionel Sambuc
39f4a2713aSLionel Sambuc BugReport *genReportNullAttrNonNull(const ExplodedNode *ErrorN,
40f4a2713aSLionel Sambuc const Expr *ArgE) const;
41f4a2713aSLionel Sambuc BugReport *genReportReferenceToNullPointer(const ExplodedNode *ErrorN,
42f4a2713aSLionel Sambuc const Expr *ArgE) const;
43f4a2713aSLionel Sambuc };
44f4a2713aSLionel Sambuc } // end anonymous namespace
45f4a2713aSLionel Sambuc
checkPreCall(const CallEvent & Call,CheckerContext & C) const46f4a2713aSLionel Sambuc void NonNullParamChecker::checkPreCall(const CallEvent &Call,
47f4a2713aSLionel Sambuc CheckerContext &C) const {
48f4a2713aSLionel Sambuc const Decl *FD = Call.getDecl();
49f4a2713aSLionel Sambuc if (!FD)
50f4a2713aSLionel Sambuc return;
51f4a2713aSLionel Sambuc
52*0a6a1f1dSLionel Sambuc // Merge all non-null attributes
53*0a6a1f1dSLionel Sambuc unsigned NumArgs = Call.getNumArgs();
54*0a6a1f1dSLionel Sambuc llvm::SmallBitVector AttrNonNull(NumArgs);
55*0a6a1f1dSLionel Sambuc for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
56*0a6a1f1dSLionel Sambuc if (!NonNull->args_size()) {
57*0a6a1f1dSLionel Sambuc AttrNonNull.set(0, NumArgs);
58*0a6a1f1dSLionel Sambuc break;
59*0a6a1f1dSLionel Sambuc }
60*0a6a1f1dSLionel Sambuc for (unsigned Val : NonNull->args()) {
61*0a6a1f1dSLionel Sambuc if (Val >= NumArgs)
62*0a6a1f1dSLionel Sambuc continue;
63*0a6a1f1dSLionel Sambuc AttrNonNull.set(Val);
64*0a6a1f1dSLionel Sambuc }
65*0a6a1f1dSLionel Sambuc }
66f4a2713aSLionel Sambuc
67f4a2713aSLionel Sambuc ProgramStateRef state = C.getState();
68f4a2713aSLionel Sambuc
69f4a2713aSLionel Sambuc CallEvent::param_type_iterator TyI = Call.param_type_begin(),
70f4a2713aSLionel Sambuc TyE = Call.param_type_end();
71f4a2713aSLionel Sambuc
72*0a6a1f1dSLionel Sambuc for (unsigned idx = 0; idx < NumArgs; ++idx) {
73f4a2713aSLionel Sambuc
74f4a2713aSLionel Sambuc // Check if the parameter is a reference. We want to report when reference
75f4a2713aSLionel Sambuc // to a null pointer is passed as a paramter.
76f4a2713aSLionel Sambuc bool haveRefTypeParam = false;
77f4a2713aSLionel Sambuc if (TyI != TyE) {
78f4a2713aSLionel Sambuc haveRefTypeParam = (*TyI)->isReferenceType();
79f4a2713aSLionel Sambuc TyI++;
80f4a2713aSLionel Sambuc }
81f4a2713aSLionel Sambuc
82*0a6a1f1dSLionel Sambuc bool haveAttrNonNull = AttrNonNull[idx];
83*0a6a1f1dSLionel Sambuc if (!haveAttrNonNull) {
84*0a6a1f1dSLionel Sambuc // Check if the parameter is also marked 'nonnull'.
85*0a6a1f1dSLionel Sambuc ArrayRef<ParmVarDecl*> parms = Call.parameters();
86*0a6a1f1dSLionel Sambuc if (idx < parms.size())
87*0a6a1f1dSLionel Sambuc haveAttrNonNull = parms[idx]->hasAttr<NonNullAttr>();
88*0a6a1f1dSLionel Sambuc }
89f4a2713aSLionel Sambuc
90f4a2713aSLionel Sambuc if (!haveRefTypeParam && !haveAttrNonNull)
91f4a2713aSLionel Sambuc continue;
92f4a2713aSLionel Sambuc
93f4a2713aSLionel Sambuc // If the value is unknown or undefined, we can't perform this check.
94f4a2713aSLionel Sambuc const Expr *ArgE = Call.getArgExpr(idx);
95f4a2713aSLionel Sambuc SVal V = Call.getArgSVal(idx);
96f4a2713aSLionel Sambuc Optional<DefinedSVal> DV = V.getAs<DefinedSVal>();
97f4a2713aSLionel Sambuc if (!DV)
98f4a2713aSLionel Sambuc continue;
99f4a2713aSLionel Sambuc
100f4a2713aSLionel Sambuc // Process the case when the argument is not a location.
101f4a2713aSLionel Sambuc assert(!haveRefTypeParam || DV->getAs<Loc>());
102f4a2713aSLionel Sambuc
103f4a2713aSLionel Sambuc if (haveAttrNonNull && !DV->getAs<Loc>()) {
104f4a2713aSLionel Sambuc // If the argument is a union type, we want to handle a potential
105f4a2713aSLionel Sambuc // transparent_union GCC extension.
106f4a2713aSLionel Sambuc if (!ArgE)
107f4a2713aSLionel Sambuc continue;
108f4a2713aSLionel Sambuc
109f4a2713aSLionel Sambuc QualType T = ArgE->getType();
110f4a2713aSLionel Sambuc const RecordType *UT = T->getAsUnionType();
111f4a2713aSLionel Sambuc if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
112f4a2713aSLionel Sambuc continue;
113f4a2713aSLionel Sambuc
114f4a2713aSLionel Sambuc if (Optional<nonloc::CompoundVal> CSV =
115f4a2713aSLionel Sambuc DV->getAs<nonloc::CompoundVal>()) {
116f4a2713aSLionel Sambuc nonloc::CompoundVal::iterator CSV_I = CSV->begin();
117f4a2713aSLionel Sambuc assert(CSV_I != CSV->end());
118f4a2713aSLionel Sambuc V = *CSV_I;
119f4a2713aSLionel Sambuc DV = V.getAs<DefinedSVal>();
120f4a2713aSLionel Sambuc assert(++CSV_I == CSV->end());
121*0a6a1f1dSLionel Sambuc // FIXME: Handle (some_union){ some_other_union_val }, which turns into
122*0a6a1f1dSLionel Sambuc // a LazyCompoundVal inside a CompoundVal.
123*0a6a1f1dSLionel Sambuc if (!V.getAs<Loc>())
124f4a2713aSLionel Sambuc continue;
125f4a2713aSLionel Sambuc // Retrieve the corresponding expression.
126f4a2713aSLionel Sambuc if (const CompoundLiteralExpr *CE = dyn_cast<CompoundLiteralExpr>(ArgE))
127f4a2713aSLionel Sambuc if (const InitListExpr *IE =
128f4a2713aSLionel Sambuc dyn_cast<InitListExpr>(CE->getInitializer()))
129f4a2713aSLionel Sambuc ArgE = dyn_cast<Expr>(*(IE->begin()));
130f4a2713aSLionel Sambuc
131f4a2713aSLionel Sambuc } else {
132f4a2713aSLionel Sambuc // FIXME: Handle LazyCompoundVals?
133f4a2713aSLionel Sambuc continue;
134f4a2713aSLionel Sambuc }
135f4a2713aSLionel Sambuc }
136f4a2713aSLionel Sambuc
137f4a2713aSLionel Sambuc ConstraintManager &CM = C.getConstraintManager();
138f4a2713aSLionel Sambuc ProgramStateRef stateNotNull, stateNull;
139*0a6a1f1dSLionel Sambuc std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
140f4a2713aSLionel Sambuc
141f4a2713aSLionel Sambuc if (stateNull && !stateNotNull) {
142f4a2713aSLionel Sambuc // Generate an error node. Check for a null node in case
143f4a2713aSLionel Sambuc // we cache out.
144f4a2713aSLionel Sambuc if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
145f4a2713aSLionel Sambuc
146*0a6a1f1dSLionel Sambuc BugReport *R = nullptr;
147f4a2713aSLionel Sambuc if (haveAttrNonNull)
148f4a2713aSLionel Sambuc R = genReportNullAttrNonNull(errorNode, ArgE);
149f4a2713aSLionel Sambuc else if (haveRefTypeParam)
150f4a2713aSLionel Sambuc R = genReportReferenceToNullPointer(errorNode, ArgE);
151f4a2713aSLionel Sambuc
152f4a2713aSLionel Sambuc // Highlight the range of the argument that was null.
153f4a2713aSLionel Sambuc R->addRange(Call.getArgSourceRange(idx));
154f4a2713aSLionel Sambuc
155f4a2713aSLionel Sambuc // Emit the bug report.
156f4a2713aSLionel Sambuc C.emitReport(R);
157f4a2713aSLionel Sambuc }
158f4a2713aSLionel Sambuc
159f4a2713aSLionel Sambuc // Always return. Either we cached out or we just emitted an error.
160f4a2713aSLionel Sambuc return;
161f4a2713aSLionel Sambuc }
162f4a2713aSLionel Sambuc
163f4a2713aSLionel Sambuc // If a pointer value passed the check we should assume that it is
164f4a2713aSLionel Sambuc // indeed not null from this point forward.
165f4a2713aSLionel Sambuc assert(stateNotNull);
166f4a2713aSLionel Sambuc state = stateNotNull;
167f4a2713aSLionel Sambuc }
168f4a2713aSLionel Sambuc
169f4a2713aSLionel Sambuc // If we reach here all of the arguments passed the nonnull check.
170f4a2713aSLionel Sambuc // If 'state' has been updated generated a new node.
171f4a2713aSLionel Sambuc C.addTransition(state);
172f4a2713aSLionel Sambuc }
173f4a2713aSLionel Sambuc
genReportNullAttrNonNull(const ExplodedNode * ErrorNode,const Expr * ArgE) const174f4a2713aSLionel Sambuc BugReport *NonNullParamChecker::genReportNullAttrNonNull(
175f4a2713aSLionel Sambuc const ExplodedNode *ErrorNode, const Expr *ArgE) const {
176f4a2713aSLionel Sambuc // Lazily allocate the BugType object if it hasn't already been
177f4a2713aSLionel Sambuc // created. Ownership is transferred to the BugReporter object once
178f4a2713aSLionel Sambuc // the BugReport is passed to 'EmitWarning'.
179f4a2713aSLionel Sambuc if (!BTAttrNonNull)
180f4a2713aSLionel Sambuc BTAttrNonNull.reset(new BugType(
181*0a6a1f1dSLionel Sambuc this, "Argument with 'nonnull' attribute passed null", "API"));
182f4a2713aSLionel Sambuc
183f4a2713aSLionel Sambuc BugReport *R = new BugReport(*BTAttrNonNull,
184f4a2713aSLionel Sambuc "Null pointer passed as an argument to a 'nonnull' parameter",
185f4a2713aSLionel Sambuc ErrorNode);
186f4a2713aSLionel Sambuc if (ArgE)
187f4a2713aSLionel Sambuc bugreporter::trackNullOrUndefValue(ErrorNode, ArgE, *R);
188f4a2713aSLionel Sambuc
189f4a2713aSLionel Sambuc return R;
190f4a2713aSLionel Sambuc }
191f4a2713aSLionel Sambuc
genReportReferenceToNullPointer(const ExplodedNode * ErrorNode,const Expr * ArgE) const192f4a2713aSLionel Sambuc BugReport *NonNullParamChecker::genReportReferenceToNullPointer(
193f4a2713aSLionel Sambuc const ExplodedNode *ErrorNode, const Expr *ArgE) const {
194f4a2713aSLionel Sambuc if (!BTNullRefArg)
195*0a6a1f1dSLionel Sambuc BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer"));
196f4a2713aSLionel Sambuc
197f4a2713aSLionel Sambuc BugReport *R = new BugReport(*BTNullRefArg,
198f4a2713aSLionel Sambuc "Forming reference to null pointer",
199f4a2713aSLionel Sambuc ErrorNode);
200f4a2713aSLionel Sambuc if (ArgE) {
201f4a2713aSLionel Sambuc const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
202*0a6a1f1dSLionel Sambuc if (!ArgEDeref)
203f4a2713aSLionel Sambuc ArgEDeref = ArgE;
204f4a2713aSLionel Sambuc bugreporter::trackNullOrUndefValue(ErrorNode,
205f4a2713aSLionel Sambuc ArgEDeref,
206f4a2713aSLionel Sambuc *R);
207f4a2713aSLionel Sambuc }
208f4a2713aSLionel Sambuc return R;
209f4a2713aSLionel Sambuc
210f4a2713aSLionel Sambuc }
211f4a2713aSLionel Sambuc
registerNonNullParamChecker(CheckerManager & mgr)212f4a2713aSLionel Sambuc void ento::registerNonNullParamChecker(CheckerManager &mgr) {
213f4a2713aSLionel Sambuc mgr.registerChecker<NonNullParamChecker>();
214f4a2713aSLionel Sambuc }
215