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 const BugType BT_pointerArith{
this,
"Dangerous pointer arithmetic"};
60 const BugType BT_polyArray{
this,
"Dangerous pointer arithmetic"};
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)) {
171 constexpr llvm::StringLiteral Msg =
172 "Pointer arithmetic on a pointer to base class is dangerous "
173 "because derived and base class may have different size.";
174 auto R = std::make_unique<PathSensitiveBugReport>(BT_polyArray, Msg, N);
176 R->markInteresting(ArrayRegion);
177 C.emitReport(std::move(R));
182 if (Kind == AllocKind::Reinterpreted)
186 if (Kind != AllocKind::SingleObject &&
187 Region->
getKind() == MemRegion::Kind::SymbolicRegionKind)
191 constexpr llvm::StringLiteral Msg =
192 "Pointer arithmetic on non-array variables relies on memory layout, "
193 "which is dangerous.";
194 auto R = std::make_unique<PathSensitiveBugReport>(BT_pointerArith, Msg, N);
196 R->markInteresting(Region);
197 C.emitReport(std::move(R));
201void PointerArithChecker::initAllocIdentifiers(
ASTContext &
C)
const {
202 if (!AllocFunctions.empty())
204 AllocFunctions.insert(&
C.Idents.get(
"alloca"));
205 AllocFunctions.insert(&
C.Idents.get(
"malloc"));
206 AllocFunctions.insert(&
C.Idents.get(
"realloc"));
207 AllocFunctions.insert(&
C.Idents.get(
"calloc"));
208 AllocFunctions.insert(&
C.Idents.get(
"valloc"));
211void PointerArithChecker::checkPostStmt(
const CallExpr *CE,
218 initAllocIdentifiers(
C.getASTContext());
219 if (AllocFunctions.count(FunI) == 0)
222 SVal SV =
C.getSVal(CE);
230 State = State->set<RegionState>(Region, AllocKind::Array);
231 C.addTransition(State);
234void PointerArithChecker::checkPostStmt(
const CXXNewExpr *NE,
240 AllocKind
Kind = getKindOfNewOp(NE, FD);
243 SVal AllocedVal =
C.getSVal(NE);
247 State = State->set<RegionState>(Region,
Kind);
248 C.addTransition(State);
251void PointerArithChecker::checkPostStmt(
const CastExpr *CE,
258 SVal CastedVal =
C.getSVal(CastedExpr);
265 State = State->set<RegionState>(Region, AllocKind::Reinterpreted);
266 C.addTransition(State);
269void PointerArithChecker::checkPreStmt(
const CastExpr *CE,
271 if (CE->
getCastKind() != CastKind::CK_ArrayToPointerDecay)
276 SVal CastedVal =
C.getSVal(CastedExpr);
282 if (
const AllocKind *Kind = State->get<RegionState>(Region)) {
283 if (*Kind == AllocKind::Array || *Kind == AllocKind::Reinterpreted)
286 State = State->set<RegionState>(Region, AllocKind::Array);
287 C.addTransition(State);
290void PointerArithChecker::checkPreStmt(
const UnaryOperator *UOp,
294 reportPointerArithMisuse(UOp->
getSubExpr(),
C,
true);
308 reportPointerArithMisuse(SubsExpr->
getBase(),
C);
314 if (!BOp->
isAdditiveOp() && OpKind != BO_AddAssign && OpKind != BO_SubAssign)
322 SVal RHSVal =
C.getSVal(Rhs);
323 if (State->isNull(RHSVal).isConstrainedTrue())
329 SVal LHSVal =
C.getSVal(Lhs);
330 if (State->isNull(LHSVal).isConstrainedTrue())
332 reportPointerArithMisuse(Rhs,
C);
340bool 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)
The JSON file list parser is used to communicate input to InstallAPI.
Diagnostic wrappers for TextAPI types for error reporting.
static void Profile(AllocKind X, FoldingSetNodeID &ID)