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> {
50 AllocKind getKindOfNewOp(
const CXXNewExpr *NE,
const FunctionDecl *FD)
const;
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 const BugType BT_pointerArith{
this,
"Dangerous pointer arithmetic"};
60 const BugType BT_polyArray{
this,
"Dangerous pointer arithmetic"};
61 mutable llvm::SmallPtrSet<IdentifierInfo *, 8> AllocFunctions;
64 void checkPreStmt(
const UnaryOperator *UOp, CheckerContext &
C)
const;
65 void checkPreStmt(
const BinaryOperator *BOp, CheckerContext &
C)
const;
66 void checkPreStmt(
const ArraySubscriptExpr *SubExpr, 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;
78 return NE->isArray() && NE->getNumPlacementArgs() > 0;
83 while (
const auto *BaseRegion = dyn_cast<CXXBaseObjectRegion>(Region)) {
84 Region = BaseRegion->getSuperRegion();
86 if (
const auto *ElemRegion = dyn_cast<ElementRegion>(Region)) {
87 State = State->set<RegionState>(ElemRegion->getSuperRegion(),
88 AllocKind::Reinterpreted);
93void PointerArithChecker::checkDeadSymbols(
SymbolReaper &SR,
106AllocKind PointerArithChecker::getKindOfNewOp(
const CXXNewExpr *NE,
107 const FunctionDecl *FD)
const {
111 return AllocKind::Unknown;
113 return AllocKind::Unknown;
115 return AllocKind::Array;
117 return AllocKind::SingleObject;
121PointerArithChecker::getPointedRegion(
const MemRegion *Region,
122 CheckerContext &
C)
const {
125 SVal S = State->getSVal(Region);
133const MemRegion *PointerArithChecker::getArrayRegion(
const MemRegion *Region,
136 CheckerContext &
C)
const {
138 while (
const auto *BaseRegion = dyn_cast<CXXBaseObjectRegion>(Region)) {
139 Region = BaseRegion->getSuperRegion();
142 if (
const auto *ElemRegion = dyn_cast<ElementRegion>(Region)) {
143 Region = ElemRegion->getSuperRegion();
147 if (
const AllocKind *Kind = State->get<RegionState>(Region)) {
149 if (*Kind == AllocKind::Array)
164void PointerArithChecker::reportPointerArithMisuse(
const Expr *E,
166 bool PointedNeeded)
const {
172 const MemRegion *Region =
C.getSVal(E).getAsRegion();
176 Region = getPointedRegion(Region,
C);
180 bool IsPolymorphic =
false;
181 AllocKind
Kind = AllocKind::Unknown;
182 if (
const MemRegion *ArrayRegion =
183 getArrayRegion(Region, IsPolymorphic, Kind,
C)) {
186 if (ExplodedNode *N =
C.generateNonFatalErrorNode()) {
187 constexpr llvm::StringLiteral Msg =
188 "Pointer arithmetic on a pointer to base class is dangerous "
189 "because derived and base class may have different size.";
190 auto R = std::make_unique<PathSensitiveBugReport>(BT_polyArray, Msg, N);
192 R->markInteresting(ArrayRegion);
193 C.emitReport(std::move(R));
198 if (Kind == AllocKind::Reinterpreted)
202 if (Kind != AllocKind::SingleObject &&
203 Region->
getKind() == MemRegion::Kind::SymbolicRegionKind)
206 if (ExplodedNode *N =
C.generateNonFatalErrorNode()) {
207 constexpr llvm::StringLiteral Msg =
208 "Pointer arithmetic on non-array variables relies on memory layout, "
209 "which is dangerous.";
210 auto R = std::make_unique<PathSensitiveBugReport>(BT_pointerArith, Msg, N);
212 R->markInteresting(Region);
213 C.emitReport(std::move(R));
217void PointerArithChecker::initAllocIdentifiers(ASTContext &
C)
const {
218 if (!AllocFunctions.empty())
220 AllocFunctions.insert(&
C.Idents.get(
"alloca"));
221 AllocFunctions.insert(&
C.Idents.get(
"malloc"));
222 AllocFunctions.insert(&
C.Idents.get(
"realloc"));
223 AllocFunctions.insert(&
C.Idents.get(
"calloc"));
224 AllocFunctions.insert(&
C.Idents.get(
"valloc"));
227void PointerArithChecker::checkPostStmt(
const CallExpr *CE,
228 CheckerContext &
C)
const {
230 const FunctionDecl *FD =
C.getCalleeDecl(CE);
234 initAllocIdentifiers(
C.getASTContext());
235 if (AllocFunctions.count(FunI) == 0)
238 SVal SV =
C.getSVal(CE);
246 State = State->set<RegionState>(Region, AllocKind::Array);
247 C.addTransition(State);
250void PointerArithChecker::checkPostStmt(
const CXXNewExpr *NE,
251 CheckerContext &
C)
const {
252 const FunctionDecl *FD =
NE->getOperatorNew();
256 AllocKind
Kind = getKindOfNewOp(NE, FD);
259 SVal AllocedVal =
C.getSVal(NE);
260 const MemRegion *Region = AllocedVal.
getAsRegion();
269 State = State->set<RegionState>(Region,
Kind);
270 C.addTransition(State);
273void PointerArithChecker::checkPostStmt(
const CastExpr *CE,
274 CheckerContext &
C)
const {
284 SVal CastedVal =
C.getSVal(CastedExpr);
291 State = State->set<RegionState>(Region, AllocKind::Reinterpreted);
292 C.addTransition(State);
295void PointerArithChecker::checkPreStmt(
const CastExpr *CE,
296 CheckerContext &
C)
const {
297 if (CE->
getCastKind() != CastKind::CK_ArrayToPointerDecay)
302 SVal CastedVal =
C.getSVal(CastedExpr);
308 if (
const AllocKind *Kind = State->get<RegionState>(Region)) {
309 if (*Kind == AllocKind::Array || *Kind == AllocKind::Reinterpreted)
312 State = State->set<RegionState>(Region, AllocKind::Array);
313 C.addTransition(State);
316void PointerArithChecker::checkPreStmt(
const UnaryOperator *UOp,
317 CheckerContext &
C)
const {
320 reportPointerArithMisuse(UOp->
getSubExpr(),
C,
true);
323void PointerArithChecker::checkPreStmt(
const ArraySubscriptExpr *SubsExpr,
324 CheckerContext &
C)
const {
325 SVal Idx =
C.getSVal(SubsExpr->
getIdx());
334 reportPointerArithMisuse(SubsExpr->
getBase(),
C);
337void PointerArithChecker::checkPreStmt(
const BinaryOperator *BOp,
338 CheckerContext &
C)
const {
340 if (!BOp->
isAdditiveOp() && OpKind != BO_AddAssign && OpKind != BO_SubAssign)
343 const Expr *Lhs = BOp->
getLHS();
344 const Expr *Rhs = BOp->
getRHS();
348 SVal RHSVal =
C.getSVal(Rhs);
349 if (State->isNull(RHSVal).isConstrainedTrue())
355 SVal LHSVal =
C.getSVal(Lhs);
356 if (State->isNull(LHSVal).isConstrainedTrue())
358 reportPointerArithMisuse(Rhs,
C);
362void ento::registerPointerArithChecker(CheckerManager &mgr) {
366bool 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.
static ProgramStateRef markSuperRegionReinterpreted(ProgramStateRef State, const MemRegion *Region)
static bool isArrayPlacementNew(const CXXNewExpr *NE)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
static bool isAdditiveOp(Opcode Opc)
Represents a new-expression for memory allocation and constructor calls, e.g: "new CXXNewExpr(foo)".
CastKind getCastKind() const
bool isVariadic() const
Whether this function is variadic.
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
bool isVoidPointerType() const
bool isPointerType() const
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
bool isVectorType() const
Expr * getSubExpr() const
static bool isIncrementDecrementOp(Opcode Op)
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
MemRegion - The root abstract class for all memory regions.
bool isZeroConstant() const
const MemRegion * getAsRegion() const
A class responsible for cleaning up unused symbols.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
bool NE(InterpState &S, CodePtr OpPC)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Diagnostic wrappers for TextAPI types for error reporting.
static void Profile(AllocKind X, FoldingSetNodeID &ID)