23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/Support/raw_ostream.h"
26 using namespace clang;
30 class DereferenceChecker
31 :
public Checker< check::Location,
33 EventDispatcher<ImplicitNullDerefEvent> > {
34 enum DerefKind { NullPointer, UndefinedPointerValue };
37 BugType BT_Undef{
this,
"Dereference of undefined pointer value",
41 CheckerContext &C)
const;
43 bool suppressReport(CheckerContext &C,
const Expr *E)
const;
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,
54 bool loadedFrom =
false);
56 bool SuppressAddressSpaces =
false;
61 DereferenceChecker::AddDerefSource(raw_ostream &os,
71 case Stmt::DeclRefExprClass: {
74 os <<
" (" << (loadedFrom ?
"loaded from" :
"from")
75 <<
" variable '" << VD->getName() <<
"')";
80 case Stmt::MemberExprClass: {
82 os <<
" (" << (loadedFrom ?
"loaded from" :
"via")
88 case Stmt::ObjCIvarRefExprClass: {
90 os <<
" (" << (loadedFrom ?
"loaded from" :
"via")
100 const Expr *E =
nullptr;
104 if (
const Expr *
expr = dyn_cast<Expr>(S))
105 E =
expr->IgnoreParenLValueCasts();
117 bool DereferenceChecker::suppressReport(CheckerContext &C,
118 const Expr *E)
const {
131 if (SuppressAddressSpaces)
134 const llvm::Triple::ArchType Arch =
135 C.getASTContext().getTargetInfo().getTriple().getArch();
137 if ((Arch == llvm::Triple::x86) || (Arch == llvm::Triple::x86_64)) {
149 if (
const auto *DRE = dyn_cast<DeclRefExpr>(E))
150 return DRE->getDecl()->getType()->isReferenceType();
155 const Stmt *S, CheckerContext &C)
const {
156 const BugType *BT =
nullptr;
157 llvm::StringRef DerefStr1;
158 llvm::StringRef DerefStr2;
160 case DerefKind::NullPointer:
162 DerefStr1 =
" results in a null pointer dereference";
163 DerefStr2 =
" results in a dereference of a null pointer";
165 case DerefKind::UndefinedPointerValue:
167 DerefStr1 =
" results in an undefined pointer dereference";
168 DerefStr2 =
" results in a dereference of an undefined pointer value";
173 ExplodedNode *N =
C.generateErrorNode(
State);
178 llvm::raw_svector_ostream os(buf);
182 switch (S->getStmtClass()) {
183 case Stmt::ArraySubscriptExprClass: {
184 os <<
"Array access";
187 State.get(), N->getLocationContext());
191 case Stmt::OMPArraySectionExprClass: {
192 os <<
"Array access";
195 State.get(), N->getLocationContext());
199 case Stmt::UnaryOperatorClass: {
200 os << BT->getDescription();
202 AddDerefSource(os, Ranges,
U->getSubExpr()->IgnoreParens(),
203 State.get(), N->getLocationContext(),
true);
206 case Stmt::MemberExprClass: {
211 State.get(), N->getLocationContext(),
true);
215 case Stmt::ObjCIvarRefExprClass: {
217 os <<
"Access to instance variable '" << *IV->
getDecl() <<
"'" << DerefStr2;
219 State.get(), N->getLocationContext(),
true);
226 auto report = std::make_unique<PathSensitiveBugReport>(
227 *BT, buf.empty() ? BT->getDescription() : buf.str(), N);
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 {
243 if (!suppressReport(C, DerefExpr))
244 reportBug(DerefKind::UndefinedPointerValue,
C.getState(), DerefExpr, C);
248 DefinedOrUnknownSVal location = l.castAs<DefinedOrUnknownSVal>();
251 if (!location.getAs<Loc>())
257 std::tie(notNullState, nullState) =
state->assume(location);
264 if (!suppressReport(C,
expr)) {
265 reportBug(DerefKind::NullPointer, nullState,
expr, C);
273 if (ExplodedNode *N =
C.generateSink(nullState,
C.getPredecessor())) {
274 ImplicitNullDerefEvent
event = {l, isLoad, N, &
C.getBugReporter(),
276 dispatchEvent(event);
281 C.addTransition(notNullState);
284 void DereferenceChecker::checkBind(SVal L, SVal
V,
const Stmt *S,
285 CheckerContext &C)
const {
290 const MemRegion *MR = L.getAsRegion();
291 const TypedValueRegion *TVR = dyn_cast_or_null<TypedValueRegion>(MR);
295 if (!TVR->getValueType()->isReferenceType())
301 std::tie(StNonNull, StNull) =
State->assume(
V.castAs<DefinedOrUnknownSVal>());
306 if (!suppressReport(C,
expr)) {
307 reportBug(DerefKind::NullPointer, StNull,
expr, C);
314 if (ExplodedNode *N =
C.generateSink(StNull,
C.getPredecessor())) {
315 ImplicitNullDerefEvent
event = {
V,
true, N,
318 dispatchEvent(event);
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) {