diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp index 2a677bc3dd08..0b16b87be3b4 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp @@ -56,18 +56,8 @@ public: }; } // end anonymous namespace -// Array state stores the array size on creation (allocation). -// Size might be an unsigned or a symbol. -struct ArraySize { - SVal NLSize; - ArraySize(SVal s) : NLSize(s) {} - void Profile(llvm::FoldingSetNodeID &ID) const { - NLSize.Profile(ID); - } -}; - // ProgramState trait - a map from array symbol to it's state. -typedef llvm::ImmutableMap ArraySizeM; +typedef llvm::ImmutableMap ArraySizeM; namespace { struct ArraySizeMap {}; } namespace clang { namespace ento { @@ -91,18 +81,20 @@ void ObjCContainersChecker::addSizeInfo(const Expr *Array, const Expr *Size, if (!ArraySym) return; - C.addTransition(State->set(ArraySym, SizeV)); + C.addTransition(State->set(ArraySym, cast(SizeV))); return; } void ObjCContainersChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { StringRef Name = C.getCalleeName(CE); - if (Name.empty()) + if (Name.empty() || CE->getNumArgs() < 1) return; // Add array size information to the state. if (Name.equals("CFArrayCreate")) { + if (CE->getNumArgs() < 3) + return; // Note, we can visit the Create method in the post-visit because // the CFIndex parameter is passed in by value and will not be invalidated // by the call. @@ -119,7 +111,7 @@ void ObjCContainersChecker::checkPostStmt(const CallExpr *CE, void ObjCContainersChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { StringRef Name = C.getCalleeName(CE); - if (Name.empty()) + if (Name.empty() || CE->getNumArgs() < 2) return; // Check the array access. @@ -128,20 +120,22 @@ void ObjCContainersChecker::checkPreStmt(const CallExpr *CE, // Retrieve the size. // Find out if we saw this array symbol before and have information about it. const Expr *ArrayExpr = CE->getArg(0); - const SVal *SizeVal = State->get(getArraySym(ArrayExpr, C)); - if (!SizeVal) + const DefinedSVal *Size = + State->get(getArraySym(ArrayExpr, C)); + if (!Size) return; - DefinedOrUnknownSVal Size = cast(*SizeVal); // Get the index. const Expr *IdxExpr = CE->getArg(1); SVal IdxVal = State->getSVal(IdxExpr, C.getLocationContext()); - DefinedOrUnknownSVal Idx = cast(IdxVal); + if (IdxVal.isUnknownOrUndef()) + return; + DefinedSVal Idx = cast(IdxVal); // Now, check if 'Idx in [0, Size-1]'. const QualType T = IdxExpr->getType(); - ProgramStateRef StInBound = State->assumeInBound(Idx, Size, true, T); - ProgramStateRef StOutBound = State->assumeInBound(Idx, Size, false, T); + ProgramStateRef StInBound = State->assumeInBound(Idx, *Size, true, T); + ProgramStateRef StOutBound = State->assumeInBound(Idx, *Size, false, T); if (StOutBound && !StInBound) { ExplodedNode *N = C.generateSink(StOutBound); if (!N) diff --git a/clang/test/Analysis/CFContainers.mm b/clang/test/Analysis/CFContainers.mm index 4912054882eb..e8166eba8dc8 100644 --- a/clang/test/Analysis/CFContainers.mm +++ b/clang/test/Analysis/CFContainers.mm @@ -158,7 +158,7 @@ void OutOfBoundsZiro(const void ** input, CFIndex S) { const void *s1 = CFArrayGetValueAtIndex(array, 0); // expected-warning {{Index is out of bounds}} } -void TestGetCount(CFArrayRef A, CFIndex sIndex, CFIndex badIndex) { +void TestGetCount(CFArrayRef A, CFIndex sIndex) { CFIndex sCount = CFArrayGetCount(A); if (sCount > sIndex) const void *s1 = CFArrayGetValueAtIndex(A, sIndex); @@ -183,3 +183,18 @@ void TestPointerToArray(int *elems, void *p1, void *p2, void *p3, unsigned count CFArrayCreate(0, (const void **) &cc, count, 0); // expected-warning {{The first argument to 'CFArrayCreate' must be a C array of pointer-sized}} CFArrayCreate(0, (const void **) cc, count, 0); // expected-warning {{The first argument to 'CFArrayCreate' must be a C array of pointer-sized}} } + +void TestUndef(CFArrayRef A, CFIndex sIndex, void* x[]) { + unsigned undefVal; + const void *s1 = CFArrayGetValueAtIndex(A, undefVal); + + unsigned undefVal2; + CFArrayRef B = CFArrayCreate(0, (const void **) &x, undefVal2, 0); + const void *s2 = CFArrayGetValueAtIndex(B, 2); +} + +void TestConst(CFArrayRef A, CFIndex sIndex, void* x[]) { + CFArrayRef B = CFArrayCreate(0, (const void **) &x, 4, 0); + const void *s1 = CFArrayGetValueAtIndex(B, 2); + +}