Skip to content

Commit

Permalink
Crash in FrameLoader::stopAllLoaders via [WebView dealloc] inside ~Ob…
Browse files Browse the repository at this point in the history
…jCEventListener

https://bugs.webkit.org/show_bug.cgi?id=197079

Reviewed by Darin Adler.

Source/WebKitLegacy/mac:

The crash was caused by the fact deleting a node could end up deleting Objective-C event listeners
some of which may be the last object holding onto WebView itself in the middle of running GC.

It's not generally safe to delete Objective-C objects defiend by client applications since
dealloc could execute arbitrary code, and for instance, try to execute JavaScript or load new page.

Fixed the bug by delaying the dealloc'ing of Objective event listeners via autorelease pool.

* DOM/ObjCEventListener.mm:
(WebCore::ObjCEventListener::~ObjCEventListener):

Tools:

Added a regression test. It hits a slightly different backtrace but of the same class of issues.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitLegacy/mac/DeallocWebViewInEventListener.mm: Added.


Canonical link: https://commits.webkit.org/211336@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@244459 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
rniwa committed Apr 19, 2019
1 parent 41104a4 commit b7cb953
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 0 deletions.
18 changes: 18 additions & 0 deletions Source/WebKitLegacy/mac/ChangeLog
@@ -1,3 +1,21 @@
2019-04-18 Ryosuke Niwa <rniwa@webkit.org>

Crash in FrameLoader::stopAllLoaders via [WebView dealloc] inside ~ObjCEventListener
https://bugs.webkit.org/show_bug.cgi?id=197079

Reviewed by Darin Adler.

The crash was caused by the fact deleting a node could end up deleting Objective-C event listeners
some of which may be the last object holding onto WebView itself in the middle of running GC.

It's not generally safe to delete Objective-C objects defiend by client applications since
dealloc could execute arbitrary code, and for instance, try to execute JavaScript or load new page.

Fixed the bug by delaying the dealloc'ing of Objective event listeners via autorelease pool.

* DOM/ObjCEventListener.mm:
(WebCore::ObjCEventListener::~ObjCEventListener):

2019-04-18 Jer Noble <jer.noble@apple.com>

Refactoring: Pull all fullscreen code out of Document and into its own helper class
Expand Down
3 changes: 3 additions & 0 deletions Source/WebKitLegacy/mac/DOM/ObjCEventListener.mm
Expand Up @@ -70,6 +70,9 @@
ObjCEventListener::~ObjCEventListener()
{
listenerMap->remove(m_listener.get());
// Avoid executing arbitrary code during GC; e.g. inside Node::~Node. Use CF* to be ARC safe.
CFRetain((__bridge CFTypeRef)m_listener.get());
CFAutorelease((__bridge CFTypeRef)m_listener.get());
}

void ObjCEventListener::handleEvent(ScriptExecutionContext&, Event& event)
Expand Down
12 changes: 12 additions & 0 deletions Tools/ChangeLog
@@ -1,3 +1,15 @@
2019-04-18 Ryosuke Niwa <rniwa@webkit.org>

Crash in FrameLoader::stopAllLoaders via [WebView dealloc] inside ~ObjCEventListener
https://bugs.webkit.org/show_bug.cgi?id=197079

Reviewed by Darin Adler.

Added a regression test. It hits a slightly different backtrace but of the same class of issues.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitLegacy/mac/DeallocWebViewInEventListener.mm: Added.

2019-04-18 Commit Queue <commit-queue@webkit.org>

