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 wxMacCocoaAutorelease( void* obj );
void* wxMacCocoaRetain( 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 #endif
// _WX_PRIVATE_CORE_H_ // _WX_PRIVATE_CORE_H_

View File

@@ -160,11 +160,13 @@ private:
OSXWebViewPtr m_webView; 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, // we may use this later to setup our own mouse events,
// so leave it in for now. // so leave it in for now.
void* m_webKitCtrlEventHandler; 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 class WXDLLIMPEXP_WEBVIEW wxWebViewFactoryWebKit : public wxWebViewFactory

View File

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

View File

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

View File

@@ -3563,11 +3563,14 @@ bool wxWidgetCocoaImpl::EnableTouchEvents(int eventsMask)
} }
else // We do want to have gesture events. 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 wxCocoaGestures::StoreForObject
( (
this, this,
new wxCocoaGesturesImpl(this, m_osxView, eventsMask) new wxCocoaGesturesImpl(this, m_osxView, eventsMask)
); );
#endif
[m_osxView setAcceptsTouchEvents:YES]; [m_osxView setAcceptsTouchEvents:YES];
} }

View File

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

View File

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