Changeset 254328 in webkit
- Timestamp:
- Jan 10, 2020 12:42:11 AM (4 years ago)
- Location:
- trunk/Source/WebKit
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebKit/ChangeLog
r254325 r254328 1 2020-01-10 Carlos Garcia Campos <cgarcia@igalia.com> 2 3 Automation: scripts are executed in the wrong js context after a history navigation 4 https://bugs.webkit.org/show_bug.cgi?id=204880 5 <rdar://problem/58413615> 6 7 Reviewed by Brian Burg. 8 9 After a history navigation we use the script object from the previous frame js context because 10 didClearWindowObjectForFrame() is not called in that case. We are caching the script object for every frame ID, 11 and after a history navigation the frame ID is the same, but the frame js context isn't. That also means we might 12 be leaking the script objects in those cases, because we end up calling JSValueUnprotect with the wrong 13 context. It would be easier to set the script object as a property of the global object and let JSC handle the 14 lifetime. Instead of caching the script object and protect/unprotect it, we just check if the global object of 15 the current js context has the property or not to get or create it. We use a private symbol as the key of the 16 global object property to ensure it's not visible. 17 18 * WebProcess/Automation/WebAutomationSessionProxy.cpp: 19 (WebKit::WebAutomationSessionProxy::WebAutomationSessionProxy): Initialize m_scriptObjectIdentifier. 20 (WebKit::WebAutomationSessionProxy::scriptObject): Helper function to get the script object for the given 21 JavaScript context. 22 (WebKit::WebAutomationSessionProxy::setScriptObject): Helper function to set the script object for the given 23 JavaScript context. 24 (WebKit::WebAutomationSessionProxy::scriptObjectForFrame): Get or create the script object. 25 (WebKit::WebAutomationSessionProxy::elementForNodeHandle): Get the script object from global object. 26 (WebKit::WebAutomationSessionProxy::didClearWindowObjectForFrame): Remove the code to unprotect script objects 27 of the frame. 28 * WebProcess/Automation/WebAutomationSessionProxy.h: Add m_scriptObjectIdentifier and remove m_webFrameScriptObjectMap. 29 1 30 2020-01-09 Ross Kirsling <ross.kirsling@sony.com> 2 31 -
trunk/Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.cpp
r254118 r254328 109 109 WebAutomationSessionProxy::WebAutomationSessionProxy(const String& sessionIdentifier) 110 110 : m_sessionIdentifier(sessionIdentifier) 111 , m_scriptObjectIdentifier(JSC::PrivateName::Description, "automationSessionProxy"_s) 111 112 { 112 113 WebProcess::singleton().addMessageReceiver(Messages::WebAutomationSessionProxy::messageReceiverName(), *this); … … 212 213 } 213 214 215 JSObjectRef WebAutomationSessionProxy::scriptObject(JSGlobalContextRef context) 216 { 217 JSC::JSGlobalObject* globalObject = toJS(context); 218 JSC::VM& vm = globalObject->vm(); 219 JSC::JSLockHolder locker(vm); 220 auto scriptObjectID = JSC::Identifier::fromUid(m_scriptObjectIdentifier); 221 if (!globalObject->hasProperty(globalObject, scriptObjectID)) 222 return nullptr; 223 224 return const_cast<JSObjectRef>(toRef(globalObject, globalObject->get(globalObject, scriptObjectID))); 225 } 226 227 void WebAutomationSessionProxy::setScriptObject(JSGlobalContextRef context, JSObjectRef object) 228 { 229 JSC::JSGlobalObject* globalObject = toJS(context); 230 JSC::VM& vm = globalObject->vm(); 231 JSC::JSLockHolder locker(vm); 232 auto scriptObjectID = JSC::Identifier::fromUid(m_scriptObjectIdentifier); 233 PutPropertySlot slot(globalObject); 234 globalObject->methodTable(vm)->put(globalObject, globalObject, scriptObjectID, toJS(globalObject, object), slot); 235 } 236 214 237 JSObjectRef WebAutomationSessionProxy::scriptObjectForFrame(WebFrame& frame) 215 238 { 216 if (JSObjectRef scriptObject = m_webFrameScriptObjectMap.get(frame.frameID())) 239 JSGlobalContextRef context = frame.jsContext(); 240 if (auto* scriptObject = this->scriptObject(context)) 217 241 return scriptObject; 218 242 219 243 JSValueRef exception = nullptr; 220 JSGlobalContextRef context = frame.jsContext(); 244 String script = StringImpl::createWithoutCopying(WebAutomationSessionProxyScriptSource, sizeof(WebAutomationSessionProxyScriptSource)); 245 JSObjectRef scriptObjectFunction = const_cast<JSObjectRef>(JSEvaluateScript(context, OpaqueJSString::tryCreate(script).get(), nullptr, nullptr, 0, &exception)); 246 ASSERT(JSValueIsObject(context, scriptObjectFunction)); 221 247 222 248 JSValueRef sessionIdentifier = toJSValue(context, m_sessionIdentifier); … … 224 250 JSObjectRef createUUIDFunction = JSObjectMakeFunctionWithCallback(context, nullptr, createUUID); 225 251 JSObjectRef isValidNodeIdentifierFunction = JSObjectMakeFunctionWithCallback(context, nullptr, isValidNodeIdentifier); 226 227 String script = StringImpl::createWithoutCopying(WebAutomationSessionProxyScriptSource, sizeof(WebAutomationSessionProxyScriptSource));228 229 JSObjectRef scriptObjectFunction = const_cast<JSObjectRef>(JSEvaluateScript(context, OpaqueJSString::tryCreate(script).get(), nullptr, nullptr, 0, &exception));230 ASSERT(JSValueIsObject(context, scriptObjectFunction));231 232 252 JSValueRef arguments[] = { sessionIdentifier, evaluateFunction, createUUIDFunction, isValidNodeIdentifierFunction }; 233 253 JSObjectRef scriptObject = const_cast<JSObjectRef>(JSObjectCallAsFunction(context, scriptObjectFunction, nullptr, WTF_ARRAY_LENGTH(arguments), arguments, &exception)); 234 254 ASSERT(JSValueIsObject(context, scriptObject)); 235 255 236 JSValueProtect(context, scriptObject); 237 m_webFrameScriptObjectMap.add(frame.frameID(), scriptObject); 238 256 setScriptObject(context, scriptObject); 239 257 return scriptObject; 240 258 } … … 245 263 // does not exist, there are no nodes mapped to handles. Using scriptObjectForFrame() 246 264 // will make a new script object if it can't find one, preventing us from returning fast. 247 JSObjectRef scriptObject = m_webFrameScriptObjectMap.get(frame.frameID()); 265 JSGlobalContextRef context = frame.jsContext(); 266 auto* scriptObject = this->scriptObject(context); 248 267 if (!scriptObject) 249 268 return nullptr; 250 251 JSGlobalContextRef context = frame.jsContext();252 269 253 270 JSValueRef functionArguments[] = { … … 269 286 void WebAutomationSessionProxy::didClearWindowObjectForFrame(WebFrame& frame) 270 287 { 271 WebCore::FrameIdentifier frameID = frame.frameID();272 if (JSObjectRef scriptObject = m_webFrameScriptObjectMap.take(frameID))273 JSValueUnprotect(frame.jsContext(), scriptObject);274 275 288 String errorMessage = "Callback was not called before the unload event."_s; 276 289 String errorType = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::JavaScriptError); 277 290 278 auto pendingFrameCallbacks = m_webFramePendingEvaluateJavaScriptCallbacksMap.take(frame ID);291 auto pendingFrameCallbacks = m_webFramePendingEvaluateJavaScriptCallbacksMap.take(frame.frameID()); 279 292 for (uint64_t callbackID : pendingFrameCallbacks) 280 293 WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidEvaluateJavaScriptFunction(callbackID, errorMessage, errorType), 0); -
trunk/Source/WebKit/WebProcess/Automation/WebAutomationSessionProxy.h
r253883 r254328 29 29 #include "CoordinateSystem.h" 30 30 #include <JavaScriptCore/JSBase.h> 31 #include <JavaScriptCore/PrivateName.h> 31 32 #include <WebCore/FrameIdentifier.h> 32 33 #include <WebCore/IntRect.h> … … 57 58 58 59 private: 60 JSObjectRef scriptObject(JSGlobalContextRef); 61 void setScriptObject(JSGlobalContextRef, JSObjectRef); 59 62 JSObjectRef scriptObjectForFrame(WebFrame&); 60 63 WebCore::Element* elementForNodeHandle(WebFrame&, const String&); … … 78 81 79 82 String m_sessionIdentifier; 83 JSC::PrivateName m_scriptObjectIdentifier; 80 84 81 HashMap<WebCore::FrameIdentifier, JSObjectRef> m_webFrameScriptObjectMap;82 85 HashMap<WebCore::FrameIdentifier, Vector<uint64_t>> m_webFramePendingEvaluateJavaScriptCallbacksMap; 83 86 };
Note: See TracChangeset
for help on using the changeset viewer.