Unreviewed, rolling out r244434.
Expand Down
4 changes: 4 additions & 0 deletions Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Expand Up @@ -672,6 +672,7 @@
9B62630C1F8C25C8007EE29B /* copy-url.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B62630B1F8C2510007EE29B /* copy-url.html */; };
9B7A37C41F8AEBA5004AA228 /* CopyURL.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9B7A37C21F8AEBA5004AA228 /* CopyURL.mm */; };
9B7D740F1F8378770006C432 /* paste-rtfd.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B7D740E1F8377E60006C432 /* paste-rtfd.html */; };
9BAD7F3E22690F2000F8DA66 /* DeallocWebViewInEventListener.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BAD7F3D22690F1400F8DA66 /* DeallocWebViewInEventListener.mm */; };
9BCB7C2820130600003E7C0C /* PasteHTML.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BCB7C2620130600003E7C0C /* PasteHTML.mm */; };
9BCD411A206DBCA3001D71BE /* mso-list-on-h4.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9BCD4119206D5ED7001D71BE /* mso-list-on-h4.html */; };
9BD4239A1E04BD9800200395 /* AttributedSubstringForProposedRangeWithImage.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BD423991E04BD9800200395 /* AttributedSubstringForProposedRangeWithImage.mm */; };
Expand Down Expand Up @@ -1935,6 +1936,7 @@
9B79164F1BD89D0D00D50B8F /* FirstResponderScrollingPosition.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FirstResponderScrollingPosition.mm; sourceTree = "<group>"; };
9B7A37C21F8AEBA5004AA228 /* CopyURL.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CopyURL.mm; sourceTree = "<group>"; };
9B7D740E1F8377E60006C432 /* paste-rtfd.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "paste-rtfd.html"; sourceTree = "<group>"; };
9BAD7F3D22690F1400F8DA66 /* DeallocWebViewInEventListener.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DeallocWebViewInEventListener.mm; sourceTree = "<group>"; };
9BCB7C2620130600003E7C0C /* PasteHTML.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PasteHTML.mm; sourceTree = "<group>"; };
9BCD4119206D5ED7001D71BE /* mso-list-on-h4.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "mso-list-on-h4.html"; sourceTree = "<group>"; };
9BD423991E04BD9800200395 /* AttributedSubstringForProposedRangeWithImage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AttributedSubstringForProposedRangeWithImage.mm; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2869,6 +2871,7 @@
children = (
9BD5111B1FE8E11600D2B630 /* AccessingPastedImage.mm */,
6B306105218A372900F5A802 /* ClosingWebView.mm */,
9BAD7F3D22690F1400F8DA66 /* DeallocWebViewInEventListener.mm */,
5CF540E82257E64B00E6BC0E /* DownloadThread.mm */,
5C6E27A6224EEBEA00128736 /* URLCanonicalization.mm */,
);
Expand Down Expand Up @@ -4069,6 +4072,7 @@
46A911592108E6780078D40D /* CustomUserAgent.mm in Sources */,
751B05D61F8EAC410028A09E /* DatabaseTrackerTest.mm in Sources */,
2DC4CF771D2D9DD800ECCC94 /* DataDetection.mm in Sources */,
9BAD7F3E22690F2000F8DA66 /* DeallocWebViewInEventListener.mm in Sources */,
518EE51D20A78D3600E024F3 /* DecidePolicyForNavigationAction.mm in Sources */,
2D1646E21D1862CD00015A1A /* DeferredViewInWindowStateChange.mm in Sources */,
46918EFC2237283C00468DFE /* DeviceOrientation.mm in Sources */,
Expand Down
@@ -0,0 +1,93 @@
/*
* Copyright (C) 2018 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/

#import "config.h"
#import "PlatformUtilities.h"
#import "WTFStringUtilities.h"

#import <Carbon/Carbon.h>
#import <WebKit/WebViewPrivate.h>
#import <wtf/RetainPtr.h>

extern "C" void JSSynchronousGarbageCollectForDebugging(JSContextRef);

#if JSC_OBJC_API_ENABLED

static bool didFinishLoad = false;
static bool didClose = false;
static RetainPtr<WebView> webView;

@interface DeallocWebViewInEventListenerLoadDelegate : NSObject <WebFrameLoadDelegate>
@end

@implementation DeallocWebViewInEventListenerLoadDelegate
- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
{
didFinishLoad = true;
}
@end

@interface DeallocWebViewInEventListener : NSObject <DOMEventListener>
@end

@implementation DeallocWebViewInEventListener
- (void)handleEvent:(DOMEvent *)event
{

}

- (void)dealloc
{
webView = nullptr;
[super dealloc];
didClose = true;
}
@end

namespace TestWebKitAPI {

TEST(WebKitLegacy, DeallocWebViewInEventListener)
{
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
webView = adoptNS([[WebView alloc] initWithFrame:NSMakeRect(0, 0, 400, 400) frameName:nil groupName:nil]);
auto loadDelegate = adoptNS([[DeallocWebViewInEventListenerLoadDelegate alloc] init]);
webView.get().frameLoadDelegate = loadDelegate.get();

[[webView mainFrame] loadHTMLString:@"<html><body></body></html>" baseURL:nil];
Util::run(&didFinishLoad);

auto listener = adoptNS([[DeallocWebViewInEventListener alloc] init]);
[[[webView mainFrameDocument] body] addEventListener:@"keypress" listener:listener.get() useCapture:NO];
listener = nullptr;
[webView close];
[pool drain];
}
Util::run(&didClose);
}

} // namespace TestWebKitAPI

#endif // ENABLE(JSC_OBJC_API)

0 comments on commit b7cb953

Please sign in to comment.