Diff
Modified: trunk/Source/WebCore/ChangeLog (199833 => 199834)
--- trunk/Source/WebCore/ChangeLog 2016-04-21 20:23:28 UTC (rev 199833)
+++ trunk/Source/WebCore/ChangeLog 2016-04-21 21:00:02 UTC (rev 199834)
@@ -1,3 +1,27 @@
+2016-04-21 Keith Miller <keith_mil...@apple.com>
+
+ WebScriptObject description swizzler should work in a multi-threaded world
+ https://bugs.webkit.org/show_bug.cgi?id=156808
+
+ Reviewed by Geoffrey Garen.
+
+ A WebKit legacy API user might be running Objective-C code on another thread.
+ Since we don't want to corrupt other thread's NSObject description method
+ we use TLS to record if we are in the stringValue function. As an attempt to
+ preserve any user swizzling we update the non-stringValue NSObject description
+ method on each call to stringValue if it has changed. Additionally, the TLS
+ needs to be a int because the user might call into stringValue, back into JS,
+ then back into stringValue. If the TLS was a boolean then it would be unset
+ at that point so when we return into the first stringValue call we would call
+ the original NSObject description method rather than our override.
+
+ Test added to API tests: WebKit1.WebScriptObjectDescription
+
+ * bridge/objc/objc_instance.mm:
+ (-[NSObject _web_description]):
+ (ObjcInstance::stringValue):
+ (swizzleNSObjectDescription): Deleted.
+
2016-04-21 Beth Dakin <bda...@apple.com>
Build fix.
Modified: trunk/Source/WebCore/bridge/objc/objc_instance.mm (199833 => 199834)
--- trunk/Source/WebCore/bridge/objc/objc_instance.mm 2016-04-21 20:23:28 UTC (rev 199833)
+++ trunk/Source/WebCore/bridge/objc/objc_instance.mm 2016-04-21 21:00:02 UTC (rev 199834)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2008, 2009, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2008, 2009, 2013, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,7 +37,9 @@
#import <runtime/ObjectPrototype.h>
#import <wtf/Assertions.h>
#import <wtf/HashMap.h>
+#import <wtf/MainThread.h>
#import <wtf/NeverDestroyed.h>
+#import <wtf/ThreadSpecific.h>
#ifdef NDEBUG
#define OBJC_LOG(formatAndArgs...) ((void)0)
@@ -459,17 +461,42 @@
return valueOf(exec);
}
-static NSString* swizzleNSObjectDescription(id self, SEL)
+static WTF::ThreadSpecific<uint32_t>* s_descriptionDepth;
+
+@interface NSObject (WebDescriptionCategory)
+- (NSString *)_web_description;
+@end
+
+@implementation NSObject (WebDescriptionCategory)
+
+- (NSString *)_web_description
{
- return [NSString stringWithFormat:@"%@%@%@", @"<", NSStringFromClass([self class]), @">"];
+ ASSERT(s_descriptionDepth);
+ if (s_descriptionDepth->isSet() && **s_descriptionDepth)
+ return [NSString stringWithFormat:@"<%@>", NSStringFromClass([self class])];
+ // We call _web_description here since this method should only be called
+ // once we have already swizzled this method with the one on NSObject.
+ // Thus, _web_description is actually the original description method.
+ return [self _web_description];
}
+@end
+
JSC::JSValue ObjcInstance::stringValue(ExecState* exec) const
{
- auto method = class_getInstanceMethod([NSObject class], @selector(description));
- IMP originalNSObjectDescription = method_setImplementation(method, (IMP)swizzleNSObjectDescription);
+ static std::once_flag initializeDescriptionDepthOnceFlag;
+ std::call_once(initializeDescriptionDepthOnceFlag, [] {
+ s_descriptionDepth = new WTF::ThreadSpecific<uint32_t>();
+ **s_descriptionDepth = 0;
+
+ auto descriptionMethod = class_getInstanceMethod([NSObject class], @selector(description));
+ auto webDescriptionMethod = class_getInstanceMethod([NSObject class], @selector(_web_description));
+ method_exchangeImplementations(descriptionMethod, webDescriptionMethod);
+ });
+
+ (**s_descriptionDepth)++;
JSC::JSValue result = convertNSStringToString(exec, [getObject() description]);
- method_setImplementation(method, originalNSObjectDescription);
+ (**s_descriptionDepth)--;
return result;
}
Modified: trunk/Tools/ChangeLog (199833 => 199834)
--- trunk/Tools/ChangeLog 2016-04-21 20:23:28 UTC (rev 199833)
+++ trunk/Tools/ChangeLog 2016-04-21 21:00:02 UTC (rev 199834)
@@ -1,3 +1,22 @@
+2016-04-21 Keith Miller <keith_mil...@apple.com>
+
+ WebScriptObject description swizzler should work in a multi-threaded world
+ https://bugs.webkit.org/show_bug.cgi?id=156808
+
+ Add a test for our NSObject swizzling TLS implementation. The test runs on
+ two threads. One in JS and another in Objective-C. We expect the JS thread
+ to use our NSObject description override and the Objective-C thread to act
+ as though it was using the original NSObject description method.
+
+ Reviewed by Geoffrey Garen.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/mac/WebScriptObjectDescription.html: Added.
+ * TestWebKitAPI/Tests/mac/WebScriptObjectDescription.mm: Added.
+ (nsObjectDescriptionTest):
+ (-[WebScriptDescriptionTest webView:didFinishLoadForFrame:]):
+ (TestWebKitAPI::TEST):
+
2016-04-21 Carlos Garcia Campos <cgar...@igalia.com>
[GTK] WebKitWebView should claim the contents size as its natural size
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (199833 => 199834)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2016-04-21 20:23:28 UTC (rev 199833)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2016-04-21 21:00:02 UTC (rev 199834)
@@ -88,6 +88,8 @@
52B8CF9815868D9100281053 /* SetDocumentURI.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 52B8CF9415868CF000281053 /* SetDocumentURI.html */; };
52D673EE1AFB127300FA19FE /* WKPageCopySessionStateWithFiltering.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52D673EC1AFB126800FA19FE /* WKPageCopySessionStateWithFiltering.cpp */; };
52E5CE4914D21EAB003B2BD8 /* ParentFrame_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 52E5CE4814D21EAB003B2BD8 /* ParentFrame_Bundle.cpp */; };
+ 536770341CC8022800D425B1 /* WebScriptObjectDescription.mm in Sources */ = {isa = PBXBuildFile; fileRef = 536770331CC8022800D425B1 /* WebScriptObjectDescription.mm */; };
+ 536770361CC81B6100D425B1 /* WebScriptObjectDescription.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 536770351CC812F900D425B1 /* WebScriptObjectDescription.html */; };
5714ECB91CA8B5B000051AC8 /* DownloadRequestOriginalURL.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5714ECB81CA8B58800051AC8 /* DownloadRequestOriginalURL.html */; };
5714ECBB1CA8BFE400051AC8 /* DownloadRequestOriginalURLFrame.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5714ECBA1CA8BFD100051AC8 /* DownloadRequestOriginalURLFrame.html */; };
5714ECBD1CA8C22A00051AC8 /* DownloadRequestOriginalURL2.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5714ECBC1CA8C21800051AC8 /* DownloadRequestOriginalURL2.html */; };
@@ -415,6 +417,7 @@
dstPath = TestWebKitAPI.resources;
dstSubfolderSpec = 7;
files = (
+ 536770361CC81B6100D425B1 /* WebScriptObjectDescription.html in Copy Resources */,
57901FB11CAF142D00ED64F9 /* LoadInvalidURLRequest.html in Copy Resources */,
5714ECBD1CA8C22A00051AC8 /* DownloadRequestOriginalURL2.html in Copy Resources */,
5714ECBB1CA8BFE400051AC8 /* DownloadRequestOriginalURLFrame.html in Copy Resources */,
@@ -658,6 +661,8 @@
52D673EC1AFB126800FA19FE /* WKPageCopySessionStateWithFiltering.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKPageCopySessionStateWithFiltering.cpp; sourceTree = "<group>"; };
52E5CE4514D21E9D003B2BD8 /* ParentFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParentFrame.cpp; sourceTree = "<group>"; };
52E5CE4814D21EAB003B2BD8 /* ParentFrame_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParentFrame_Bundle.cpp; sourceTree = "<group>"; };
+ 536770331CC8022800D425B1 /* WebScriptObjectDescription.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebScriptObjectDescription.mm; sourceTree = "<group>"; };
+ 536770351CC812F900D425B1 /* WebScriptObjectDescription.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = WebScriptObjectDescription.html; sourceTree = "<group>"; };
5714ECB81CA8B58800051AC8 /* DownloadRequestOriginalURL.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = DownloadRequestOriginalURL.html; sourceTree = "<group>"; };
5714ECBA1CA8BFD100051AC8 /* DownloadRequestOriginalURLFrame.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = DownloadRequestOriginalURLFrame.html; sourceTree = "<group>"; };
5714ECBC1CA8C21800051AC8 /* DownloadRequestOriginalURL2.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = DownloadRequestOriginalURL2.html; sourceTree = "<group>"; };
@@ -1502,6 +1507,7 @@
1A7BFC0A171A0BDB00BC5F64 /* WillSendSubmitEvent.mm */,
A5E2027215B2181900C13E14 /* WindowlessWebViewWithMedia.mm */,
764322D51B61CCA40024F801 /* WordBoundaryTypingAttributes.mm */,
+ 536770331CC8022800D425B1 /* WebScriptObjectDescription.mm */,
);
path = mac;
sourceTree = "<group>";
@@ -1535,6 +1541,7 @@
C540F783152E5A7800A40C8C /* verboseMarkup.html */,
CE14F1A2181873B0001C2705 /* WillPerformClientRedirectToURLCrash.html */,
A5E2027015B2180600C13E14 /* WindowlessWebViewWithMedia.html */,
+ 536770351CC812F900D425B1 /* WebScriptObjectDescription.html */,
);
name = Resources;
sourceTree = "<group>";
@@ -1804,6 +1811,7 @@
7CCE7EE11A411A9A00447C4C /* GetBackingScaleFactor.mm in Sources */,
CDBFCC451A9FF45300A7B691 /* FullscreenZoomInitialFrame.mm in Sources */,
7CCE7EF91A411AE600447C4C /* GetInjectedBundleInitializationUserDataCallback.cpp in Sources */,
+ 536770341CC8022800D425B1 /* WebScriptObjectDescription.mm in Sources */,
7CCE7EE21A411A9A00447C4C /* GetPIDAfterAbortedProcessLaunch.cpp in Sources */,
7CCE7F351A411B8E00447C4C /* HashMap.cpp in Sources */,
7CCE7F361A411B8E00447C4C /* HashSet.cpp in Sources */,
@@ -1955,7 +1963,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 0766DD201A5AD5200023E3BB /* PendingAPIRequestURL.cpp in Sources */,
+ 0766DD201A5AD5200023E3BB /* PendingAPIRequestURL.cpp in Sources */,
2D9A53AF1B31FA8D0074D5AA /* ShrinkToFit.mm in Sources */,
51B454EC1B4E236B0085EAA6 /* WebViewCloseInsideDidFinishLoadForFrame.mm in Sources */,
57901FAD1CAF12C200ED64F9 /* LoadInvalidURLRequest.mm in Sources */,
Added: trunk/Tools/TestWebKitAPI/Tests/mac/WebScriptObjectDescription.html (0 => 199834)
--- trunk/Tools/TestWebKitAPI/Tests/mac/WebScriptObjectDescription.html (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/mac/WebScriptObjectDescription.html 2016-04-21 21:00:02 UTC (rev 199834)
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<body>
+ <script>
+ function foo(base) {
+ for (let i = 0; i < 100000; i++) {
+ if (base + "" !== "<NSObject>")
+ return false;
+ }
+ return true;
+ }
+ </script>
+</body>
Added: trunk/Tools/TestWebKitAPI/Tests/mac/WebScriptObjectDescription.mm (0 => 199834)
--- trunk/Tools/TestWebKitAPI/Tests/mac/WebScriptObjectDescription.mm (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/mac/WebScriptObjectDescription.mm 2016-04-21 21:00:02 UTC (rev 199834)
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include "config.h"
+
+#import "PlatformUtilities.h"
+#import "PlatformWebView.h"
+#import <atomic>
+#import <thread>
+#import <wtf/RetainPtr.h>
+
+@interface WebScriptDescriptionTest : NSObject <WebFrameLoadDelegate>
+@end
+
+static bool didFinishLoad;
+static bool failedObjCDescription { false };
+
+void nsObjectDescriptionTest(NSObject *object)
+{
+ NSError *error = nullptr;
+ NSRegularExpression *regexp = [NSRegularExpression regularExpressionWithPattern:@"<NSObject: 0x[0-9|a-f]+>" options:0 error:&error];
+ for (unsigned i = 0; i < 100000; ++i) {
+ NSString *description = [object description];
+ if ([regexp numberOfMatchesInString:description options:0 range:NSMakeRange(0, [description length])] != 1)
+ failedObjCDescription = true;
+ }
+}
+
+@implementation WebScriptDescriptionTest
+
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
+{
+ didFinishLoad = true;
+}
+@end
+
+namespace TestWebKitAPI {
+
+TEST(WebKit1, WebScriptObjectDescription)
+{
+ RetainPtr<WebView> webView = adoptNS([[WebView alloc] initWithFrame:NSMakeRect(0, 0, 120, 200) frameName:nil groupName:nil]);
+ RetainPtr<WebScriptDescriptionTest> testController = adoptNS([WebScriptDescriptionTest new]);
+ NSObject *object = [[NSObject alloc] init];
+
+ webView.get().frameLoadDelegate = testController.get();
+ [[webView.get() mainFrame] loadRequest:[NSURLRequest requestWithURL:[[NSBundle mainBundle]
+ URLForResource:@"WebScriptObjectDescription" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]];
+
+ Util::run(&didFinishLoad);
+ didFinishLoad = false;
+ failedObjCDescription = false;
+
+ std::thread thread1(nsObjectDescriptionTest, object);
+
+ CFBooleanRef result = (CFBooleanRef)([[webView.get() windowScriptObject] callWebScriptMethod:@"foo" withArguments:@[ object ]]);
+ EXPECT_EQ(CFBooleanGetValue(result), true);
+
+ thread1.join();
+ EXPECT_EQ(failedObjCDescription, false);
+ [object release];
+}
+
+} // namespace TestWebKitAPI
+