Skip to content
Snippets Groups Projects
Commit 73669ab6 authored by Devin Coughlin's avatar Devin Coughlin
Browse files

[analyzer] Remove ObjCContainersChecker size information when a CFMutableArrayRef escapes

Update ObjCContainersChecker to be notified when pointers escape so it can
remove size information for escaping CFMutableArrayRefs. When such pointers
escape, un-analyzed code could mutate the array and cause the size information
to be incorrect.

rdar://problem/19406485


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@239709 91177308-0d34-0410-b5e6-96231b3b80d8
parent 131d93e5
No related branches found
No related tags found
No related merge requests found
...@@ -29,7 +29,8 @@ using namespace ento; ...@@ -29,7 +29,8 @@ using namespace ento;
namespace { namespace {
class ObjCContainersChecker : public Checker< check::PreStmt<CallExpr>, class ObjCContainersChecker : public Checker< check::PreStmt<CallExpr>,
check::PostStmt<CallExpr> > { check::PostStmt<CallExpr>,
check::PointerEscape> {
mutable std::unique_ptr<BugType> BT; mutable std::unique_ptr<BugType> BT;
inline void initBugType() const { inline void initBugType() const {
if (!BT) if (!BT)
...@@ -52,6 +53,10 @@ public: ...@@ -52,6 +53,10 @@ public:
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
ProgramStateRef checkPointerEscape(ProgramStateRef State,
const InvalidatedSymbols &Escaped,
const CallEvent *Call,
PointerEscapeKind Kind) const;
}; };
} // end anonymous namespace } // end anonymous namespace
...@@ -146,6 +151,24 @@ void ObjCContainersChecker::checkPreStmt(const CallExpr *CE, ...@@ -146,6 +151,24 @@ void ObjCContainersChecker::checkPreStmt(const CallExpr *CE,
} }
} }
ProgramStateRef
ObjCContainersChecker::checkPointerEscape(ProgramStateRef State,
const InvalidatedSymbols &Escaped,
const CallEvent *Call,
PointerEscapeKind Kind) const {
for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
E = Escaped.end();
I != E; ++I) {
SymbolRef Sym = *I;
// When a symbol for a mutable array escapes, we can't reason precisely
// about its size any more -- so remove it from the map.
// Note that we aren't notified here when a CFMutableArrayRef escapes as a
// CFArrayRef. This is because CFArrayRef is typedef'd as a pointer to a
// const-qualified type.
State = State->remove<ArraySizeMap>(Sym);
}
return State;
}
/// Register checker. /// Register checker.
void ento::registerObjCContainersChecker(CheckerManager &mgr) { void ento::registerObjCContainersChecker(CheckerManager &mgr) {
mgr.registerChecker<ObjCContainersChecker>(); mgr.registerChecker<ObjCContainersChecker>();
......
...@@ -19,6 +19,7 @@ typedef struct { ...@@ -19,6 +19,7 @@ typedef struct {
} CFArrayCallBacks; } CFArrayCallBacks;
typedef const struct __CFArray * CFArrayRef; typedef const struct __CFArray * CFArrayRef;
CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks); CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks);
typedef struct __CFArray * CFMutableArrayRef;
typedef const struct __CFString * CFStringRef; typedef const struct __CFString * CFStringRef;
enum { enum {
kCFNumberSInt8Type = 1, kCFNumberSInt8Type = 1,
...@@ -202,3 +203,24 @@ void TestConst(CFArrayRef A, CFIndex sIndex, void* x[]) { ...@@ -202,3 +203,24 @@ void TestConst(CFArrayRef A, CFIndex sIndex, void* x[]) {
void TestNullArray() { void TestNullArray() {
CFArrayGetValueAtIndex(0, 0); CFArrayGetValueAtIndex(0, 0);
} }
void ArrayRefMutableEscape(CFMutableArrayRef a);
void ArrayRefEscape(CFArrayRef a);
void TestCFMutableArrayRefEscapeViaMutableArgument(CFMutableArrayRef a) {
CFIndex aLen = CFArrayGetCount(a);
ArrayRefMutableEscape(a);
// ArrayRefMutableEscape could mutate a to make it have
// at least aLen + 1 elements, so do not report an error here.
CFArrayGetValueAtIndex(a, aLen);
}
void TestCFMutableArrayRefEscapeViaImmutableArgument(CFMutableArrayRef a) {
CFIndex aLen = CFArrayGetCount(a);
ArrayRefEscape(a);
// ArrayRefEscape is declared to take a CFArrayRef (i.e, an immutable array)
// so we assume it does not change the length of a.
CFArrayGetValueAtIndex(a, aLen); // expected-warning {{Index is out of bounds}}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment