22 #include "llvm/ADT/SmallString.h" 23 #include "llvm/Support/raw_ostream.h" 25 using namespace clang;
29 class DereferenceChecker
30 :
public Checker< check::Location,
32 EventDispatcher<ImplicitNullDerefEvent> > {
33 mutable std::unique_ptr<BuiltinBug> BT_null;
34 mutable std::unique_ptr<BuiltinBug> BT_undef;
39 void checkLocation(SVal location,
bool isLoad,
const Stmt* S,
40 CheckerContext &C)
const;
41 void checkBind(SVal L, SVal
V,
const Stmt *S, CheckerContext &C)
const;
43 static void AddDerefSource(raw_ostream &os,
45 const Expr *Ex,
const ProgramState *
state,
47 bool loadedFrom =
false);
52 DereferenceChecker::AddDerefSource(raw_ostream &os,
55 const ProgramState *
state,
62 case Stmt::DeclRefExprClass: {
65 os <<
" (" << (loadedFrom ?
"loaded from" :
"from")
66 <<
" variable '" << VD->getName() <<
"')";
71 case Stmt::MemberExprClass: {
73 os <<
" (" << (loadedFrom ?
"loaded from" :
"via")
79 case Stmt::ObjCIvarRefExprClass: {
81 os <<
" (" << (loadedFrom ?
"loaded from" :
"via")
91 const Expr *E =
nullptr;
95 if (
const Expr *
expr = dyn_cast<Expr>(S))
96 E =
expr->IgnoreParenLValueCasts();
114 if (
const auto *DRE = dyn_cast<DeclRefExpr>(E))
115 return DRE->getDecl()->getType()->isReferenceType();
120 CheckerContext &C)
const {
122 ExplodedNode *N = C.generateErrorNode(State);
129 BT_null.reset(
new BuiltinBug(
this,
"Dereference of null pointer"));
132 llvm::raw_svector_ostream os(buf);
137 case Stmt::ArraySubscriptExprClass: {
138 os <<
"Array access";
141 State.get(), N->getLocationContext());
142 os <<
" results in a null pointer dereference";
145 case Stmt::OMPArraySectionExprClass: {
146 os <<
"Array access";
149 State.get(), N->getLocationContext());
150 os <<
" results in a null pointer dereference";
153 case Stmt::UnaryOperatorClass: {
154 os <<
"Dereference of null pointer";
157 State.get(), N->getLocationContext(),
true);
160 case Stmt::MemberExprClass: {
164 <<
"' results in a dereference of a null pointer";
166 State.get(), N->getLocationContext(),
true);
170 case Stmt::ObjCIvarRefExprClass: {
172 os <<
"Access to instance variable '" << *IV->
getDecl()
173 <<
"' results in a dereference of a null pointer";
175 State.get(), N->getLocationContext(),
true);
182 auto report = std::make_unique<PathSensitiveBugReport>(
183 *BT_null, buf.empty() ? BT_null->getDescription() : StringRef(buf), N);
185 bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report);
188 I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
189 report->addRange(*I);
191 C.emitReport(std::move(report));
194 void DereferenceChecker::checkLocation(SVal l,
bool isLoad,
const Stmt* S,
195 CheckerContext &C)
const {
198 if (ExplodedNode *N = C.generateErrorNode()) {
201 new BuiltinBug(
this,
"Dereference of undefined pointer value"));
203 auto report = std::make_unique<PathSensitiveBugReport>(
204 *BT_undef, BT_undef->getDescription(), N);
205 bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report);
206 C.emitReport(std::move(report));
211 DefinedOrUnknownSVal location = l.castAs<DefinedOrUnknownSVal>();
214 if (!location.getAs<Loc>())
220 std::tie(notNullState, nullState) = state->assume(location);
227 reportBug(nullState, expr, C);
235 if (ExplodedNode *N = C.generateSink(nullState, C.getPredecessor())) {
236 ImplicitNullDerefEvent
event = {l, isLoad, N, &C.getBugReporter(),
238 dispatchEvent(event);
243 C.addTransition(notNullState);
246 void DereferenceChecker::checkBind(SVal L, SVal
V,
const Stmt *S,
247 CheckerContext &C)
const {
252 const MemRegion *MR = L.getAsRegion();
253 const TypedValueRegion *TVR = dyn_cast_or_null<TypedValueRegion>(MR);
257 if (!TVR->getValueType()->isReferenceType())
263 std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
269 reportBug(StNull, expr, C);
276 if (ExplodedNode *N = C.generateSink(StNull, C.getPredecessor())) {
277 ImplicitNullDerefEvent
event = {
V,
true, N,
280 dispatchEvent(event);
300 C.addTransition(State,
this);
303 void ento::registerDereferenceChecker(CheckerManager &mgr) {
304 mgr.registerChecker<DereferenceChecker>();
307 bool ento::shouldRegisterDereferenceChecker(
const LangOptions &LO) {
Stmt - This represents one statement.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Represents a variable declaration or definition.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
static bool suppressReport(const Expr *E)
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
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
OpenMP 4.0 [2.4, Array Sections].
std::pair< const clang::VarDecl *, const clang::Expr * > parseAssignment(const Stmt *S)
static bool isDeclRefExprToReference(const Expr *E)
This represents one expression.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof), the postinc/postdec operators from postfix-expression, and various extensions.
SourceLocation getMemberLoc() const
getMemberLoc - Return the location of the "member", in X->F, it is the location of 'F'...
Encodes a location in the source.
Expr * getSubExpr() const
static const Expr * getDereferenceExpr(const Stmt *S, bool IsBind=false)
Dataflow Directional Tag Classes.
DeclarationNameInfo getMemberNameInfo() const
Retrieve the member declaration name info.
StmtClass getStmtClass() const
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
SourceLocation getLocation() const
Expr * IgnoreParenLValueCasts() LLVM_READONLY
Skip past any parentheses and lvalue casts which might surround this expression until reaching a fixe...
const Expr * getBase() const
bool hasAddressSpace() const
Check if this type has any address space qualifier.
ObjCIvarRefExpr - A reference to an ObjC instance variable.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
A reference to a declared variable, function, enum, etc.
A trivial tuple used to represent a source range.
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point...
Expr * getBase()
An array section can be written only as Base[LowerBound:Length].