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 mutable std::unique_ptr<BuiltinBug> BT_null;
35 mutable std::unique_ptr<BuiltinBug> BT_undef;
40 void checkLocation(SVal location,
bool isLoad,
const Stmt* S,
41 CheckerContext &C)
const;
42 void checkBind(SVal L, SVal V,
const Stmt *S, CheckerContext &C)
const;
44 static void AddDerefSource(raw_ostream &os,
46 const Expr *Ex,
const ProgramState *
state,
48 bool loadedFrom =
false);
53 DereferenceChecker::AddDerefSource(raw_ostream &os,
56 const ProgramState *
state,
63 case Stmt::DeclRefExprClass: {
66 os <<
" (" << (loadedFrom ?
"loaded from" :
"from")
67 <<
" variable '" << VD->getName() <<
"')";
72 case Stmt::MemberExprClass: {
74 os <<
" (" << (loadedFrom ?
"loaded from" :
"via")
80 case Stmt::ObjCIvarRefExprClass: {
82 os <<
" (" << (loadedFrom ?
"loaded from" :
"via")
92 const Expr *E =
nullptr;
96 if (
const Expr *
expr = dyn_cast<Expr>(S))
97 E =
expr->IgnoreParenLValueCasts();
115 if (
const auto *DRE = dyn_cast<DeclRefExpr>(E))
116 return DRE->getDecl()->getType()->isReferenceType();
121 CheckerContext &C)
const {
123 ExplodedNode *N = C.generateErrorNode(State);
130 BT_null.reset(
new BuiltinBug(
this,
"Dereference of null pointer"));
133 llvm::raw_svector_ostream os(buf);
138 case Stmt::ArraySubscriptExprClass: {
139 os <<
"Array access";
142 State.get(), N->getLocationContext());
143 os <<
" results in a null pointer dereference";
146 case Stmt::OMPArraySectionExprClass: {
147 os <<
"Array access";
150 State.get(), N->getLocationContext());
151 os <<
" results in a null pointer dereference";
154 case Stmt::UnaryOperatorClass: {
155 os <<
"Dereference of null pointer";
158 State.get(), N->getLocationContext(),
true);
161 case Stmt::MemberExprClass: {
165 <<
"' results in a dereference of a null pointer";
167 State.get(), N->getLocationContext(),
true);
171 case Stmt::ObjCIvarRefExprClass: {
173 os <<
"Access to instance variable '" << *IV->
getDecl()
174 <<
"' results in a dereference of a null pointer";
176 State.get(), N->getLocationContext(),
true);
183 auto report = llvm::make_unique<BugReport>(
184 *BT_null, buf.empty() ? BT_null->getDescription() : StringRef(buf), N);
186 bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report);
189 I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
190 report->addRange(*I);
192 C.emitReport(std::move(report));
195 void DereferenceChecker::checkLocation(SVal l,
bool isLoad,
const Stmt* S,
196 CheckerContext &C)
const {
199 if (ExplodedNode *N = C.generateErrorNode()) {
202 new BuiltinBug(
this,
"Dereference of undefined pointer value"));
205 llvm::make_unique<BugReport>(*BT_undef, BT_undef->getDescription(), N);
206 bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report);
207 C.emitReport(std::move(report));
212 DefinedOrUnknownSVal location = l.castAs<DefinedOrUnknownSVal>();
215 if (!location.getAs<Loc>())
221 std::tie(notNullState, nullState) = state->assume(location);
228 reportBug(nullState, expr, C);
236 if (ExplodedNode *N = C.generateSink(nullState, C.getPredecessor())) {
237 ImplicitNullDerefEvent
event = {l, isLoad, N, &C.getBugReporter(),
239 dispatchEvent(event);
244 C.addTransition(notNullState);
247 void DereferenceChecker::checkBind(SVal L, SVal V,
const Stmt *S,
248 CheckerContext &C)
const {
253 const MemRegion *MR = L.getAsRegion();
254 const TypedValueRegion *TVR = dyn_cast_or_null<TypedValueRegion>(MR);
258 if (!TVR->getValueType()->isReferenceType())
264 std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
270 reportBug(StNull, expr, C);
277 if (ExplodedNode *N = C.generateSink(StNull, C.getPredecessor())) {
278 ImplicitNullDerefEvent
event = {V,
true, N,
281 dispatchEvent(event);
301 C.addTransition(State,
this);
304 void ento::registerDereferenceChecker(CheckerManager &mgr) {
305 mgr.registerChecker<DereferenceChecker>();
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)
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
bool hasAddressSpace() const
Expr * IgnoreParenCasts() LLVM_READONLY
IgnoreParenCasts - Ignore parentheses and casts.
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
Ignore parentheses and lvalue casts.
const Expr * getBase() const
ObjCIvarRefExpr - A reference to an ObjC instance variable.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
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
IgnoreParens - Ignore parentheses.
Expr * getBase()
An array section can be written only as Base[LowerBound:Length].