Fix macOS memory leaks, also avoid false positive warnings from clang analyzer

__clang_analyzer__ is a constant that only is defined during analyze build, this helps avoiding false positives as long as there is no specific way to silence analyzer messages
This commit is contained in:
Stefan Csomor
2019-04-21 23:52:37 +02:00
parent d0a84a6266
commit 5020a810db
7 changed files with 143 additions and 47 deletions

View File

@@ -1013,6 +1013,83 @@ void wxMacCocoaRelease( void* obj );
void wxMacCocoaAutorelease( void* obj );
void* wxMacCocoaRetain( void* obj );
// shared_ptr like API for NSObject and subclasses
template <class T>
class wxNSObjRef
{
public:
typedef T element_type;
wxNSObjRef()
: m_ptr(NULL)
{
}
wxNSObjRef( T p )
: m_ptr(p)
{
}
wxNSObjRef( const wxNSObjRef& otherRef )
: m_ptr(wxMacCocoaRetain(otherRef.m_ptr))
{
}
wxNSObjRef& operator=( const wxNSObjRef& otherRef )
{
if (this != &otherRef)
{
wxMacCocoaRetain(otherRef.m_ptr);
wxMacCocoaRelease(m_ptr);
m_ptr = otherRef.m_ptr;
}
return *this;
}
wxNSObjRef& operator=( T ptr )
{
if (get() != ptr)
{
wxMacCocoaRetain(ptr);
wxMacCocoaRelease(m_ptr);
m_ptr = ptr;
}
return *this;
}
T get() const
{
return m_ptr;
}
operator T() const
{
return m_ptr;
}
T operator->() const
{
return m_ptr;
}
void reset( T p = NULL )
{
wxMacCocoaRelease(m_ptr);
m_ptr = p; // Automatic conversion should occur
}
// Release the pointer, i.e. give up its ownership.
T release()
{
T p = m_ptr;
m_ptr = NULL;
return p;
}
protected:
T m_ptr;
};
#endif
// _WX_PRIVATE_CORE_H_

View File

@@ -160,11 +160,13 @@ private:
OSXWebViewPtr m_webView;
WX_NSObject m_loadDelegate;
WX_NSObject m_policyDelegate;
WX_NSObject m_UIDelegate;
// we may use this later to setup our own mouse events,
// so leave it in for now.
void* m_webKitCtrlEventHandler;
//It should be WebView*, but WebView is an Objective-C class
//TODO: look into using DECLARE_WXCOCOA_OBJC_CLASS rather than this.
};
class WXDLLIMPEXP_WEBVIEW wxWebViewFactoryWebKit : public wxWebViewFactory

View File

