1d99bd55aSTed Kremenek //=== PointerArithChecker.cpp - Pointer arithmetic checker -----*- C++ -*--===//
2d99bd55aSTed Kremenek //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d99bd55aSTed Kremenek //
7d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
8d99bd55aSTed Kremenek //
9d99bd55aSTed Kremenek // This files defines PointerArithChecker, a builtin checker that checks for
10d99bd55aSTed Kremenek // pointer arithmetic on locations other than array elements.
11d99bd55aSTed Kremenek //
12d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
13d99bd55aSTed Kremenek
1476a21502SKristof Umann #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15d1abcf79SGabor Horvath #include "clang/AST/DeclCXX.h"
16d1abcf79SGabor Horvath #include "clang/AST/ExprCXX.h"
173a02247dSChandler Carruth #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
186a5674ffSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/Checker.h"
19507ff53eSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/CheckerManager.h"
20dff865d1SArgyrios Kyrtzidis #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
21d99bd55aSTed Kremenek
22d99bd55aSTed Kremenek using namespace clang;
23d99bd55aSTed Kremenek using namespace ento;
24d99bd55aSTed Kremenek
25d99bd55aSTed Kremenek namespace {
26d1abcf79SGabor Horvath enum class AllocKind {
27d1abcf79SGabor Horvath SingleObject,
28d1abcf79SGabor Horvath Array,
29d1abcf79SGabor Horvath Unknown,
30d1abcf79SGabor Horvath Reinterpreted // Single object interpreted as an array.
31d1abcf79SGabor Horvath };
32d1abcf79SGabor Horvath } // end namespace
33d1abcf79SGabor Horvath
34d1abcf79SGabor Horvath namespace llvm {
35d1abcf79SGabor Horvath template <> struct FoldingSetTrait<AllocKind> {
Profilellvm::FoldingSetTrait36d1abcf79SGabor Horvath static inline void Profile(AllocKind X, FoldingSetNodeID &ID) {
37d1abcf79SGabor Horvath ID.AddInteger(static_cast<int>(X));
38d1abcf79SGabor Horvath }
39d1abcf79SGabor Horvath };
40d1abcf79SGabor Horvath } // end namespace llvm
41d1abcf79SGabor Horvath
42d1abcf79SGabor Horvath namespace {
43d99bd55aSTed Kremenek class PointerArithChecker
44d1abcf79SGabor Horvath : public Checker<
45d1abcf79SGabor Horvath check::PreStmt<BinaryOperator>, check::PreStmt<UnaryOperator>,
46d1abcf79SGabor Horvath check::PreStmt<ArraySubscriptExpr>, check::PreStmt<CastExpr>,
47d1abcf79SGabor Horvath check::PostStmt<CastExpr>, check::PostStmt<CXXNewExpr>,
48d1abcf79SGabor Horvath check::PostStmt<CallExpr>, check::DeadSymbols> {
49d1abcf79SGabor Horvath AllocKind getKindOfNewOp(const CXXNewExpr *NE, const FunctionDecl *FD) const;
50d1abcf79SGabor Horvath const MemRegion *getArrayRegion(const MemRegion *Region, bool &Polymorphic,
51d1abcf79SGabor Horvath AllocKind &AKind, CheckerContext &C) const;
52d1abcf79SGabor Horvath const MemRegion *getPointedRegion(const MemRegion *Region,
53d1abcf79SGabor Horvath CheckerContext &C) const;
54d1abcf79SGabor Horvath void reportPointerArithMisuse(const Expr *E, CheckerContext &C,
55d1abcf79SGabor Horvath bool PointedNeeded = false) const;
56d1abcf79SGabor Horvath void initAllocIdentifiers(ASTContext &C) const;
57d1abcf79SGabor Horvath
58d1abcf79SGabor Horvath mutable std::unique_ptr<BuiltinBug> BT_pointerArith;
59d1abcf79SGabor Horvath mutable std::unique_ptr<BuiltinBug> BT_polyArray;
60d1abcf79SGabor Horvath mutable llvm::SmallSet<IdentifierInfo *, 8> AllocFunctions;
61dff865d1SArgyrios Kyrtzidis
62d99bd55aSTed Kremenek public:
63d1abcf79SGabor Horvath void checkPreStmt(const UnaryOperator *UOp, CheckerContext &C) const;
64d1abcf79SGabor Horvath void checkPreStmt(const BinaryOperator *BOp, CheckerContext &C) const;
65d1abcf79SGabor Horvath void checkPreStmt(const ArraySubscriptExpr *SubExpr, CheckerContext &C) const;
66d1abcf79SGabor Horvath void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
67d1abcf79SGabor Horvath void checkPostStmt(const CastExpr *CE, CheckerContext &C) const;
68d1abcf79SGabor Horvath void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const;
69d1abcf79SGabor Horvath void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
70d1abcf79SGabor Horvath void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
71d99bd55aSTed Kremenek };
72d1abcf79SGabor Horvath } // end namespace
73d1abcf79SGabor Horvath
REGISTER_MAP_WITH_PROGRAMSTATE(RegionState,const MemRegion *,AllocKind)74d1abcf79SGabor Horvath REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, const MemRegion *, AllocKind)
75d1abcf79SGabor Horvath
76d1abcf79SGabor Horvath void PointerArithChecker::checkDeadSymbols(SymbolReaper &SR,
77d1abcf79SGabor Horvath CheckerContext &C) const {
78d1abcf79SGabor Horvath // TODO: intentional leak. Some information is garbage collected too early,
79d1abcf79SGabor Horvath // see http://reviews.llvm.org/D14203 for further information.
80d1abcf79SGabor Horvath /*ProgramStateRef State = C.getState();
81d1abcf79SGabor Horvath RegionStateTy RegionStates = State->get<RegionState>();
82d1abcf79SGabor Horvath for (RegionStateTy::iterator I = RegionStates.begin(), E = RegionStates.end();
83d1abcf79SGabor Horvath I != E; ++I) {
84d1abcf79SGabor Horvath if (!SR.isLiveRegion(I->first))
85d1abcf79SGabor Horvath State = State->remove<RegionState>(I->first);
86d1abcf79SGabor Horvath }
87d1abcf79SGabor Horvath C.addTransition(State);*/
88d99bd55aSTed Kremenek }
89d99bd55aSTed Kremenek
getKindOfNewOp(const CXXNewExpr * NE,const FunctionDecl * FD) const90d1abcf79SGabor Horvath AllocKind PointerArithChecker::getKindOfNewOp(const CXXNewExpr *NE,
91d1abcf79SGabor Horvath const FunctionDecl *FD) const {
92d1abcf79SGabor Horvath // This checker try not to assume anything about placement and overloaded
93d1abcf79SGabor Horvath // new to avoid false positives.
94d1abcf79SGabor Horvath if (isa<CXXMethodDecl>(FD))
95d1abcf79SGabor Horvath return AllocKind::Unknown;
96d1abcf79SGabor Horvath if (FD->getNumParams() != 1 || FD->isVariadic())
97d1abcf79SGabor Horvath return AllocKind::Unknown;
98d1abcf79SGabor Horvath if (NE->isArray())
99d1abcf79SGabor Horvath return AllocKind::Array;
100d1abcf79SGabor Horvath
101d1abcf79SGabor Horvath return AllocKind::SingleObject;
102d1abcf79SGabor Horvath }
103d1abcf79SGabor Horvath
104d1abcf79SGabor Horvath const MemRegion *
getPointedRegion(const MemRegion * Region,CheckerContext & C) const105d1abcf79SGabor Horvath PointerArithChecker::getPointedRegion(const MemRegion *Region,
106dff865d1SArgyrios Kyrtzidis CheckerContext &C) const {
107d1abcf79SGabor Horvath assert(Region);
108d1abcf79SGabor Horvath ProgramStateRef State = C.getState();
109d1abcf79SGabor Horvath SVal S = State->getSVal(Region);
110d1abcf79SGabor Horvath return S.getAsRegion();
111d1abcf79SGabor Horvath }
112d1abcf79SGabor Horvath
113d1abcf79SGabor Horvath /// Checks whether a region is the part of an array.
114b23ccecbSRaphael Isemann /// In case there is a derived to base cast above the array element, the
115d1abcf79SGabor Horvath /// Polymorphic output value is set to true. AKind output value is set to the
116d1abcf79SGabor Horvath /// allocation kind of the inspected region.
getArrayRegion(const MemRegion * Region,bool & Polymorphic,AllocKind & AKind,CheckerContext & C) const117d1abcf79SGabor Horvath const MemRegion *PointerArithChecker::getArrayRegion(const MemRegion *Region,
118d1abcf79SGabor Horvath bool &Polymorphic,
119d1abcf79SGabor Horvath AllocKind &AKind,
120d1abcf79SGabor Horvath CheckerContext &C) const {
121d1abcf79SGabor Horvath assert(Region);
122630f7dafSArtem Dergachev while (const auto *BaseRegion = dyn_cast<CXXBaseObjectRegion>(Region)) {
123630f7dafSArtem Dergachev Region = BaseRegion->getSuperRegion();
124d1abcf79SGabor Horvath Polymorphic = true;
125d1abcf79SGabor Horvath }
126630f7dafSArtem Dergachev if (const auto *ElemRegion = dyn_cast<ElementRegion>(Region)) {
127630f7dafSArtem Dergachev Region = ElemRegion->getSuperRegion();
128d1abcf79SGabor Horvath }
129d1abcf79SGabor Horvath
130d1abcf79SGabor Horvath ProgramStateRef State = C.getState();
131d1abcf79SGabor Horvath if (const AllocKind *Kind = State->get<RegionState>(Region)) {
132d1abcf79SGabor Horvath AKind = *Kind;
133d1abcf79SGabor Horvath if (*Kind == AllocKind::Array)
134d1abcf79SGabor Horvath return Region;
135d1abcf79SGabor Horvath else
136d1abcf79SGabor Horvath return nullptr;
137d1abcf79SGabor Horvath }
138d1abcf79SGabor Horvath // When the region is symbolic and we do not have any information about it,
139d1abcf79SGabor Horvath // assume that this is an array to avoid false positives.
140630f7dafSArtem Dergachev if (isa<SymbolicRegion>(Region))
141d1abcf79SGabor Horvath return Region;
142d1abcf79SGabor Horvath
143d1abcf79SGabor Horvath // No AllocKind stored and not symbolic, assume that it points to a single
144d1abcf79SGabor Horvath // object.
145d1abcf79SGabor Horvath return nullptr;
146d1abcf79SGabor Horvath }
147d1abcf79SGabor Horvath
reportPointerArithMisuse(const Expr * E,CheckerContext & C,bool PointedNeeded) const148d1abcf79SGabor Horvath void PointerArithChecker::reportPointerArithMisuse(const Expr *E,
149d1abcf79SGabor Horvath CheckerContext &C,
150d1abcf79SGabor Horvath bool PointedNeeded) const {
151d1abcf79SGabor Horvath SourceRange SR = E->getSourceRange();
152d1abcf79SGabor Horvath if (SR.isInvalid())
153d99bd55aSTed Kremenek return;
154d99bd55aSTed Kremenek
155d1abcf79SGabor Horvath ProgramStateRef State = C.getState();
156d703ec94SGeorge Karpenkov const MemRegion *Region = C.getSVal(E).getAsRegion();
157d1abcf79SGabor Horvath if (!Region)
158d1abcf79SGabor Horvath return;
159d1abcf79SGabor Horvath if (PointedNeeded)
160d1abcf79SGabor Horvath Region = getPointedRegion(Region, C);
161d1abcf79SGabor Horvath if (!Region)
162d99bd55aSTed Kremenek return;
163d99bd55aSTed Kremenek
164d1abcf79SGabor Horvath bool IsPolymorphic = false;
165d1abcf79SGabor Horvath AllocKind Kind = AllocKind::Unknown;
166d1abcf79SGabor Horvath if (const MemRegion *ArrayRegion =
167d1abcf79SGabor Horvath getArrayRegion(Region, IsPolymorphic, Kind, C)) {
168d1abcf79SGabor Horvath if (!IsPolymorphic)
169d1abcf79SGabor Horvath return;
170e39bd407SDevin Coughlin if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
171d1abcf79SGabor Horvath if (!BT_polyArray)
172d1abcf79SGabor Horvath BT_polyArray.reset(new BuiltinBug(
173d1abcf79SGabor Horvath this, "Dangerous pointer arithmetic",
174d1abcf79SGabor Horvath "Pointer arithmetic on a pointer to base class is dangerous "
175d1abcf79SGabor Horvath "because derived and base class may have different size."));
1762f169e7cSArtem Dergachev auto R = std::make_unique<PathSensitiveBugReport>(
1772f169e7cSArtem Dergachev *BT_polyArray, BT_polyArray->getDescription(), N);
178d1abcf79SGabor Horvath R->addRange(E->getSourceRange());
179d1abcf79SGabor Horvath R->markInteresting(ArrayRegion);
1808d3a7a56SAaron Ballman C.emitReport(std::move(R));
181d99bd55aSTed Kremenek }
182d1abcf79SGabor Horvath return;
183d1abcf79SGabor Horvath }
184d1abcf79SGabor Horvath
185d1abcf79SGabor Horvath if (Kind == AllocKind::Reinterpreted)
186d1abcf79SGabor Horvath return;
187d1abcf79SGabor Horvath
188d1abcf79SGabor Horvath // We might not have enough information about symbolic regions.
189d1abcf79SGabor Horvath if (Kind != AllocKind::SingleObject &&
190d1abcf79SGabor Horvath Region->getKind() == MemRegion::Kind::SymbolicRegionKind)
191d1abcf79SGabor Horvath return;
192d1abcf79SGabor Horvath
193d1abcf79SGabor Horvath if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
194d1abcf79SGabor Horvath if (!BT_pointerArith)
195d1abcf79SGabor Horvath BT_pointerArith.reset(new BuiltinBug(this, "Dangerous pointer arithmetic",
196d1abcf79SGabor Horvath "Pointer arithmetic on non-array "
197d1abcf79SGabor Horvath "variables relies on memory layout, "
198d1abcf79SGabor Horvath "which is dangerous."));
1992f169e7cSArtem Dergachev auto R = std::make_unique<PathSensitiveBugReport>(
2002f169e7cSArtem Dergachev *BT_pointerArith, BT_pointerArith->getDescription(), N);
201d1abcf79SGabor Horvath R->addRange(SR);
202d1abcf79SGabor Horvath R->markInteresting(Region);
203d1abcf79SGabor Horvath C.emitReport(std::move(R));
204d1abcf79SGabor Horvath }
205d1abcf79SGabor Horvath }
206d1abcf79SGabor Horvath
initAllocIdentifiers(ASTContext & C) const207d1abcf79SGabor Horvath void PointerArithChecker::initAllocIdentifiers(ASTContext &C) const {
208d1abcf79SGabor Horvath if (!AllocFunctions.empty())
209d1abcf79SGabor Horvath return;
210d1abcf79SGabor Horvath AllocFunctions.insert(&C.Idents.get("alloca"));
211d1abcf79SGabor Horvath AllocFunctions.insert(&C.Idents.get("malloc"));
212d1abcf79SGabor Horvath AllocFunctions.insert(&C.Idents.get("realloc"));
213d1abcf79SGabor Horvath AllocFunctions.insert(&C.Idents.get("calloc"));
214d1abcf79SGabor Horvath AllocFunctions.insert(&C.Idents.get("valloc"));
215d1abcf79SGabor Horvath }
216d1abcf79SGabor Horvath
checkPostStmt(const CallExpr * CE,CheckerContext & C) const217d1abcf79SGabor Horvath void PointerArithChecker::checkPostStmt(const CallExpr *CE,
218d1abcf79SGabor Horvath CheckerContext &C) const {
219d1abcf79SGabor Horvath ProgramStateRef State = C.getState();
220d1abcf79SGabor Horvath const FunctionDecl *FD = C.getCalleeDecl(CE);
221d1abcf79SGabor Horvath if (!FD)
222d1abcf79SGabor Horvath return;
223d1abcf79SGabor Horvath IdentifierInfo *FunI = FD->getIdentifier();
224d1abcf79SGabor Horvath initAllocIdentifiers(C.getASTContext());
225d1abcf79SGabor Horvath if (AllocFunctions.count(FunI) == 0)
226d1abcf79SGabor Horvath return;
227d1abcf79SGabor Horvath
228d703ec94SGeorge Karpenkov SVal SV = C.getSVal(CE);
229d1abcf79SGabor Horvath const MemRegion *Region = SV.getAsRegion();
230d1abcf79SGabor Horvath if (!Region)
231d1abcf79SGabor Horvath return;
232d1abcf79SGabor Horvath // Assume that C allocation functions allocate arrays to avoid false
233d1abcf79SGabor Horvath // positives.
234d1abcf79SGabor Horvath // TODO: Add heuristics to distinguish alloc calls that allocates single
235d1abcf79SGabor Horvath // objecs.
236d1abcf79SGabor Horvath State = State->set<RegionState>(Region, AllocKind::Array);
237d1abcf79SGabor Horvath C.addTransition(State);
238d1abcf79SGabor Horvath }
239d1abcf79SGabor Horvath
checkPostStmt(const CXXNewExpr * NE,CheckerContext & C) const240d1abcf79SGabor Horvath void PointerArithChecker::checkPostStmt(const CXXNewExpr *NE,
241d1abcf79SGabor Horvath CheckerContext &C) const {
242d1abcf79SGabor Horvath const FunctionDecl *FD = NE->getOperatorNew();
243d1abcf79SGabor Horvath if (!FD)
244d1abcf79SGabor Horvath return;
245d1abcf79SGabor Horvath
246d1abcf79SGabor Horvath AllocKind Kind = getKindOfNewOp(NE, FD);
247d1abcf79SGabor Horvath
248d1abcf79SGabor Horvath ProgramStateRef State = C.getState();
249d703ec94SGeorge Karpenkov SVal AllocedVal = C.getSVal(NE);
250d1abcf79SGabor Horvath const MemRegion *Region = AllocedVal.getAsRegion();
251d1abcf79SGabor Horvath if (!Region)
252d1abcf79SGabor Horvath return;
253d1abcf79SGabor Horvath State = State->set<RegionState>(Region, Kind);
254d1abcf79SGabor Horvath C.addTransition(State);
255d1abcf79SGabor Horvath }
256d1abcf79SGabor Horvath
checkPostStmt(const CastExpr * CE,CheckerContext & C) const257d1abcf79SGabor Horvath void PointerArithChecker::checkPostStmt(const CastExpr *CE,
258d1abcf79SGabor Horvath CheckerContext &C) const {
259d1abcf79SGabor Horvath if (CE->getCastKind() != CastKind::CK_BitCast)
260d1abcf79SGabor Horvath return;
261d1abcf79SGabor Horvath
262d1abcf79SGabor Horvath const Expr *CastedExpr = CE->getSubExpr();
263d1abcf79SGabor Horvath ProgramStateRef State = C.getState();
264d703ec94SGeorge Karpenkov SVal CastedVal = C.getSVal(CastedExpr);
265d1abcf79SGabor Horvath
266d1abcf79SGabor Horvath const MemRegion *Region = CastedVal.getAsRegion();
267d1abcf79SGabor Horvath if (!Region)
268d1abcf79SGabor Horvath return;
269d1abcf79SGabor Horvath
270d1abcf79SGabor Horvath // Suppress reinterpret casted hits.
271d1abcf79SGabor Horvath State = State->set<RegionState>(Region, AllocKind::Reinterpreted);
272d1abcf79SGabor Horvath C.addTransition(State);
273d1abcf79SGabor Horvath }
274d1abcf79SGabor Horvath
checkPreStmt(const CastExpr * CE,CheckerContext & C) const275d1abcf79SGabor Horvath void PointerArithChecker::checkPreStmt(const CastExpr *CE,
276d1abcf79SGabor Horvath CheckerContext &C) const {
277d1abcf79SGabor Horvath if (CE->getCastKind() != CastKind::CK_ArrayToPointerDecay)
278d1abcf79SGabor Horvath return;
279d1abcf79SGabor Horvath
280d1abcf79SGabor Horvath const Expr *CastedExpr = CE->getSubExpr();
281d1abcf79SGabor Horvath ProgramStateRef State = C.getState();
282d703ec94SGeorge Karpenkov SVal CastedVal = C.getSVal(CastedExpr);
283d1abcf79SGabor Horvath
284d1abcf79SGabor Horvath const MemRegion *Region = CastedVal.getAsRegion();
285d1abcf79SGabor Horvath if (!Region)
286d1abcf79SGabor Horvath return;
287d1abcf79SGabor Horvath
288d1abcf79SGabor Horvath if (const AllocKind *Kind = State->get<RegionState>(Region)) {
289d1abcf79SGabor Horvath if (*Kind == AllocKind::Array || *Kind == AllocKind::Reinterpreted)
290d1abcf79SGabor Horvath return;
291d1abcf79SGabor Horvath }
292d1abcf79SGabor Horvath State = State->set<RegionState>(Region, AllocKind::Array);
293d1abcf79SGabor Horvath C.addTransition(State);
294d1abcf79SGabor Horvath }
295d1abcf79SGabor Horvath
checkPreStmt(const UnaryOperator * UOp,CheckerContext & C) const296d1abcf79SGabor Horvath void PointerArithChecker::checkPreStmt(const UnaryOperator *UOp,
297d1abcf79SGabor Horvath CheckerContext &C) const {
298d1abcf79SGabor Horvath if (!UOp->isIncrementDecrementOp() || !UOp->getType()->isPointerType())
299d1abcf79SGabor Horvath return;
300d1abcf79SGabor Horvath reportPointerArithMisuse(UOp->getSubExpr(), C, true);
301d1abcf79SGabor Horvath }
302d1abcf79SGabor Horvath
checkPreStmt(const ArraySubscriptExpr * SubsExpr,CheckerContext & C) const303d1abcf79SGabor Horvath void PointerArithChecker::checkPreStmt(const ArraySubscriptExpr *SubsExpr,
304d1abcf79SGabor Horvath CheckerContext &C) const {
305d703ec94SGeorge Karpenkov SVal Idx = C.getSVal(SubsExpr->getIdx());
306d1abcf79SGabor Horvath
307d1abcf79SGabor Horvath // Indexing with 0 is OK.
308d1abcf79SGabor Horvath if (Idx.isZeroConstant())
309d1abcf79SGabor Horvath return;
3108e3a6591SGeorge Karpenkov
3118e3a6591SGeorge Karpenkov // Indexing vector-type expressions is also OK.
3128e3a6591SGeorge Karpenkov if (SubsExpr->getBase()->getType()->isVectorType())
3138e3a6591SGeorge Karpenkov return;
314d1abcf79SGabor Horvath reportPointerArithMisuse(SubsExpr->getBase(), C);
315d1abcf79SGabor Horvath }
316d1abcf79SGabor Horvath
checkPreStmt(const BinaryOperator * BOp,CheckerContext & C) const317d1abcf79SGabor Horvath void PointerArithChecker::checkPreStmt(const BinaryOperator *BOp,
318d1abcf79SGabor Horvath CheckerContext &C) const {
319d1abcf79SGabor Horvath BinaryOperatorKind OpKind = BOp->getOpcode();
320d1abcf79SGabor Horvath if (!BOp->isAdditiveOp() && OpKind != BO_AddAssign && OpKind != BO_SubAssign)
321d1abcf79SGabor Horvath return;
322d1abcf79SGabor Horvath
323d1abcf79SGabor Horvath const Expr *Lhs = BOp->getLHS();
324d1abcf79SGabor Horvath const Expr *Rhs = BOp->getRHS();
325d1abcf79SGabor Horvath ProgramStateRef State = C.getState();
326d1abcf79SGabor Horvath
327d1abcf79SGabor Horvath if (Rhs->getType()->isIntegerType() && Lhs->getType()->isPointerType()) {
328d703ec94SGeorge Karpenkov SVal RHSVal = C.getSVal(Rhs);
329d1abcf79SGabor Horvath if (State->isNull(RHSVal).isConstrainedTrue())
330d1abcf79SGabor Horvath return;
331d1abcf79SGabor Horvath reportPointerArithMisuse(Lhs, C, !BOp->isAdditiveOp());
332d1abcf79SGabor Horvath }
333d1abcf79SGabor Horvath // The int += ptr; case is not valid C++.
334d1abcf79SGabor Horvath if (Lhs->getType()->isIntegerType() && Rhs->getType()->isPointerType()) {
335d703ec94SGeorge Karpenkov SVal LHSVal = C.getSVal(Lhs);
336d1abcf79SGabor Horvath if (State->isNull(LHSVal).isConstrainedTrue())
337d1abcf79SGabor Horvath return;
338d1abcf79SGabor Horvath reportPointerArithMisuse(Rhs, C);
339d99bd55aSTed Kremenek }
340d99bd55aSTed Kremenek }
341d99bd55aSTed Kremenek
registerPointerArithChecker(CheckerManager & mgr)342507ff53eSArgyrios Kyrtzidis void ento::registerPointerArithChecker(CheckerManager &mgr) {
343dff865d1SArgyrios Kyrtzidis mgr.registerChecker<PointerArithChecker>();
344507ff53eSArgyrios Kyrtzidis }
345058a7a45SKristof Umann
shouldRegisterPointerArithChecker(const CheckerManager & mgr)346*bda3dd0dSKirstóf Umann bool ento::shouldRegisterPointerArithChecker(const CheckerManager &mgr) {
347058a7a45SKristof Umann return true;
348058a7a45SKristof Umann }
349