Skip to content

Commit

Permalink
Merge r182537 - [GTK] Crash in DOMObjectCache when a wrapped object o…
Browse files Browse the repository at this point in the history
…wned by the cache is unreffed by the user

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

Reviewed by Martin Robinson.

This is a case we claim to support, but it only works if the
object has only one reference. In that case, when the user unrefs
it, the weak ref notify callback removes the object from the
cache. However, if the object has more than one ref, the cache
doesn't know the user unreffed it, and when clearing the cache we
try to remove more references than what the object actually has,
causing a crash in g_object_unref.

* bindings/gobject/DOMObjectCache.cpp:
(WebKit::DOMObjectCacheData::clearObject):

Canonical link: https://commits.webkit.org/154760.342@webkitgtk/2.6
git-svn-id: https://svn.webkit.org/repository/webkit/releases/WebKitGTK/webkit-2.6@182539 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
carlosgcampos committed Apr 8, 2015
1 parent eb34ea8 commit bb9defa
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 1 deletion.
18 changes: 18 additions & 0 deletions Source/WebCore/ChangeLog
@@ -1,3 +1,21 @@
2015-04-08 Carlos Garcia Campos <cgarcia@igalia.com>

[GTK] Crash in DOMObjectCache when a wrapped object owned by the cache is unreffed by the user
https://bugs.webkit.org/show_bug.cgi?id=143521

Reviewed by Martin Robinson.

This is a case we claim to support, but it only works if the
object has only one reference. In that case, when the user unrefs
it, the weak ref notify callback removes the object from the
cache. However, if the object has more than one ref, the cache
doesn't know the user unreffed it, and when clearing the cache we
try to remove more references than what the object actually has,
causing a crash in g_object_unref.

* bindings/gobject/DOMObjectCache.cpp:
(WebKit::DOMObjectCacheData::clearObject):

2015-02-17 Carlos Garcia Campos <cgarcia@igalia.com>

