36 static inline void Profile(AllocKind
X, FoldingSetNodeID &ID) {
37 ID.AddInteger(
static_cast<int>(
X));
43class 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> {
55 bool PointedNeeded =
false)
const;
58 mutable std::unique_ptr<BuiltinBug> BT_pointerArith;
59 mutable std::unique_ptr<BuiltinBug> BT_polyArray;
60 mutable llvm::SmallSet<IdentifierInfo *, 8> AllocFunctions;
76void 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)) {
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)
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));
207void 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"));
217void PointerArithChecker::checkPostStmt(
const CallExpr *CE,
224 initAllocIdentifiers(
C.getASTContext());
225 if (AllocFunctions.count(FunI) == 0)
228 SVal SV =
C.getSVal(CE);
236 State = State->set<RegionState>(Region, AllocKind::Array);
237 C.addTransition(State);
240void PointerArithChecker::checkPostStmt(
const CXXNewExpr *NE,
246 AllocKind
Kind = getKindOfNewOp(NE, FD);
249 SVal AllocedVal =
C.getSVal(NE);
253 State = State->set<RegionState>(Region,
Kind);
254 C.addTransition(State);
257void PointerArithChecker::checkPostStmt(
const CastExpr *CE,
264 SVal CastedVal =
C.getSVal(CastedExpr);
271 State = State->set<RegionState>(Region, AllocKind::Reinterpreted);
272 C.addTransition(State);
275void PointerArithChecker::checkPreStmt(
const CastExpr *CE,
277 if (CE->
getCastKind() != CastKind::CK_ArrayToPointerDecay)
282 SVal CastedVal =
C.getSVal(CastedExpr);
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);
296void PointerArithChecker::checkPreStmt(
const UnaryOperator *UOp,
300 reportPointerArithMisuse(UOp->
getSubExpr(),
C,
true);
314 reportPointerArithMisuse(SubsExpr->
getBase(),
C);
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);
346bool ento::shouldRegisterPointerArithChecker(
const CheckerManager &mgr) {
static CompilationDatabasePluginRegistry::Add< FixedCompilationDatabasePlugin > X("fixed-compilation-database", "Reads plain-text flags file")
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)
@ C
Languages that the frontend can parse and compile.
YAML serialization mapping.
static void Profile(AllocKind X, FoldingSetNodeID &ID)