@@ -374,17 +374,17 @@ CGImageRef wxOSXCreateCGImageFromImage( WXImage nsimage, double *scaleptr )
#if wxOSX_USE_COCOA
static NSCursor* wxGetStockCursor( short sIndex )
static NSCursor* wxCreateStockCursor( short sIndex )
{
ClassicCursor* pCursor = &gMacCursors[sIndex];
//Classic mac cursors are 1bps 16x16 black and white with a
//identical mask that is 1 for on and 0 for off
NSImage *theImage = [[NSImage alloc] initWithSize:NSMakeSize(16.0,16.0)];
ClassicCursor* pCursor = &gMacCursors[sIndex];
wxNSObjRef<NSImage*> theImage( [[NSImage alloc] initWithSize:NSMakeSize(16.0,16.0)] );
//NSCursor takes an NSImage takes a number of Representations - here
//we need only one for the raw data
NSBitmapImageRep *theRep = [[NSBitmapImageRep alloc]
wxNSObjRef<NSBitmapImageRep*> theRep( [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes: NULL // Tell Cocoa to allocate the planes for us.
pixelsWide: 16 // All classic cursors are 16x16
pixelsHigh: 16
@@ -394,16 +394,16 @@ static NSCursor* wxGetStockCursor( short sIndex )
isPlanar: YES // Use a separate array for each sample
colorSpaceName: NSCalibratedWhiteColorSpace // 0.0=black 1.0=white
bytesPerRow: 2 // Rows in each plane are on 2-byte boundaries (no pad)
bitsPerPixel: 1]; // same as bitsPerSample since data is planar
bitsPerPixel: 1] ); // same as bitsPerSample since data is planar
// Ensure that Cocoa allocated 2 and only 2 of the 5 possible planes
unsigned char *planes[5];
[theRep getBitmapDataPlanes:planes];
wxASSERT(planes[0] != NULL);
wxASSERT(planes[1] != NULL);
wxASSERT(planes[2] == NULL);
wxASSERT(planes[3] == NULL);
wxASSERT(planes[4] == NULL);
wxCHECK(planes[0] != NULL, nil);
wxCHECK(planes[1] != NULL, nil);
wxCHECK(planes[2] == NULL, nil);
wxCHECK(planes[3] == NULL, nil);
wxCHECK(planes[4] == NULL, nil);
// NOTE1: The Cursor's bits field is white=0 black=1.. thus the bitwise-not
// Why not use NSCalibratedBlackColorSpace? Because that reverses the
@@ -437,10 +437,6 @@ static NSCursor* wxGetStockCursor( short sIndex )
hotSpot:NSMakePoint(pCursor->hotspot[1], pCursor->hotspot[0])
];
//do the usual cleanups
[theRep release];
[theImage release];
//return the new cursor
return theCursor;
}
@@ -460,7 +456,7 @@ WX_NSCursor wxMacCocoaCreateStockCursor( int cursor_type )
// according to the HIG
// cursor = [[NSCursor arrowCursor] retain];
// but for crossplatform compatibility we display a watch cursor
cursor = wxGetStockCursor(kwxCursorWatch);
cursor = wxCreateStockCursor(kwxCursorWatch);
break;
case wxCURSOR_IBEAM:
@@ -472,11 +468,11 @@ WX_NSCursor wxMacCocoaCreateStockCursor( int cursor_type )
break;
case wxCURSOR_SIZENWSE:
cursor = wxGetStockCursor(kwxCursorSizeNWSE);
cursor = wxCreateStockCursor(kwxCursorSizeNWSE);
break;
case wxCURSOR_SIZENESW:
cursor = wxGetStockCursor(kwxCursorSizeNESW);
cursor = wxCreateStockCursor(kwxCursorSizeNESW);
break;
case wxCURSOR_SIZEWE:
@@ -488,7 +484,7 @@ WX_NSCursor wxMacCocoaCreateStockCursor( int cursor_type )
break;
case wxCURSOR_SIZING:
cursor = wxGetStockCursor(kwxCursorSize);
cursor = wxCreateStockCursor(kwxCursorSize);
break;
case wxCURSOR_HAND:
@@ -496,47 +492,47 @@ WX_NSCursor wxMacCocoaCreateStockCursor( int cursor_type )
break;
case wxCURSOR_BULLSEYE:
cursor = wxGetStockCursor(kwxCursorBullseye);
cursor = wxCreateStockCursor(kwxCursorBullseye);
break;
case wxCURSOR_PENCIL:
cursor = wxGetStockCursor(kwxCursorPencil);
cursor = wxCreateStockCursor(kwxCursorPencil);
break;
case wxCURSOR_MAGNIFIER:
cursor = wxGetStockCursor(kwxCursorMagnifier);
cursor = wxCreateStockCursor(kwxCursorMagnifier);
break;
case wxCURSOR_NO_ENTRY:
cursor = wxGetStockCursor(kwxCursorNoEntry);
cursor = wxCreateStockCursor(kwxCursorNoEntry);
break;
case wxCURSOR_PAINT_BRUSH:
cursor = wxGetStockCursor(kwxCursorPaintBrush);
cursor = wxCreateStockCursor(kwxCursorPaintBrush);
break;
case wxCURSOR_POINT_LEFT:
cursor = wxGetStockCursor(kwxCursorPointLeft);
cursor = wxCreateStockCursor(kwxCursorPointLeft);
break;
case wxCURSOR_POINT_RIGHT:
cursor = wxGetStockCursor(kwxCursorPointRight);
cursor = wxCreateStockCursor(kwxCursorPointRight);
break;
case wxCURSOR_QUESTION_ARROW:
cursor = wxGetStockCursor(kwxCursorQuestionArrow);
cursor = wxCreateStockCursor(kwxCursorQuestionArrow);
break;
case wxCURSOR_BLANK:
cursor = wxGetStockCursor(kwxCursorBlank);
cursor = wxCreateStockCursor(kwxCursorBlank);
break;
case wxCURSOR_RIGHT_ARROW:
cursor = wxGetStockCursor(kwxCursorRightArrow);
cursor = wxCreateStockCursor(kwxCursorRightArrow);
break;
case wxCURSOR_SPRAYCAN:
cursor = wxGetStockCursor(kwxCursorRoller);
cursor = wxCreateStockCursor(kwxCursorRoller);
break;
case wxCURSOR_OPEN_HAND:
@@ -547,15 +543,21 @@ WX_NSCursor wxMacCocoaCreateStockCursor( int cursor_type )
cursor = [[NSCursor closedHandCursor] retain];
break;
case wxCURSOR_CHAR:
case wxCURSOR_ARROW:
cursor = [[NSCursor arrowCursor] retain];
break;
case wxCURSOR_CHAR:
case wxCURSOR_LEFT_BUTTON:
case wxCURSOR_RIGHT_BUTTON:
case wxCURSOR_MIDDLE_BUTTON:
default:
cursor = [[NSCursor arrowCursor] retain];
break;
}
if ( cursor == nil )
cursor = [[NSCursor arrowCursor] retain];
return cursor;
}

