forked from OSchip/llvm-project
[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 llvm-svn: 239709
This commit is contained in:
parent
b11df184ad
commit
0bee1d7ff1
|
@ -29,7 +29,8 @@ using namespace ento;
|
|||
|
||||
namespace {
|
||||
class ObjCContainersChecker : public Checker< check::PreStmt<CallExpr>,
|
||||
check::PostStmt<CallExpr> > {
|
||||
check::PostStmt<CallExpr>,
|
||||
check::PointerEscape> {
|
||||
mutable std::unique_ptr<BugType> BT;
|
||||
inline void initBugType() const {
|
||||
if (!BT)
|
||||
|
@ -52,6 +53,10 @@ public:
|
|||
|
||||
void checkPostStmt(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
|
||||
|
||||
|
@ -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.
|
||||
void ento::registerObjCContainersChecker(CheckerManager &mgr) {
|
||||
mgr.registerChecker<ObjCContainersChecker>();
|
||||
|
|
|
@ -19,6 +19,7 @@ typedef struct {
|
|||
} CFArrayCallBacks;
|
||||
typedef const struct __CFArray * CFArrayRef;
|
||||
CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks);
|
||||
typedef struct __CFArray * CFMutableArrayRef;
|
||||
typedef const struct __CFString * CFStringRef;
|
||||
enum {
|
||||
kCFNumberSInt8Type = 1,
|
||||
|
@ -202,3 +203,24 @@ void TestConst(CFArrayRef A, CFIndex sIndex, void* x[]) {
|
|||
void TestNullArray() {
|
||||
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}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue