Add unit test for crash due to by delayed execution of JS functions on destroyed windows (issue #2038)

This commit is contained in:
Dmitry Azaraev 2016-11-08 21:52:36 +03:00 committed by Marshall Greenblatt
parent cca0bcc8e0
commit 3b499d3d11
3 changed files with 144 additions and 0 deletions

View File

@ -5,6 +5,7 @@
#include "tests/ceftests/test_handler.h"
#include "include/base/cef_bind.h"
#include "include/base/cef_logging.h"
#include "include/cef_command_line.h"
#include "include/cef_stream.h"
#include "include/wrapper/cef_closure_task.h"
@ -283,6 +284,11 @@ CefRefPtr<CefResourceHandler> TestHandler::GetResourceHandler(
return NULL;
}
void TestHandler::OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
TerminationStatus status) {
LOG(WARNING) << "OnRenderProcessTerminated: status = " << status << ".";
}
CefRefPtr<CefBrowser> TestHandler::GetBrowser() {
return first_browser_;
}

View File

@ -182,6 +182,9 @@ class TestHandler : public CefClient,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request) override;
void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
TerminationStatus status) override;
// These methods should only be used if at most one non-popup browser exists.
CefRefPtr<CefBrowser> GetBrowser();
int GetBrowserId();

View File

@ -37,6 +37,10 @@ const char kV8ContextEvalCspBypassSandbox[] =
"http://tests/V8Test.ContextEvalCspBypassSandbox";
const char kV8OnUncaughtExceptionTestUrl[] =
"http://tests/V8Test.OnUncaughtException";
const char kV8HandlerCallOnReleasedContextUrl[] =
"http://tests/V8Test.HandlerCallOnReleasedContext/main.html";
const char kV8HandlerCallOnReleasedContextChildUrl[] =
"http://tests/V8Test.HandlerCallOnReleasedContext/child.html";
const char kV8TestMsg[] = "V8Test.Test";
const char kV8TestCmdArg[] = "v8-test";
const char kV8RunTestMsg[] = "V8Test.RunTest";
@ -88,6 +92,7 @@ enum V8TestMode {
V8TEST_ON_UNCAUGHT_EXCEPTION,
V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS,
V8TEST_EXTENSION,
V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT,
};
// Set to the current test being run in the browser process. Will always be
@ -254,6 +259,8 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
case V8TEST_ON_UNCAUGHT_EXCEPTION:
RunOnUncaughtExceptionTest();
break;
case V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT:
break;
default:
// Was a startup test.
EXPECT_TRUE(startup_test_success_);
@ -2482,6 +2489,79 @@ class V8RendererTest : public ClientAppRenderer::Delegate,
EXPECT_TRUE(object.get());
EXPECT_TRUE(object->SetValue("v8_binding_test", CefV8Value::CreateInt(12),
V8_PROPERTY_ATTRIBUTE_NONE));
} else if (url == kV8HandlerCallOnReleasedContextUrl) {
// For V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT
class Handler : public CefV8Handler {
public:
Handler(CefRefPtr<V8RendererTest> renderer_test)
: renderer_test_(renderer_test) {}
bool Execute(const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception) override {
if (name == "notify_test_done") {
CefPostDelayedTask(
TID_RENDERER,
base::Bind(&V8RendererTest::DestroyTest, renderer_test_.get()),
1000);
return true;
}
return false;
}
private:
CefRefPtr<V8RendererTest> renderer_test_;
IMPLEMENT_REFCOUNTING(Handler);
};
Handler* handler = new Handler(this);
CefRefPtr<CefV8Handler> handlerPtr(handler);
// Function that will be called from the parent frame context.
CefRefPtr<CefV8Value> func =
CefV8Value::CreateFunction("notify_test_done", handler);
EXPECT_TRUE(func.get());
CefRefPtr<CefV8Value> object = context->GetGlobal();
EXPECT_TRUE(object.get());
EXPECT_TRUE(object->SetValue("notify_test_done", func,
V8_PROPERTY_ATTRIBUTE_NONE));
} else if (url == kV8HandlerCallOnReleasedContextChildUrl) {
// For V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT
class Handler : public CefV8Handler {
public:
Handler() {}
bool Execute(const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception) override {
if (name == "v8_context_is_alive") {
retval = CefV8Value::CreateBool(true);
return true;
}
return false;
}
IMPLEMENT_REFCOUNTING(Handler);
};
Handler* handler = new Handler;
CefRefPtr<CefV8Handler> handlerPtr(handler);
// Function that will be called from the parent frame context.
CefRefPtr<CefV8Value> func =
CefV8Value::CreateFunction("v8_context_is_alive", handler);
EXPECT_TRUE(func.get());
CefRefPtr<CefV8Value> object = context->GetGlobal();
EXPECT_TRUE(object.get());
EXPECT_TRUE(object->SetValue("v8_context_is_alive", func,
V8_PROPERTY_ATTRIBUTE_NONE));
}
}
@ -2714,6 +2794,58 @@ class V8TestHandler : public TestHandler {
"</body></html>\n",
"text/html");
CreateBrowser(kV8OnUncaughtExceptionTestUrl);
} else if (test_mode_ == V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT) {
AddResource(kV8HandlerCallOnReleasedContextUrl,
"<html><body onload='createFrame()'>"
"(main)"
"<script>"
"function createFrame() {"
" var el = document.createElement('iframe');"
" el.id = 'child';"
" el.src = '" +
std::string(kV8HandlerCallOnReleasedContextChildUrl) +
"';"
" el.onload = function() {"
" setTimeout(function() {"
" try {"
" el.contentWindow.removeMe();"
" window.notify_test_done();"
" } catch (e) { alert('Unit test error.\\n' + e); }"
" }, 1000);"
" };"
" document.body.appendChild(el);"
"}"
""
"function removeFrame(id) {"
" var el = document.getElementById(id);"
" if (el) { el.parentElement.removeChild(el); }"
" else { alert('Error in test. No element \"' + id + "
"'\" found.'); }"
"}"
"</script>"
"</body></html>",
"text/html");
AddResource(kV8HandlerCallOnReleasedContextChildUrl,
"<html><body>"
"(child)"
"<script>"
"try {"
" if (!window.v8_context_is_alive()) {"
" throw 'v8_context_is_alive returns non-true value.';"
" }"
"} catch (e) {"
" alert('Unit test error.\\n' + e);"
"}"
""
"function removeMe() {"
" var w = window;"
" w.parent.removeFrame('child');"
" return w.v8_context_is_alive();"
"}"
"</script>"
"</body></html>",
"text/html");
CreateBrowser(kV8HandlerCallOnReleasedContextUrl);
} else {
EXPECT_TRUE(test_url_ != NULL);
AddResource(test_url_,
@ -2879,3 +3011,6 @@ V8_TEST(StackTrace, V8TEST_STACK_TRACE);
V8_TEST(OnUncaughtException, V8TEST_ON_UNCAUGHT_EXCEPTION);
V8_TEST(OnUncaughtExceptionDevTools, V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS);
V8_TEST(Extension, V8TEST_EXTENSION);
V8_TEST_EX(HandlerCallOnReleasedContext,
V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT,
kV8HandlerCallOnReleasedContextUrl)