Commit 1f0843d3 authored by dcheng@chromium.org's avatar dcheng@chromium.org

Fix use-after-free when creating and detaching iframe during load.

WebLocalFrameImpl::createChildFrame needs to keep a reference to the
WebCore::LocalFrame in case LocalFrame::init() detaches the frame.

BUG=384890
TEST=fast/loader/create-frame-in-DOMContentLoaded.html
R=abarth@chromium.org

Review URL: https://codereview.chromium.org/339513002

git-svn-id: svn://svn.chromium.org/blink/trunk@176232 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 4589fefa
...@@ -1670,35 +1670,36 @@ void WebLocalFrameImpl::initializeAsMainFrame(WebCore::Page* page) ...@@ -1670,35 +1670,36 @@ void WebLocalFrameImpl::initializeAsMainFrame(WebCore::Page* page)
PassRefPtr<LocalFrame> WebLocalFrameImpl::createChildFrame(const FrameLoadRequest& request, HTMLFrameOwnerElement* ownerElement) PassRefPtr<LocalFrame> WebLocalFrameImpl::createChildFrame(const FrameLoadRequest& request, HTMLFrameOwnerElement* ownerElement)
{ {
ASSERT(m_client); ASSERT(m_client);
// Protect a reference to the new child frame, in case it gets detached. WebLocalFrameImpl* webframeChild = toWebLocalFrameImpl(m_client->createChildFrame(this, request.frameName()));
RefPtr<WebLocalFrameImpl> child = toWebLocalFrameImpl(m_client->createChildFrame(this, request.frameName())); if (!webframeChild)
if (!child)
return nullptr; return nullptr;
// FIXME: Using subResourceAttributeName as fallback is not a perfect // FIXME: Using subResourceAttributeName as fallback is not a perfect
// solution. subResourceAttributeName returns just one attribute name. The // solution. subResourceAttributeName returns just one attribute name. The
// element might not have the attribute, and there might be other attributes // element might not have the attribute, and there might be other attributes
// which can identify the element. // which can identify the element.
child->initializeAsChildFrame(frame()->host(), ownerElement, request.frameName(), ownerElement->getAttribute(ownerElement->subResourceAttributeName())); RefPtr<LocalFrame> child = webframeChild->initializeAsChildFrame(frame()->host(), ownerElement, request.frameName(), ownerElement->getAttribute(ownerElement->subResourceAttributeName()));
// Initializing the WebCore frame may cause the new child to be detached, since it may dispatch a load event in the parent. // Initializing the WebCore frame may cause the new child to be detached, since it may dispatch a load event in the parent.
if (!child->frame()) if (!child->tree().parent())
return nullptr; return nullptr;
// If we're moving in the back/forward list, we might want to replace the content // If we're moving in the back/forward list, we might want to replace the content
// of this child frame with whatever was there at that point. // of this child frame with whatever was there at that point.
RefPtr<HistoryItem> childItem; RefPtr<HistoryItem> childItem;
if (isBackForwardLoadType(frame()->loader().loadType()) && !frame()->document()->loadEventFinished()) if (isBackForwardLoadType(frame()->loader().loadType()) && !frame()->document()->loadEventFinished())
childItem = PassRefPtr<HistoryItem>(child->client()->historyItemForNewChildFrame(child.get())); childItem = PassRefPtr<HistoryItem>(webframeChild->client()->historyItemForNewChildFrame(webframeChild));
if (childItem) if (childItem)
child->frame()->loader().loadHistoryItem(childItem.get()); child->loader().loadHistoryItem(childItem.get());
else else
child->frame()->loader().load(FrameLoadRequest(0, request.resourceRequest(), "_self")); child->loader().load(FrameLoadRequest(0, request.resourceRequest(), "_self"));
// Note a synchronous navigation (about:blank) would have already processed // Note a synchronous navigation (about:blank) would have already processed
// onload, so it is possible for the child frame to have already been destroyed by // onload, so it is possible for the child frame to have already been
// script in the page. // detached by script in the page.
return child->frame(); if (!child->tree().parent())
return nullptr;
return child;
} }
void WebLocalFrameImpl::didChangeContentsSize(const IntSize& size) void WebLocalFrameImpl::didChangeContentsSize(const IntSize& size)
...@@ -1944,12 +1945,14 @@ void WebLocalFrameImpl::invalidateAll() const ...@@ -1944,12 +1945,14 @@ void WebLocalFrameImpl::invalidateAll() const
invalidateScrollbar(); invalidateScrollbar();
} }
void WebLocalFrameImpl::initializeAsChildFrame(FrameHost* host, FrameOwner* owner, const AtomicString& name, const AtomicString& fallbackName) PassRefPtr<LocalFrame> WebLocalFrameImpl::initializeAsChildFrame(FrameHost* host, FrameOwner* owner, const AtomicString& name, const AtomicString& fallbackName)
{ {
setWebCoreFrame(LocalFrame::create(&m_frameLoaderClientImpl, host, owner)); RefPtr<LocalFrame> frame = LocalFrame::create(&m_frameLoaderClientImpl, host, owner);
frame()->tree().setName(name, fallbackName); setWebCoreFrame(frame);
// May dispatch JS events; frame() may be null after this. frame->tree().setName(name, fallbackName);
frame()->init(); // May dispatch JS events; frame may be detached after this.
frame->init();
return frame;
} }
} // namespace blink } // namespace blink
...@@ -313,7 +313,7 @@ public: ...@@ -313,7 +313,7 @@ public:
// Invalidates both content area and the scrollbar. // Invalidates both content area and the scrollbar.
void invalidateAll() const; void invalidateAll() const;
void initializeAsChildFrame(WebCore::FrameHost*, WebCore::FrameOwner*, const AtomicString& name, const AtomicString& fallbackName); PassRefPtr<WebCore::LocalFrame> initializeAsChildFrame(WebCore::FrameHost*, WebCore::FrameOwner*, const AtomicString& name, const AtomicString& fallbackName);
private: private:
friend class FrameLoaderClientImpl; friend class FrameLoaderClientImpl;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment