21#include "llvm/ADT/StringRef.h"
37 static inline void Profile(AllocKind
X, FoldingSetNodeID &ID) {
38 ID.AddInteger(
static_cast<int>(
X));
44class 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> {
56 bool PointedNeeded =
false)
const;
59 mutable std::unique_ptr<BugType> BT_pointerArith;
60 mutable std::unique_ptr<BugType> BT_polyArray;
61 mutable llvm::SmallSet<IdentifierInfo *, 8> AllocFunctions;
77void PointerArithChecker::checkDeadSymbols(
SymbolReaper &SR,
90AllocKind PointerArithChecker::getKindOfNewOp(
const CXXNewExpr *NE,
94 if (isa<CXXMethodDecl>(FD))
95 return AllocKind::Unknown;
97 return AllocKind::Unknown;
99 return AllocKind::Array;
101 return AllocKind::SingleObject;
105PointerArithChecker::getPointedRegion(
const MemRegion *Region,
109 SVal S = State->getSVal(Region);
110 return S.getAsRegion();
122 while (
const auto *BaseRegion = dyn_cast<CXXBaseObjectRegion>(Region)) {
123 Region = BaseRegion->getSuperRegion();
126 if (
const auto *ElemRegion = dyn_cast<ElementRegion>(Region)) {
127 Region = ElemRegion->getSuperRegion();
131 if (
const AllocKind *Kind = State->get<RegionState>(Region)) {
133 if (*Kind == AllocKind::Array)
140 if (isa<SymbolicRegion>(Region))
148void PointerArithChecker::reportPointerArithMisuse(
const Expr *E,
150 bool PointedNeeded)
const {
156 const MemRegion *Region =
C.getSVal(E).getAsRegion();
160 Region = getPointedRegion(Region,
C);
164 bool IsPolymorphic =
false;
165 AllocKind
Kind = AllocKind::Unknown;
167 getArrayRegion(Region, IsPolymorphic, Kind,
C)) {
172 BT_polyArray.reset(
new BugType(
this,
"Dangerous pointer arithmetic"));
173 constexpr llvm::StringLiteral Msg =
174 "Pointer arithmetic on a pointer to base class is dangerous "
175 "because derived and base class may have different size.";
176 auto R = std::make_unique<PathSensitiveBugReport>(*BT_polyArray, Msg, N);
178 R->markInteresting(ArrayRegion);
179 C.emitReport(std::move(R));
184 if (Kind == AllocKind::Reinterpreted)
188 if (Kind != AllocKind::SingleObject &&
189 Region->
getKind() == MemRegion::Kind::SymbolicRegionKind)
193 if (!BT_pointerArith)
194 BT_pointerArith.reset(
new BugType(
this,
"Dangerous pointer arithmetic"));
195 constexpr llvm::StringLiteral Msg =
196 "Pointer arithmetic on non-array variables relies on memory layout, "
197 "which is dangerous.";
198 auto R = std::make_unique<PathSensitiveBugReport>(*BT_pointerArith, Msg, N);
200 R->markInteresting(Region);
201 C.emitReport(std::move(R));
205void PointerArithChecker::initAllocIdentifiers(
ASTContext &
C)
const {
206 if (!AllocFunctions.empty())
208 AllocFunctions.insert(&
C.Idents.get(
"alloca"));
209 AllocFunctions.insert(&
C.Idents.get(
"malloc"));
210 AllocFunctions.insert(&
C.Idents.get(
"realloc"));
211 AllocFunctions.insert(&
C.Idents.get(
"calloc"));
212 AllocFunctions.insert(&
C.Idents.get(
"valloc"));
215void PointerArithChecker::checkPostStmt(
const CallExpr *CE,
222 initAllocIdentifiers(
C.getASTContext());
223 if (AllocFunctions.count(FunI) == 0)
226 SVal SV =
C.getSVal(CE);
234 State = State->set<RegionState>(Region, AllocKind::Array);
235 C.addTransition(State);
238void PointerArithChecker::checkPostStmt(
const CXXNewExpr *NE,
244 AllocKind
Kind = getKindOfNewOp(NE, FD);
247 SVal AllocedVal =
C.getSVal(NE);
251 State = State->set<RegionState>(Region,
Kind);
252 C.addTransition(State);
255void PointerArithChecker::checkPostStmt(
const CastExpr *CE,
262 SVal CastedVal =
C.getSVal(CastedExpr);
269 State = State->set<RegionState>(Region, AllocKind::Reinterpreted);
270 C.addTransition(State);
273void PointerArithChecker::checkPreStmt(
const CastExpr *CE,
275 if (CE->
getCastKind() != CastKind::CK_ArrayToPointerDecay)
280 SVal CastedVal =
C.getSVal(CastedExpr);
286 if (
const AllocKind *Kind = State->get<RegionState>(Region)) {
287 if (*Kind == AllocKind::Array || *Kind == AllocKind::Reinterpreted)
290 State = State->set<RegionState>(Region, AllocKind::Array);
291 C.addTransition(State);
294void PointerArithChecker::checkPreStmt(
const UnaryOperator *UOp,
298 reportPointerArithMisuse(UOp->
getSubExpr(),
C,
true);
312 reportPointerArithMisuse(SubsExpr->
getBase(),
C);
318 if (!BOp->
isAdditiveOp() && OpKind != BO_AddAssign && OpKind != BO_SubAssign)
326 SVal RHSVal =
C.getSVal(Rhs);
327 if (State->isNull(RHSVal).isConstrainedTrue())
333 SVal LHSVal =
C.getSVal(Lhs);
334 if (State->isNull(LHSVal).isConstrainedTrue())
336 reportPointerArithMisuse(Rhs,
C);
344bool ento::shouldRegisterPointerArithChecker(
const CheckerManager &mgr) {
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the clang::Expr interface and subclasses for C++ expressions.
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
A builtin binary operation expression such as "x + y" or "x <= y".
static bool isAdditiveOp(Opcode Opc)
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
CastKind getCastKind() const
This represents one expression.
Represents a function declaration or definition.
bool isVariadic() const
Whether this function is variadic.
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
One of these records is kept for each identifier that is lexed.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
A trivial tuple used to represent a source range.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
bool isPointerType() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
bool isVectorType() const
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Expr * getSubExpr() const
static bool isIncrementDecrementOp(Opcode Op)
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
MemRegion - The root abstract class for all memory regions.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
bool isZeroConstant() const
const MemRegion * getAsRegion() const
A class responsible for cleaning up unused symbols.
bool NE(InterpState &S, CodePtr OpPC)
YAML serialization mapping.
static void Profile(AllocKind X, FoldingSetNodeID &ID)