[cfe-commits] r162935 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp test/Analysis/inlining/assume-super-init-does-not-return-nil.m
Anna Zaks
ganna at apple.com
Thu Aug 30 12:40:53 PDT 2012
Author: zaks
Date: Thu Aug 30 14:40:52 2012
New Revision: 162935
URL: http://llvm.org/viewvc/llvm-project?rev=162935&view=rev
Log:
[analyzer] Do not propagate the [super init] could be nil assumption
from callee to caller.
radar://12109638
Added:
cfe/trunk/test/Analysis/inlining/assume-super-init-does-not-return-nil.m
Modified:
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h?rev=162935&r1=162934&r2=162935&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h Thu Aug 30 14:40:52 2012
@@ -100,6 +100,11 @@
return Pred->getStackFrame();
}
+ /// Returns true if the predecessor is within an inlined function/method.
+ bool isWithinInlined() {
+ return (getStackFrame() != 0);
+ }
+
BugReporter &getBugReporter() {
return Eng.getBugReporter();
}
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp?rev=162935&r1=162934&r2=162935&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp Thu Aug 30 14:40:52 2012
@@ -718,8 +718,8 @@
namespace {
/// \class ObjCNonNilReturnValueChecker
-/// \brief The checker restricts the return values of APIs known to never
-/// return nil.
+/// \brief The checker restricts the return values of APIs known to
+/// never (or almost never) return 'nil'.
class ObjCNonNilReturnValueChecker
: public Checker<check::PostObjCMessage> {
mutable bool Initialized;
@@ -732,9 +732,18 @@
};
}
+ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
+ ProgramStateRef State,
+ CheckerContext &C) {
+ SVal Val = State->getSVal(NonNullExpr, C.getLocationContext());
+ if (!isa<DefinedOrUnknownSVal>(Val))
+ return State;
+ return State->assume(cast<DefinedOrUnknownSVal>(Val), true);
+}
+
void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
CheckerContext &C)
- const {
+ const {
ProgramStateRef State = C.getState();
if (!Initialized) {
@@ -745,19 +754,34 @@
// Check the receiver type.
if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
+
+ // Assume that object returned from '[self init]' or '[super init]' is not
+ // 'nil' if we are processing an inlined function/method.
+ //
+ // A defensive callee will (and should) check if the object returned by
+ // '[super init]' is 'nil' before doing it's own initialization. However,
+ // since 'nil' is rarely returned in practice, we should not warn when the
+ // caller to the defensive constructor uses the object in contexts where
+ // 'nil' is not accepted.
+ if (C.isWithinInlined() &&
+ M.getDecl()->getMethodFamily() == OMF_init &&
+ M.isReceiverSelfOrSuper()) {
+ State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
+ }
+
+ // Objects returned from
+ // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
+ // are never 'nil'.
FoundationClass Cl = findKnownClass(Interface);
if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
Selector Sel = M.getSelector();
if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
// Go ahead and assume the value is non-nil.
- SVal Val = State->getSVal(M.getOriginExpr(), C.getLocationContext());
- if (!isa<DefinedOrUnknownSVal>(Val))
- return;
- State = State->assume(cast<DefinedOrUnknownSVal>(Val), true);
- C.addTransition(State);
+ State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
}
}
}
+ C.addTransition(State);
}
//===----------------------------------------------------------------------===//
Added: cfe/trunk/test/Analysis/inlining/assume-super-init-does-not-return-nil.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/inlining/assume-super-init-does-not-return-nil.m?rev=162935&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/inlining/assume-super-init-does-not-return-nil.m (added)
+++ cfe/trunk/test/Analysis/inlining/assume-super-init-does-not-return-nil.m Thu Aug 30 14:40:52 2012
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -analyze -analyzer-ipa=dynamic-bifurcate -analyzer-checker=core,osx -verify %s
+
+typedef signed char BOOL;
+
+ at protocol NSObject - (BOOL)isEqual:(id)object; @end
+ at interface NSObject <NSObject> {}
++(id)alloc;
++(id)new;
+-(id)init;
+-(id)autorelease;
+-(id)copy;
+- (Class)class;
+-(id)retain;
+- (oneway void)release;
+ at end
+
+ at interface Cell : NSObject {
+ int x;
+}
+- (id) init;
+- (void)test;
+ at end
+
+ at implementation Cell
+- (id) init {
+ if ((self = [super init])) {
+ ;
+ }
+ // Test that this is being analyzed.
+ int m;
+ m = m + 1; //expected-warning {{The left operand of '+' is a garbage value}}
+ return self;
+}
+
+// Make sure that we do not propagate the 'nil' check from inlined 'init' to 'test'.
+- (void) test {
+ Cell *newCell = [[Cell alloc] init];
+ newCell->x = 5; // no-warning
+ [newCell release];
+}
+ at end
More information about the cfe-commits
mailing list