r180234 - [analyzer] Fix a crash in RetainCountChecker - we should not rely on CallEnter::getCallExpr to return non-NULL

Anna Zaks ganna at apple.com
Wed Apr 24 17:41:33 PDT 2013


Author: zaks
Date: Wed Apr 24 19:41:32 2013
New Revision: 180234

URL: http://llvm.org/viewvc/llvm-project?rev=180234&view=rev
Log:
[analyzer] Fix a crash in RetainCountChecker - we should not rely on CallEnter::getCallExpr to return non-NULL

We get a CallEnter with a null expression, when processing a destructor. All other users of
CallEnter::getCallExpr work fine with null as return value.

(Addresses PR15832, Thanks to Jordan for reducing the test case!)

Modified:
    cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
    cfe/trunk/test/Analysis/retain-release.mm

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp?rev=180234&r1=180233&r2=180234&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp Wed Apr 24 19:41:32 2013
@@ -2192,7 +2192,7 @@ GetAllocationSite(ProgramStateManager& S
     if (!InitMethodContext)
       if (Optional<CallEnter> CEP = N->getLocation().getAs<CallEnter>()) {
         const Stmt *CE = CEP->getCallExpr();
-        if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(CE)) {
+        if (const ObjCMessageExpr *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) {
           const Stmt *RecExpr = ME->getInstanceReceiver();
           if (RecExpr) {
             SVal RecV = St->getSVal(RecExpr, NContext);

Modified: cfe/trunk/test/Analysis/retain-release.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release.mm?rev=180234&r1=180233&r2=180234&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/retain-release.mm (original)
+++ cfe/trunk/test/Analysis/retain-release.mm Wed Apr 24 19:41:32 2013
@@ -83,6 +83,7 @@ typedef UInt32 CFStringEncoding;
 enum {
 kCFStringEncodingMacRoman = 0,     kCFStringEncodingWindowsLatin1 = 0x0500,     kCFStringEncodingISOLatin1 = 0x0201,     kCFStringEncodingNextStepLatin = 0x0B01,     kCFStringEncodingASCII = 0x0600,     kCFStringEncodingUnicode = 0x0100,     kCFStringEncodingUTF8 = 0x08000100,     kCFStringEncodingNonLossyASCII = 0x0BFF      ,     kCFStringEncodingUTF16 = 0x0100,     kCFStringEncodingUTF16BE = 0x10000100,     kCFStringEncodingUTF16LE = 0x14000100,      kCFStringEncodingUTF32 = 0x0c000100,     kCFStringEncodingUTF32BE = 0x18000100,     kCFStringEncodingUTF32LE = 0x1c000100  };
 extern CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding);
+extern CFStringRef CFStringCreateCopy(CFAllocatorRef alloc, CFStringRef theString);
 typedef double CFTimeInterval;
 typedef CFTimeInterval CFAbsoluteTime;
 extern CFAbsoluteTime CFAbsoluteTimeGetCurrent(void);
@@ -269,7 +270,6 @@ extern void CGContextDrawLinearGradient(
     CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint,
     CGGradientDrawingOptions options);
 extern CGColorSpaceRef CGColorSpaceCreateDeviceRGB(void);
-
 //===----------------------------------------------------------------------===//
 // Test cases.
 //===----------------------------------------------------------------------===//
@@ -408,3 +408,56 @@ void testCallback() {
 }
 @end
 
+//===----------------------------------------------------------------------===//
+// Don't crash on getting a null expression from CallEnter corresponding to a
+// destructor.
+//===----------------------------------------------------------------------===//
+
+template <typename X>
+class Holder {
+public:
+	Holder() throw();
+	~Holder() throw() {}
+	X* get() const throw();
+	void reset(X* p) throw();
+private:
+	X* ptr_;
+};
+
+template<typename X>
+inline
+Holder<X>::Holder() throw()
+: ptr_(0){}
+
+template <typename X>
+inline
+X* Holder<X>::get() const throw() {
+	return ptr_;
+}
+
+template <typename X>
+inline
+void Holder<X>::reset(X* p) throw() {
+	if (ptr_ != p) {
+		if (ptr_ != 0) {
+			::CFRelease( ptr_ );
+		}
+		ptr_ = p;
+	}
+}
+
+class radar13722286 {
+public:
+  radar13722286() {}
+private:
+	void			PrepareBitmap();
+	Holder<const struct __CFString>	mStr;
+};
+
+void	radar13722286::PrepareBitmap() {
+	if (mStr.get() != 0) {
+		Holder<const struct __CFString> str1;
+		mStr.reset( CFStringCreateCopy( 0, str1.get() ) ); //expected-warning {{Potential leak of an object}}
+	}
+}
+





More information about the cfe-commits mailing list