[webkit-dev] TimerWindowWndProc and dangling page instances

Van Den Berghe, Vincent Vincent.VanDenBerghe at bvdinfo.com
Fri Sep 13 00:42:56 PDT 2013


Hello,

Background
---------------
I'm currently embedding WebKit in a .NET application, which required me to solve a whole set of issues that are not relevant here. However, I've stumbled upon a scenario which I suspect is *really* problematic (but I can be wrong). Before patching anything, I'd like to submit this to greater minds for validation. The version of WebKit to which this applies is irrelevant: any recent version will do.

Problem
----------
When I'm finish with a WebView instance and before I'm releasing the COM object, I close it by doing a

DestroyWindow(m_viewWindow)

...where m_viewWindow is WebView's view window. Note that calling WebView::close() would work just as well.
This triggers a sequence of events that ultimately causes the destructor of the page to be called:

Page::~Page()

This works well, but when stress testing this will crash the WebKit.DLL with the following stack trace:

                WebKit.dll!WebCore::setImageLoadingSettings(WebCore::Page * page)  Line 57 + 0x3 bytes      C++
               WebKit.dll!WebCore::Settings::imageLoadingSettingsTimerFired(WebCore::Timer<WebCore::Settings> * __formal)  Line 363 + 0x8 bytes C++
               WebKit.dll!WebCore::Timer<WebCore::XMLHttpRequestProgressEventThrottle>::fired()  Line 114 + 0xb bytes C++
               WebKit.dll!WebCore::ThreadTimers::sharedTimerFiredInternal()  Line 132           C++
               WebKit.dll!WebCore::TimerWindowWndProc(HWND__ * hWnd, unsigned int message, unsigned int wParam, long lParam)  Line 111              C++

Depending on the managed environment (details are irrelevant for this discussion), the crash happens either immediately or after a while. Because of the way I embed WebKit, this usually happens when the second (or third, forth...) instance is being created.
The visible cause of the crash is the call to

WebKit.dll!WebCore::setImageLoadingSettings(WebCore::Page * page)

... with a page instance for which its destructor has already been executed.

Primary Cause
-----------------
I suspect the primary cause of a crash is the pending timer whose message is still in the message queue, that is executed just after the destruction of the page, but before any pending timers are killed. This causes a delayed execution of a function on a dangling page instance.
The problem doesn't occur when I don't call DestroyWindow or WebView::Close(), but this leads to unacceptable memory leaks.

Workaround
---------------
The minimal (but far from elegant) workaround is to add a method to WebCore::Settings:

        void clearPage()
        {
          m_page = 0;
        }


And call this method as the first line of Page's destructor:

Page::~Page()
{
    m_settings->clearPage();
    m_mainFrame->setView(0);
...


...and finally add a if(page) guard in setImageLoadingSettings like so:

static void setImageLoadingSettings(Page* page)
{
    if(page)
    for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
        frame->document()->cachedResourceLoader()->setImagesEnabled(page->settings().areImagesEnabled());
        frame->document()->cachedResourceLoader()->setAutoLoadImages(page->settings().loadsImagesAutomatically());
    }
}

This doesn't remedy the delayed execution of the timer, but solves the problem by setting the deleted instance to NULL and making sure it's not used in the delayed call.

The questions of course are:

-          Is this behavior by design?

-          If it is, is there a way to clean up WebKit instances without causing this crashing behavior, and if so which one?

-          If it isn't, is there a more elegant workaround than the one outlined here?

Thanks for any feedback,

Vincent


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.webkit.org/pipermail/webkit-dev/attachments/20130913/8a86fd1a/attachment.html>


More information about the webkit-dev mailing list