23 using namespace clang;
38 ID.AddInteger(static_cast<int>(X));
44 class PointerArithChecker
46 check::PreStmt<BinaryOperator>, check::PreStmt<UnaryOperator>,
47 check::PreStmt<ArraySubscriptExpr>, check::PreStmt<CastExpr>,
48 check::PostStmt<CastExpr>, check::PostStmt<CXXNewExpr>,
49 check::PostStmt<CallExpr>, check::DeadSymbols> {
51 const MemRegion *getArrayRegion(
const MemRegion *Region,
bool &Polymorphic,
52 AllocKind &AKind, CheckerContext &C)
const;
53 const MemRegion *getPointedRegion(
const MemRegion *Region,
54 CheckerContext &C)
const;
55 void reportPointerArithMisuse(
const Expr *E, CheckerContext &C,
56 bool PointedNeeded =
false)
const;
57 void initAllocIdentifiers(
ASTContext &C)
const;
59 mutable std::unique_ptr<BuiltinBug> BT_pointerArith;
60 mutable std::unique_ptr<BuiltinBug> BT_polyArray;
61 mutable llvm::SmallSet<IdentifierInfo *, 8> AllocFunctions;
64 void checkPreStmt(
const UnaryOperator *UOp, CheckerContext &C)
const;
65 void checkPreStmt(
const BinaryOperator *BOp, CheckerContext &C)
const;
67 void checkPreStmt(
const CastExpr *CE, CheckerContext &C)
const;
68 void checkPostStmt(
const CastExpr *CE, CheckerContext &C)
const;
69 void checkPostStmt(
const CXXNewExpr *NE, CheckerContext &C)
const;
70 void checkPostStmt(
const CallExpr *CE, CheckerContext &C)
const;
71 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C)
const;
77 void PointerArithChecker::checkDeadSymbols(SymbolReaper &SR,
78 CheckerContext &C)
const {
95 if (isa<CXXMethodDecl>(FD))
100 return AllocKind::Array;
102 return AllocKind::SingleObject;
106 PointerArithChecker::getPointedRegion(
const MemRegion *Region,
107 CheckerContext &C)
const {
110 SVal S = State->getSVal(Region);
111 return S.getAsRegion();
118 const MemRegion *PointerArithChecker::getArrayRegion(
const MemRegion *Region,
121 CheckerContext &C)
const {
123 while (Region->getKind() == MemRegion::Kind::CXXBaseObjectRegionKind) {
124 Region = Region->getAs<CXXBaseObjectRegion>()->getSuperRegion();
127 if (Region->getKind() == MemRegion::Kind::ElementRegionKind) {
128 Region = Region->getAs<ElementRegion>()->getSuperRegion();
132 if (
const AllocKind *
Kind = State->get<RegionState>(Region)) {
134 if (*
Kind == AllocKind::Array)
141 if (Region->getKind() == MemRegion::Kind::SymbolicRegionKind)
149 void PointerArithChecker::reportPointerArithMisuse(
const Expr *E,
151 bool PointedNeeded)
const {
157 const MemRegion *Region = C.getSVal(E).getAsRegion();
161 Region = getPointedRegion(Region, C);
165 bool IsPolymorphic =
false;
167 if (
const MemRegion *ArrayRegion =
168 getArrayRegion(Region, IsPolymorphic, Kind, C)) {
171 if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
173 BT_polyArray.reset(
new BuiltinBug(
174 this,
"Dangerous pointer arithmetic",
175 "Pointer arithmetic on a pointer to base class is dangerous " 176 "because derived and base class may have different size."));
177 auto R = llvm::make_unique<BugReport>(*BT_polyArray,
178 BT_polyArray->getDescription(), N);
180 R->markInteresting(ArrayRegion);
181 C.emitReport(std::move(R));
186 if (Kind == AllocKind::Reinterpreted)
190 if (Kind != AllocKind::SingleObject &&
191 Region->getKind() == MemRegion::Kind::SymbolicRegionKind)
194 if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
195 if (!BT_pointerArith)
196 BT_pointerArith.reset(
new BuiltinBug(
this,
"Dangerous pointer arithmetic",
197 "Pointer arithmetic on non-array " 198 "variables relies on memory layout, " 199 "which is dangerous."));
200 auto R = llvm::make_unique<BugReport>(*BT_pointerArith,
201 BT_pointerArith->getDescription(), N);
203 R->markInteresting(Region);
204 C.emitReport(std::move(R));
208 void PointerArithChecker::initAllocIdentifiers(
ASTContext &C)
const {
209 if (!AllocFunctions.empty())
211 AllocFunctions.insert(&C.
Idents.
get(
"alloca"));
212 AllocFunctions.insert(&C.
Idents.
get(
"malloc"));
213 AllocFunctions.insert(&C.
Idents.
get(
"realloc"));
214 AllocFunctions.insert(&C.
Idents.
get(
"calloc"));
215 AllocFunctions.insert(&C.
Idents.
get(
"valloc"));
218 void PointerArithChecker::checkPostStmt(
const CallExpr *CE,
219 CheckerContext &C)
const {
225 initAllocIdentifiers(C.getASTContext());
226 if (AllocFunctions.count(FunI) == 0)
229 SVal SV = C.getSVal(CE);
230 const MemRegion *Region = SV.getAsRegion();
237 State = State->set<RegionState>(Region, AllocKind::Array);
238 C.addTransition(State);
241 void PointerArithChecker::checkPostStmt(
const CXXNewExpr *NE,
242 CheckerContext &C)
const {
250 SVal AllocedVal = C.getSVal(NE);
251 const MemRegion *Region = AllocedVal.getAsRegion();
254 State = State->set<RegionState>(Region,
Kind);
255 C.addTransition(State);
258 void PointerArithChecker::checkPostStmt(
const CastExpr *CE,
259 CheckerContext &C)
const {
265 SVal CastedVal = C.getSVal(CastedExpr);
267 const MemRegion *Region = CastedVal.getAsRegion();
272 State = State->set<RegionState>(Region, AllocKind::Reinterpreted);
273 C.addTransition(State);
276 void PointerArithChecker::checkPreStmt(
const CastExpr *CE,
277 CheckerContext &C)
const {
278 if (CE->
getCastKind() != CastKind::CK_ArrayToPointerDecay)
283 SVal CastedVal = C.getSVal(CastedExpr);
285 const MemRegion *Region = CastedVal.getAsRegion();
289 if (
const AllocKind *
Kind = State->get<RegionState>(Region)) {
290 if (*
Kind == AllocKind::Array || *
Kind == AllocKind::Reinterpreted)
293 State = State->set<RegionState>(Region, AllocKind::Array);
294 C.addTransition(State);
297 void PointerArithChecker::checkPreStmt(
const UnaryOperator *UOp,
298 CheckerContext &C)
const {
301 reportPointerArithMisuse(UOp->
getSubExpr(), C,
true);
305 CheckerContext &C)
const {
306 SVal Idx = C.getSVal(SubsExpr->
getIdx());
309 if (Idx.isZeroConstant())
315 reportPointerArithMisuse(SubsExpr->
getBase(), C);
319 CheckerContext &C)
const {
321 if (!BOp->
isAdditiveOp() && OpKind != BO_AddAssign && OpKind != BO_SubAssign)
329 SVal RHSVal = C.getSVal(Rhs);
330 if (State->isNull(RHSVal).isConstrainedTrue())
336 SVal LHSVal = C.getSVal(Lhs);
337 if (State->isNull(LHSVal).isConstrainedTrue())
339 reportPointerArithMisuse(Rhs, C);
343 void ento::registerPointerArithChecker(CheckerManager &mgr) {
344 mgr.registerChecker<PointerArithChecker>();
Represents a function declaration or definition.
DominatorTree GraphTraits specialization so the DominatorTree can be iterable by generic graph iterat...
FunctionDecl * getOperatorNew() const
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Defines the clang::Expr interface and subclasses for C++ expressions.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
One of these records is kept for each identifier that is lexed.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
static void Profile(AllocKind X, FoldingSetNodeID &ID)
static bool isIncrementDecrementOp(Opcode Op)
A builtin binary operation expression such as "x + y" or "x <= y".
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
This represents one expression.
bool isVariadic() const
Whether this function is variadic.
UnaryOperator - This represents the unary-expression's (except sizeof and alignof), the postinc/postdec operators from postfix-expression, and various extensions.
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
Expr * getSubExpr() const
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
CastKind getCastKind() const
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)"...
bool isVectorType() const
Dataflow Directional Tag Classes.
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
static bool isAdditiveOp(Opcode Opc)
X
Add a minimal nested name specifier fixit hint to allow lookup of a tag name from an outer enclosing ...
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
bool isPointerType() const
A trivial tuple used to represent a source range.
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.