[DFAJumpThreading] Remove incoming StartBlock from all phis when unfolding select...
[llvm-project.git] / clang / lib / StaticAnalyzer / Checkers / DereferenceChecker.cpp
bloba678c3827e7f12b37b49733014c20b9cea36b6c5
1 //===-- DereferenceChecker.cpp - Null dereference checker -----------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This defines NullDerefChecker, a builtin check in ExprEngine that performs
10 // checks for null pointers at loads and stores.
12 //===----------------------------------------------------------------------===//
14 #include "clang/AST/ExprObjC.h"
15 #include "clang/AST/ExprOpenMP.h"
16 #include "clang/Basic/TargetInfo.h"
17 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
18 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
19 #include "clang/StaticAnalyzer/Core/Checker.h"
20 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/Support/raw_ostream.h"
26 using namespace clang;
27 using namespace ento;
29 namespace {
30 class DereferenceChecker
31 : public Checker< check::Location,
32 check::Bind,
33 EventDispatcher<ImplicitNullDerefEvent> > {
34 enum DerefKind { NullPointer, UndefinedPointerValue };
36 BugType BT_Null{this, "Dereference of null pointer", categories::LogicError};
37 BugType BT_Undef{this, "Dereference of undefined pointer value",
38 categories::LogicError};
40 void reportBug(DerefKind K, ProgramStateRef State, const Stmt *S,
41 CheckerContext &C) const;
43 bool suppressReport(CheckerContext &C, const Expr *E) const;
45 public:
46 void checkLocation(SVal location, bool isLoad, const Stmt* S,
47 CheckerContext &C) const;
48 void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const;
50 static void AddDerefSource(raw_ostream &os,
51 SmallVectorImpl<SourceRange> &Ranges,
52 const Expr *Ex, const ProgramState *state,
53 const LocationContext *LCtx,
54 bool loadedFrom = false);
56 bool SuppressAddressSpaces = false;
58 } // end anonymous namespace
60 void
61 DereferenceChecker::AddDerefSource(raw_ostream &os,
62 SmallVectorImpl<SourceRange> &Ranges,
63 const Expr *Ex,
64 const ProgramState *state,
65 const LocationContext *LCtx,
66 bool loadedFrom) {
67 Ex = Ex->IgnoreParenLValueCasts();
68 switch (Ex->getStmtClass()) {
69 default:
70 break;
71 case Stmt::DeclRefExprClass: {
72 const DeclRefExpr *DR = cast<DeclRefExpr>(Ex);
73 if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
74 os << " (" << (loadedFrom ? "loaded from" : "from")
75 << " variable '" << VD->getName() << "')";
76 Ranges.push_back(DR->getSourceRange());
78 break;
80 case Stmt::MemberExprClass: {
81 const MemberExpr *ME = cast<MemberExpr>(Ex);
82 os << " (" << (loadedFrom ? "loaded from" : "via")
83 << " field '" << ME->getMemberNameInfo() << "')";
84 SourceLocation L = ME->getMemberLoc();
85 Ranges.push_back(SourceRange(L, L));
86 break;
88 case Stmt::ObjCIvarRefExprClass: {
89 const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(Ex);
90 os << " (" << (loadedFrom ? "loaded from" : "via")
91 << " ivar '" << IV->getDecl()->getName() << "')";
92 SourceLocation L = IV->getLocation();
93 Ranges.push_back(SourceRange(L, L));
94 break;
99 static const Expr *getDereferenceExpr(const Stmt *S, bool IsBind=false){
100 const Expr *E = nullptr;
102 // Walk through lvalue casts to get the original expression
103 // that syntactically caused the load.
104 if (const Expr *expr = dyn_cast<Expr>(S))
105 E = expr->IgnoreParenLValueCasts();
107 if (IsBind) {
108 const VarDecl *VD;
109 const Expr *Init;
110 std::tie(VD, Init) = parseAssignment(S);
111 if (VD && Init)
112 E = Init;
114 return E;
117 bool DereferenceChecker::suppressReport(CheckerContext &C,
118 const Expr *E) const {
119 // Do not report dereferences on memory that use address space #256, #257,
120 // and #258. Those address spaces are used when dereferencing address spaces
121 // relative to the GS, FS, and SS segments on x86/x86-64 targets.
122 // Dereferencing a null pointer in these address spaces is not defined
123 // as an error. All other null dereferences in other address spaces
124 // are defined as an error unless explicitly defined.
125 // See https://clang.llvm.org/docs/LanguageExtensions.html, the section
126 // "X86/X86-64 Language Extensions"
128 QualType Ty = E->getType();
129 if (!Ty.hasAddressSpace())
130 return false;
131 if (SuppressAddressSpaces)
132 return true;
134 const llvm::Triple::ArchType Arch =
135 C.getASTContext().getTargetInfo().getTriple().getArch();
137 if ((Arch == llvm::Triple::x86) || (Arch == llvm::Triple::x86_64)) {
138 switch (toTargetAddressSpace(E->getType().getAddressSpace())) {
139 case 256:
140 case 257:
141 case 258:
142 return true;
145 return false;
148 static bool isDeclRefExprToReference(const Expr *E) {
149 if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
150 return DRE->getDecl()->getType()->isReferenceType();
151 return false;
154 void DereferenceChecker::reportBug(DerefKind K, ProgramStateRef State,
155 const Stmt *S, CheckerContext &C) const {
156 const BugType *BT = nullptr;
157 llvm::StringRef DerefStr1;
158 llvm::StringRef DerefStr2;
159 switch (K) {
160 case DerefKind::NullPointer:
161 BT = &BT_Null;
162 DerefStr1 = " results in a null pointer dereference";
163 DerefStr2 = " results in a dereference of a null pointer";
164 break;
165 case DerefKind::UndefinedPointerValue:
166 BT = &BT_Undef;
167 DerefStr1 = " results in an undefined pointer dereference";
168 DerefStr2 = " results in a dereference of an undefined pointer value";
169 break;
172 // Generate an error node.
173 ExplodedNode *N = C.generateErrorNode(State);
174 if (!N)
175 return;
177 SmallString<100> buf;
178 llvm::raw_svector_ostream os(buf);
180 SmallVector<SourceRange, 2> Ranges;
182 switch (S->getStmtClass()) {
183 case Stmt::ArraySubscriptExprClass: {
184 os << "Array access";
185 const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
186 AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
187 State.get(), N->getLocationContext());
188 os << DerefStr1;
189 break;
191 case Stmt::OMPArraySectionExprClass: {
192 os << "Array access";
193 const OMPArraySectionExpr *AE = cast<OMPArraySectionExpr>(S);
194 AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(),
195 State.get(), N->getLocationContext());
196 os << DerefStr1;
197 break;
199 case Stmt::UnaryOperatorClass: {
200 os << BT->getDescription();
201 const UnaryOperator *U = cast<UnaryOperator>(S);
202 AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(),
203 State.get(), N->getLocationContext(), true);
204 break;
206 case Stmt::MemberExprClass: {
207 const MemberExpr *M = cast<MemberExpr>(S);
208 if (M->isArrow() || isDeclRefExprToReference(M->getBase())) {
209 os << "Access to field '" << M->getMemberNameInfo() << "'" << DerefStr2;
210 AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(),
211 State.get(), N->getLocationContext(), true);
213 break;
215 case Stmt::ObjCIvarRefExprClass: {
216 const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
217 os << "Access to instance variable '" << *IV->getDecl() << "'" << DerefStr2;
218 AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(),
219 State.get(), N->getLocationContext(), true);
220 break;
222 default:
223 break;
226 auto report = std::make_unique<PathSensitiveBugReport>(
227 *BT, buf.empty() ? BT->getDescription() : buf.str(), N);
229 bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report);
231 for (SmallVectorImpl<SourceRange>::iterator
232 I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
233 report->addRange(*I);
235 C.emitReport(std::move(report));
238 void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S,
239 CheckerContext &C) const {
240 // Check for dereference of an undefined value.
241 if (l.isUndef()) {
242 const Expr *DerefExpr = getDereferenceExpr(S);
243 if (!suppressReport(C, DerefExpr))
244 reportBug(DerefKind::UndefinedPointerValue, C.getState(), DerefExpr, C);
245 return;
248 DefinedOrUnknownSVal location = l.castAs<DefinedOrUnknownSVal>();
250 // Check for null dereferences.
251 if (!isa<Loc>(location))
252 return;
254 ProgramStateRef state = C.getState();
256 ProgramStateRef notNullState, nullState;
257 std::tie(notNullState, nullState) = state->assume(location);
259 if (nullState) {
260 if (!notNullState) {
261 // We know that 'location' can only be null. This is what
262 // we call an "explicit" null dereference.
263 const Expr *expr = getDereferenceExpr(S);
264 if (!suppressReport(C, expr)) {
265 reportBug(DerefKind::NullPointer, nullState, expr, C);
266 return;
270 // Otherwise, we have the case where the location could either be
271 // null or not-null. Record the error node as an "implicit" null
272 // dereference.
273 if (ExplodedNode *N = C.generateSink(nullState, C.getPredecessor())) {
274 ImplicitNullDerefEvent event = {l, isLoad, N, &C.getBugReporter(),
275 /*IsDirectDereference=*/true};
276 dispatchEvent(event);
280 // From this point forward, we know that the location is not null.
281 C.addTransition(notNullState);
284 void DereferenceChecker::checkBind(SVal L, SVal V, const Stmt *S,
285 CheckerContext &C) const {
286 // If we're binding to a reference, check if the value is known to be null.
287 if (V.isUndef())
288 return;
290 const MemRegion *MR = L.getAsRegion();
291 const TypedValueRegion *TVR = dyn_cast_or_null<TypedValueRegion>(MR);
292 if (!TVR)
293 return;
295 if (!TVR->getValueType()->isReferenceType())
296 return;
298 ProgramStateRef State = C.getState();
300 ProgramStateRef StNonNull, StNull;
301 std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
303 if (StNull) {
304 if (!StNonNull) {
305 const Expr *expr = getDereferenceExpr(S, /*IsBind=*/true);
306 if (!suppressReport(C, expr)) {
307 reportBug(DerefKind::NullPointer, StNull, expr, C);
308 return;
312 // At this point the value could be either null or non-null.
313 // Record this as an "implicit" null dereference.
314 if (ExplodedNode *N = C.generateSink(StNull, C.getPredecessor())) {
315 ImplicitNullDerefEvent event = {V, /*isLoad=*/true, N,
316 &C.getBugReporter(),
317 /*IsDirectDereference=*/true};
318 dispatchEvent(event);
322 // Unlike a regular null dereference, initializing a reference with a
323 // dereferenced null pointer does not actually cause a runtime exception in
324 // Clang's implementation of references.
326 // int &r = *p; // safe??
327 // if (p != NULL) return; // uh-oh
328 // r = 5; // trap here
330 // The standard says this is invalid as soon as we try to create a "null
331 // reference" (there is no such thing), but turning this into an assumption
332 // that 'p' is never null will not match our actual runtime behavior.
333 // So we do not record this assumption, allowing us to warn on the last line
334 // of this example.
336 // We do need to add a transition because we may have generated a sink for
337 // the "implicit" null dereference.
338 C.addTransition(State, this);
341 void ento::registerDereferenceChecker(CheckerManager &mgr) {
342 auto *Chk = mgr.registerChecker<DereferenceChecker>();
343 Chk->SuppressAddressSpaces = mgr.getAnalyzerOptions().getCheckerBooleanOption(
344 mgr.getCurrentCheckerName(), "SuppressAddressSpaces");
347 bool ento::shouldRegisterDereferenceChecker(const CheckerManager &mgr) {
348 return true;