View File

@@ -254,6 +254,7 @@ public :
[windowMenuItem setSubmenu:windowMenu];
[windowMenu release];
[m_osxMenu addItem:windowMenuItem];
[windowMenuItem release];
}
return windowMenu;
}

View File

@@ -3563,11 +3563,14 @@ bool wxWidgetCocoaImpl::EnableTouchEvents(int eventsMask)
}
else // We do want to have gesture events.
{
// clang does not see that the owning object always destroys its extra field
#ifndef __clang_analyzer__
wxCocoaGestures::StoreForObject
(
this,
new wxCocoaGesturesImpl(this, m_osxView, eventsMask)
);
#endif
[m_osxView setAcceptsTouchEvents:YES];
}

View File

@@ -138,16 +138,22 @@ bool wxWebViewWebKit::Create(wxWindow *parent,
[m_webView setFrameLoadDelegate:loadDelegate];
m_loadDelegate = loadDelegate;
// this is used to veto page loads, etc.
WebViewPolicyDelegate* policyDelegate =
[[WebViewPolicyDelegate alloc] initWithWxWindow: this];
[m_webView setPolicyDelegate:policyDelegate];
m_policyDelegate = policyDelegate;
WebViewUIDelegate* uiDelegate =
[[WebViewUIDelegate alloc] initWithWxWindow: this];
[m_webView setUIDelegate:uiDelegate];
m_UIDelegate = uiDelegate;
#endif
//Register our own class for custom scheme handling
[NSURLProtocol registerClass:[WebViewCustomProtocol class]];
@@ -160,21 +166,13 @@ wxWebViewWebKit::~wxWebViewWebKit()
{
#if wxOSX_USE_IPHONE
#else
WebViewLoadDelegate* loadDelegate = [m_webView frameLoadDelegate];
WebViewPolicyDelegate* policyDelegate = [m_webView policyDelegate];
WebViewUIDelegate* uiDelegate = [m_webView UIDelegate];
[m_webView setFrameLoadDelegate: nil];
[m_webView setPolicyDelegate: nil];
[m_webView setUIDelegate: nil];
if (loadDelegate)
[loadDelegate release];
if (policyDelegate)
[policyDelegate release];
if (uiDelegate)
[uiDelegate release];
[m_loadDelegate release];
[m_policyDelegate release];
[m_UIDelegate release];
#endif
}
@@ -1033,7 +1031,15 @@ wxString nsErrorToWxHtmlError(NSError* error, wxWebViewNavigationError* out)
wxString wxpath = wxCFStringRef::AsString(path);
wxString scheme = wxCFStringRef::AsString([[request URL] scheme]);
// since canInitRequest has already checked whether this scheme is supported
// the hash map contains this entry, but to satisfy static code analysis
// suspecting nullptr dereference ...
#ifndef __clang_analyzer__
wxFSFile* file = g_stringHandlerMap[scheme]->GetFile(wxpath);
#else
wxFSFile* file = NULL;
#endif
if (!file)
{
@@ -1043,6 +1049,8 @@ wxString nsErrorToWxHtmlError(NSError* error, wxWebViewNavigationError* out)
[client URLProtocol:self didFailWithError:error];
[error release];
return;
}
@@ -1069,6 +1077,8 @@ wxString nsErrorToWxHtmlError(NSError* error, wxWebViewNavigationError* out)
//Notify that we have finished
[client URLProtocolDidFinishLoading:self];
[data release];
[response release];
}

View File

@@ -111,6 +111,7 @@ WX_NSWindow CreateFloatingWindow(wxWindow* wxWin)
void CloseFloatingWindow(WX_NSWindow nsWin)
{
[nsWin setReleasedWhenClosed:YES];
[nsWin close];
}