Use HashMap::add instead of get/contains + set in DOMObjectCache
Expand Down
4 changes: 4 additions & 0 deletions Source/WebCore/bindings/gobject/DOMObjectCache.cpp
Expand Up @@ -43,7 +43,11 @@ struct DOMObjectCacheData {
{
ASSERT(object);
ASSERT(cacheReferences >= 1);
ASSERT(object->ref_count >= 1);

// Make sure we don't unref more than the references the object actually has. It can happen that user
// unreffed a reference owned by the cache.
cacheReferences = std::min(static_cast<unsigned>(object->ref_count), cacheReferences);
GRefPtr<GObject> protect(object);
do {
g_object_unref(object);
Expand Down
19 changes: 19 additions & 0 deletions Tools/ChangeLog
@@ -1,3 +1,22 @@
2015-04-08 Carlos Garcia Campos <cgarcia@igalia.com>

[GTK] Crash in DOMObjectCache when a wrapped object owned by the cache is unreffed by the user
https://bugs.webkit.org/show_bug.cgi?id=143521

Reviewed by Martin Robinson.

Add a way to detect unexpected web process crashes to WebViewTest,
and a test case to testDOMCache to trigger the crash.

* TestWebKitAPI/Tests/WebKit2Gtk/DOMNodeTest.cpp:
(WebKitDOMNodeTest::testDOMCache):
* TestWebKitAPI/Tests/WebKit2Gtk/TestWebExtensions.cpp:
(testWebKitWebViewProcessCrashed):
* TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.cpp:
(WebViewTest::WebViewTest):
(WebViewTest::webProcessCrashed):
* TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.h:

2015-03-06 Carlos Garcia Campos <cgarcia@igalia.com>

[GTK] Test /webkit2/WebKitWebView/sync-request-on-max-conns might fail after finished
Expand Down
6 changes: 6 additions & 0 deletions Tools/TestWebKitAPI/Tests/WebKit2Gtk/DOMNodeTest.cpp
Expand Up @@ -231,6 +231,12 @@ class WebKitDOMNodeTest : public WebProcessTest {
g_assert(WEBKIT_DOM_IS_HTML_PARAGRAPH_ELEMENT(p2.get()));
assertObjectIsDeletedWhenTestFinishes(G_OBJECT(p2.get()));

// Manually handling a DOM object owned by the cache shouldn't crash when the cache has more than one reference.
GRefPtr<WebKitDOMElement> p3 = adoptGRef(webkit_dom_document_create_element(document, "P", nullptr));
g_assert(WEBKIT_DOM_IS_HTML_PARAGRAPH_ELEMENT(p3.get()));
assertObjectIsDeletedWhenTestFinishes(G_OBJECT(p3.get()));
webkit_dom_node_append_child(WEBKIT_DOM_NODE(div), WEBKIT_DOM_NODE(p3.get()), nullptr);

// DOM objects removed from the document are also correctly handled by the cache.
WebKitDOMElement* a = webkit_dom_document_create_element(document, "A", nullptr);
g_assert(WEBKIT_DOM_IS_ELEMENT(a));
Expand Down
5 changes: 4 additions & 1 deletion Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestWebExtensions.cpp
Expand Up @@ -86,9 +86,11 @@ static void testWebKitWebViewProcessCrashed(WebViewTest* test, gconstpointer)
test->loadHtml("<html></html>", 0);
test->waitUntilLoadFinished();

g_signal_connect(test->m_webView, "web-process-crashed",
g_signal_connect_after(test->m_webView, "web-process-crashed",
G_CALLBACK(webProcessCrashedCallback), test);

test->m_expectedWebProcessCrash = true;

GRefPtr<GDBusProxy> proxy = adoptGRef(bus->createProxy("org.webkit.gtk.WebExtensionTest",
"/org/webkit/gtk/WebExtensionTest", "org.webkit.gtk.WebExtensionTest", test->m_mainLoop));

Expand All @@ -100,6 +102,7 @@ static void testWebKitWebViewProcessCrashed(WebViewTest* test, gconstpointer)
-1, 0, 0));
g_assert(!result);
g_main_loop_run(test->m_mainLoop);
test->m_expectedWebProcessCrash = false;
}

static void testWebExtensionWindowObjectCleared(WebViewTest* test, gconstpointer)
Expand Down
12 changes: 12 additions & 0 deletions Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.cpp
Expand Up @@ -34,8 +34,10 @@ WebViewTest::WebViewTest(WebKitWebView* webView)
, m_javascriptResult(0)
, m_resourceDataSize(0)
, m_surface(0)
, m_expectedWebProcessCrash(false)
{
assertObjectIsDeletedWhenTestFinishes(G_OBJECT(m_webView));
g_signal_connect(m_webView, "web-process-crashed", G_CALLBACK(WebViewTest::webProcessCrashed), this);
}

WebViewTest::~WebViewTest()
Expand All @@ -50,6 +52,16 @@ WebViewTest::~WebViewTest()
g_main_loop_unref(m_mainLoop);
}

gboolean WebViewTest::webProcessCrashed(WebKitWebView*, WebViewTest* test)
{
if (test->m_expectedWebProcessCrash) {
test->m_expectedWebProcessCrash = false;
return FALSE;
}
g_assert_not_reached();
return TRUE;
}

void WebViewTest::loadURI(const char* uri)
{
m_activeURI = uri;
Expand Down
3 changes: 3 additions & 0 deletions Tools/TestWebKitAPI/gtk/WebKit2Gtk/WebViewTest.h
Expand Up @@ -72,6 +72,8 @@ class WebViewTest: public Test {

bool runWebProcessTest(const char* suiteName, const char* testName);

static gboolean webProcessCrashed(WebKitWebView*, WebViewTest*);

WebKitWebView* m_webView;
GMainLoop* m_mainLoop;
CString m_activeURI;
Expand All @@ -82,6 +84,7 @@ class WebViewTest: public Test {
GUniquePtr<char> m_resourceData;
size_t m_resourceDataSize;
cairo_surface_t* m_surface;
bool m_expectedWebProcessCrash;

private:
void doMouseButtonEvent(GdkEventType, int, int, unsigned, unsigned);
Expand Down

0 comments on commit bb9defa

Please sign in to comment.