22 using namespace clang;
37 ID.AddInteger(static_cast<int>(X));
43 class PointerArithChecker
45 check::PreStmt<BinaryOperator>, check::PreStmt<UnaryOperator>,
46 check::PreStmt<ArraySubscriptExpr>, check::PreStmt<CastExpr>,
47 check::PostStmt<CastExpr>, check::PostStmt<CXXNewExpr>,
48 check::PostStmt<CallExpr>, check::DeadSymbols> {
50 const MemRegion *getArrayRegion(
const MemRegion *Region,
bool &Polymorphic,
51 AllocKind &AKind, CheckerContext &C)
const;
52 const MemRegion *getPointedRegion(
const MemRegion *Region,
53 CheckerContext &C)
const;
54 void reportPointerArithMisuse(
const Expr *E, CheckerContext &C,
55 bool PointedNeeded =
false)
const;
56 void initAllocIdentifiers(
ASTContext &C)
const;
58 mutable std::unique_ptr<BuiltinBug> BT_pointerArith;
59 mutable std::unique_ptr<BuiltinBug> BT_polyArray;
60 mutable llvm::SmallSet<IdentifierInfo *, 8> AllocFunctions;
63 void checkPreStmt(
const UnaryOperator *UOp, CheckerContext &C)
const;
64 void checkPreStmt(
const BinaryOperator *BOp, CheckerContext &C)
const;
66 void checkPreStmt(
const CastExpr *CE, CheckerContext &C)
const;
67 void checkPostStmt(
const CastExpr *CE, CheckerContext &C)
const;
68 void checkPostStmt(
const CXXNewExpr *NE, CheckerContext &C)
const;
69 void checkPostStmt(
const CallExpr *CE, CheckerContext &C)
const;
70 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C)
const;
76 void PointerArithChecker::checkDeadSymbols(SymbolReaper &SR,
77 CheckerContext &C)
const {
94 if (isa<CXXMethodDecl>(FD))
99 return AllocKind::Array;
101 return AllocKind::SingleObject;
105 PointerArithChecker::getPointedRegion(
const MemRegion *Region,
106 CheckerContext &C)
const {
109 SVal S = State->getSVal(Region);
110 return S.getAsRegion();
117 const MemRegion *PointerArithChecker::getArrayRegion(
const MemRegion *Region,
120 CheckerContext &C)
const {
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))
148 void 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;
166 if (
const MemRegion *ArrayRegion =
167 getArrayRegion(Region, IsPolymorphic, Kind, C)) {
170 if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
172 BT_polyArray.reset(
new BuiltinBug(
173 this,
"Dangerous pointer arithmetic",
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>(
177 *BT_polyArray, BT_polyArray->getDescription(), N);
179 R->markInteresting(ArrayRegion);
180 C.emitReport(std::move(R));
185 if (Kind == AllocKind::Reinterpreted)
189 if (Kind != AllocKind::SingleObject &&
190 Region->getKind() == MemRegion::Kind::SymbolicRegionKind)
193 if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
194 if (!BT_pointerArith)
195 BT_pointerArith.reset(
new BuiltinBug(
this,
"Dangerous pointer arithmetic",
196 "Pointer arithmetic on non-array " 197 "variables relies on memory layout, " 198 "which is dangerous."));
199 auto R = std::make_unique<PathSensitiveBugReport>(
200 *BT_pointerArith, BT_pointerArith->getDescription(), N);
202 R->markInteresting(Region);
203 C.emitReport(std::move(R));
207 void PointerArithChecker::initAllocIdentifiers(
ASTContext &C)
const {
208 if (!AllocFunctions.empty())
210 AllocFunctions.insert(&C.
Idents.
get(
"alloca"));
211 AllocFunctions.insert(&C.
Idents.
get(
"malloc"));
212 AllocFunctions.insert(&C.
Idents.
get(
"realloc"));
213 AllocFunctions.insert(&C.
Idents.
get(
"calloc"));
214 AllocFunctions.insert(&C.
Idents.
get(
"valloc"));
217 void PointerArithChecker::checkPostStmt(
const CallExpr *CE,
218 CheckerContext &C)
const {
224 initAllocIdentifiers(C.getASTContext());
225 if (AllocFunctions.count(FunI) == 0)
228 SVal SV = C.getSVal(CE);
229 const MemRegion *Region = SV.getAsRegion();
236 State = State->set<RegionState>(Region, AllocKind::Array);
237 C.addTransition(State);
240 void PointerArithChecker::checkPostStmt(
const CXXNewExpr *NE,
241 CheckerContext &C)
const {
249 SVal AllocedVal = C.getSVal(NE);
250 const MemRegion *Region = AllocedVal.getAsRegion();
253 State = State->set<RegionState>(Region,
Kind);
254 C.addTransition(State);
257 void PointerArithChecker::checkPostStmt(
const CastExpr *CE,
258 CheckerContext &C)
const {
264 SVal CastedVal = C.getSVal(CastedExpr);
266 const MemRegion *Region = CastedVal.getAsRegion();
271 State = State->set<RegionState>(Region, AllocKind::Reinterpreted);
272 C.addTransition(State);
275 void PointerArithChecker::checkPreStmt(
const CastExpr *CE,
276 CheckerContext &C)
const {
277 if (CE->
getCastKind() != CastKind::CK_ArrayToPointerDecay)
282 SVal CastedVal = C.getSVal(CastedExpr);
284 const MemRegion *Region = CastedVal.getAsRegion();
288 if (
const AllocKind *
Kind = State->get<RegionState>(Region)) {
289 if (*
Kind == AllocKind::Array || *
Kind == AllocKind::Reinterpreted)
292 State = State->set<RegionState>(Region, AllocKind::Array);
293 C.addTransition(State);
296 void PointerArithChecker::checkPreStmt(
const UnaryOperator *UOp,
297 CheckerContext &C)
const {
300 reportPointerArithMisuse(UOp->
getSubExpr(), C,
true);
304 CheckerContext &C)
const {
305 SVal Idx = C.getSVal(SubsExpr->
getIdx());
308 if (Idx.isZeroConstant())
314 reportPointerArithMisuse(SubsExpr->
getBase(), C);
318 CheckerContext &C)
const {
320 if (!BOp->
isAdditiveOp() && OpKind != BO_AddAssign && OpKind != BO_SubAssign)
328 SVal RHSVal = C.getSVal(Rhs);
329 if (State->isNull(RHSVal).isConstrainedTrue())
335 SVal LHSVal = C.getSVal(Lhs);
336 if (State->isNull(LHSVal).isConstrainedTrue())
338 reportPointerArithMisuse(Rhs, C);
342 void ento::registerPointerArithChecker(CheckerManager &mgr) {
343 mgr.registerChecker<PointerArithChecker>();
346 bool ento::shouldRegisterPointerArithChecker(
const LangOptions &LO) {
Represents a function declaration or definition.
Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be placed into a PointerUnion...
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)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
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.
bool NE(InterpState &S, CodePtr OpPC)
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.