26 using namespace clang;
30 class ObjCContainersChecker :
public Checker< check::PreStmt<CallExpr>,
31 check::PostStmt<CallExpr>,
32 check::PointerEscape> {
33 mutable std::unique_ptr<BugType> BT;
34 inline void initBugType()
const {
36 BT.reset(
new BugType(
this,
"CFArray API",
40 inline SymbolRef getArraySym(
const Expr *E, CheckerContext &C)
const {
42 SymbolRef ArraySym = ArrayRef.getAsSymbol();
46 void addSizeInfo(
const Expr *Array,
const Expr *Size,
47 CheckerContext &C)
const;
51 static void *getTag() {
static int Tag;
return &Tag; }
53 void checkPostStmt(
const CallExpr *CE, CheckerContext &C)
const;
54 void checkPreStmt(
const CallExpr *CE, CheckerContext &C)
const;
61 const char *NL,
const char *Sep)
const;
68 void ObjCContainersChecker::addSizeInfo(
const Expr *Array,
const Expr *Size,
69 CheckerContext &C)
const {
71 SVal SizeV = C.getSVal(Size);
73 if (SizeV.isUnknownOrUndef())
78 SymbolRef ArraySym = ArrayRef.getAsSymbol();
83 State->set<ArraySizeMap>(ArraySym, SizeV.castAs<DefinedSVal>()));
86 void ObjCContainersChecker::checkPostStmt(
const CallExpr *CE,
87 CheckerContext &C)
const {
88 StringRef Name = C.getCalleeName(CE);
93 if (Name.equals(
"CFArrayCreate")) {
99 addSizeInfo(CE, CE->
getArg(2), C);
103 if (Name.equals(
"CFArrayGetCount")) {
104 addSizeInfo(CE->
getArg(0), CE, C);
109 void ObjCContainersChecker::checkPreStmt(
const CallExpr *CE,
110 CheckerContext &C)
const {
111 StringRef Name = C.getCalleeName(CE);
116 if (Name.equals(
"CFArrayGetValueAtIndex")) {
122 SymbolRef ArraySym = getArraySym(ArrayExpr, C);
126 const DefinedSVal *Size = State->get<ArraySizeMap>(ArraySym);
133 SVal IdxVal = C.getSVal(IdxExpr);
134 if (IdxVal.isUnknownOrUndef())
136 DefinedSVal Idx = IdxVal.castAs<DefinedSVal>();
141 ProgramStateRef StOutBound = State->assumeInBound(Idx, *Size,
false, T);
142 if (StOutBound && !StInBound) {
143 ExplodedNode *N = C.generateErrorNode(StOutBound);
147 auto R = llvm::make_unique<BugReport>(*BT,
"Index is out of bounds", N);
149 bugreporter::trackExpressionValue(N, IdxExpr, *R,
151 C.emitReport(std::move(R));
162 for (
const auto &Sym : Escaped) {
168 State = State->remove<ArraySizeMap>(Sym);
174 const char *NL,
const char *Sep)
const {
175 ArraySizeMapTy Map = State->get<ArraySizeMap>();
179 OS << Sep <<
"ObjC container sizes :" << NL;
181 OS << I.first <<
" : " << I.second << NL;
186 void ento::registerObjCContainersChecker(CheckerManager &mgr) {
187 mgr.registerChecker<ObjCContainersChecker>();
190 bool ento::shouldRegisterObjCContainersChecker(
const LangOptions &LO) {
const char *const CoreFoundationObjectiveC
A (possibly-)qualified type.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
const SymExpr * SymbolRef
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
This represents one expression.
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
Dataflow Directional Tag Classes.
PointerEscapeKind
Describes the different reasons a pointer escapes during analysis.
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
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]).