void runCheckersForPostStmt(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const Stmt *S,
- ExprEngine &Eng) {
- runCheckersForStmt(/*isPreVisit=*/false, Dst, Src, S, Eng);
+ ExprEngine &Eng,
+ bool wasInlined = false) {
+ runCheckersForStmt(/*isPreVisit=*/false, Dst, Src, S, Eng, wasInlined);
}
/// \brief Run checkers for visiting Stmts.
void runCheckersForStmt(bool isPreVisit,
ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
- const Stmt *S, ExprEngine &Eng);
+ const Stmt *S, ExprEngine &Eng,
+ bool wasInlined = false);
/// \brief Run checkers for pre-visiting obj-c messages.
void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst,
NodeBuilder &NB;
public:
+ /// If we are post visiting a call, this flag will be set if the
+ /// call was inlined. In all other cases it will be false.
+ const bool wasInlined;
+
CheckerContext(NodeBuilder &builder,
ExprEngine &eng,
ExplodedNode *pred,
- const ProgramPoint &loc)
+ const ProgramPoint &loc,
+ bool wasInlined = false)
: Eng(eng),
Pred(pred),
Changed(false),
Location(loc),
- NB(builder) {
+ NB(builder),
+ wasInlined(wasInlined) {
assert(Pred->getState() &&
"We should not call the checkers on an empty state.");
}
void RetainCountChecker::checkPostStmt(const CallExpr *CE,
CheckerContext &C) const {
+ if (C.wasInlined)
+ return;
+
// Get the callee.
ProgramStateRef state = C.getState();
const Expr *Callee = CE->getCallee();
const CheckersTy &Checkers;
const Stmt *S;
ExprEngine &Eng;
+ bool wasInlined;
CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
CheckStmtContext(bool isPreVisit, const CheckersTy &checkers,
- const Stmt *s, ExprEngine &eng)
- : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng) { }
+ const Stmt *s, ExprEngine &eng, bool wasInlined = false)
+ : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng),
+ wasInlined(wasInlined) {}
void runChecker(CheckerManager::CheckStmtFunc checkFn,
NodeBuilder &Bldr, ExplodedNode *Pred) {
ProgramPoint::PostStmtKind;
const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
Pred->getLocationContext(), checkFn.Checker);
- CheckerContext C(Bldr, Eng, Pred, L);
-
+ CheckerContext C(Bldr, Eng, Pred, L, wasInlined);
checkFn(S, C);
}
};
ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const Stmt *S,
- ExprEngine &Eng) {
+ ExprEngine &Eng,
+ bool wasInlined) {
CheckStmtContext C(isPreVisit, *getCachedStmtCheckersFor(S, isPreVisit),
- S, Eng);
+ S, Eng, wasInlined);
expandGraphWithCheckers(C, Dst, Src);
}
&Ctx);
SaveAndRestore<unsigned> CBISave(currentStmtIdx, calleeCtx->getIndex());
- getCheckerManager().runCheckersForPostStmt(Dst, N, CE, *this);
+ getCheckerManager().runCheckersForPostStmt(Dst, N, CE, *this,
+ /* wasInlined */ true);
// Enqueue the next element in the block.
for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I) {
[x retain];
[x release];
}
+
+//===----------------------------------------------------------------------===//
+// Test not applying "double effects" from inlining and RetainCountChecker summaries.
+// If we inline a call, we should already see its retain/release semantics.
+//===----------------------------------------------------------------------===//
+
+__attribute__((cf_returns_retained)) CFStringRef test_return_inline(CFStringRef x) {
+ CFRetain(x);
+ return x;
+}
+
+void test_test_return_inline(char *bytes) {
+ CFStringRef str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0);
+ // After this call, 'str' really has +2 reference count.
+ CFStringRef str2 = test_return_inline(str);
+ // After this call, 'str' really has a +1 reference count.
+ CFRelease(str);
+ // After this call, 'str2' and 'str' has a +0 reference count.
+ CFRelease(str2);
+}
+
+void test_test_return_inline_2(char *bytes) {
+ CFStringRef str = CFStringCreateWithCStringNoCopy(0, bytes, NSNEXTSTEPStringEncoding, 0); // expected-warning {{leak}}
+ // After this call, 'str' really has +2 reference count.
+ CFStringRef str2 = test_return_inline(str);
+ // After this call, 'str' really has a +1 reference count.
+ CFRelease(str);
+}
+
+
+
}
int rdar10553686_positive(void)
{
- NSObject* bar = static_objc_cast<NSObject*>([[NSObject alloc] init]); // expected-warning {{Potential leak}}
+ NSObject* bar = static_objc_cast<NSObject*>([[NSObject alloc] init]);
[bar release];
- [bar retain];
+ [bar retain]; // expected-warning {{used after it is released}}
return 0;
}