Bug 249872

Summary: Crash in PDFDocument::injectStyleAndContentScript when downloading PDF
Product: WebKit Reporter: Michael Catanzaro <mcatanzaro>
Component: WebKitGTKAssignee: Michael Catanzaro <mcatanzaro>
Status: RESOLVED FIXED    
Severity: Normal CC: bugs-noreply, mcatanzaro, webkit-bug-importer
Priority: P2    
Version: WebKit Nightly Build   
Hardware: PC   
OS: Linux   
See Also: https://bugs.webkit.org/show_bug.cgi?id=272590
Bug Depends on:    
Bug Blocks: 235969    

Description Michael Catanzaro 2022-12-24 10:15:57 PST
With WebKitGTK 2.39.3, open a PDF in PDF.js and try to save it using the download button. It will crash:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007f999ad8cffd in WTF::RefCountedBase::ref (this=<optimized out>) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/_builddir/WTF/Headers/wtf/RefCounted.h:49
49	        ++m_refCount;
[Current thread is 1 (Thread 0x7f9991edc600 (LWP 2))]
(gdb) bt
#0  0x00007f999ad8cffd in WTF::RefCountedBase::ref() const (this=<optimized out>)
    at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/_builddir/WTF/Headers/wtf/RefCounted.h:49
#1  WTF::Ref<WebCore::EventListener, WTF::RawPtrTraits<WebCore::EventListener> >::Ref(WebCore::EventListener&)
    (object=..., this=0x7ffc3fbffd00)
    at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/_builddir/WTF/Headers/wtf/Ref.h:67
#2  WTF::Ref<WebCore::EventListener, WTF::RawPtrTraits<WebCore::EventListener> >::copyRef() const &
    (this=<optimized out>) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/_builddir/WTF/Headers/wtf/Ref.h:125
#3  WebCore::tryAddEventListener (listener=..., options=..., eventType=..., targetNode=0x7f97fe09fbc0)
    at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/dom/Node.cpp:2194
#4  WebCore::Node::addEventListener(WTF::AtomString const&, WTF::Ref<WebCore::EventListener, WTF::RawPtrTraits<WebCore::EventListener> >&&, WebCore::AddEventListenerOptions const&)
    (this=this@entry=0x7f97fe09fbc0, eventType=..., listener=..., options=...)
    at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/dom/Node.cpp:2229
#5  0x00007f999b009f4d in WebCore::PDFDocument::injectStyleAndContentScript() (this=0x7f9936121800)
    at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/html/PDFDocument.cpp:237
#6  0x00007f999ad60236 in WebCore::EventTarget::innerInvokeEventListeners(WebCore::Event&, WTF::Vector<WTF::RefPtr<WebCore::RegisteredEventListener, WTF::RawPtrTraits<WebCore::RegisteredEventListener>, WTF::DefaultRefDerefTraits<WebCore::RegisteredEventListener> >, 1ul, WTF::CrashOnOverflow, 2ul, WTF::FastMalloc>, WebCore::EventTarget::EventInvokePhase)
    (this=this@entry=0x7f97fe002000, event=..., listeners=..., phase=phase@entry=WebCore::EventTarget::EventInvokePhase::Bubbling) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/dom/EventTarget.cpp:369
#7  0x00007f999ad609d8 in WebCore::EventTarget::fireEventListeners(WebCore::Event&, WebCore::EventTarget::EventInvokePhase) (this=0x7f97fe002000, event=..., phase=WebCore::EventTarget::EventInvokePhase::Bubbling)
    at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/dom/EventTarget.cpp:301
#8  0x00007f999ad60e1f in WebCore::EventContext::handleLocalEvents(WebCore::Event&, WebCore::EventTarget::EventInvokePhase) const (this=<optimized out>, event=<optimized out>, phase=<optimized out>)
    at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/dom/EventContext.cpp:96
#9  0x00007f999ad615af in WebCore::dispatchEventInDOM(WebCore::Event&, WebCore::EventPath const&)
    (event=..., path=...) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/dom/EventDispatcher.cpp:109
#10 0x00007f999ad653fd in WebCore::EventDispatcher::dispatchEvent(WebCore::Node&, WebCore::Event&)
     (node=..., event=...) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/dom/EventDispatcher.cpp:190
#11 0x00007f999b2aa63f in WebCore::FrameLoader::PolicyChecker::checkNavigationPolicy(WebCore::ResourceRequest&&, WebCore::ResourceResponse const&, WebCore::DocumentLoader*, WTF::RefPtr<WebCore::FormState, WTF::RawPtrTraits<WebCore::FormState>, WTF::DefaultRefDerefTraits<WebCore::FormState> >&&, WTF::CompletionHandler<void (WebCore::ResourceRequest&&, WTF::WeakPtr<WebCore::FormState, WTF::DefaultWeakPtrImpl>&&, WebCore::NavigationPolicyDecision)>&&, WebCore::PolicyDecisionMode)
     (this=this@entry=0x7f998a2110c0, request=..., redirectResponse=..., loader=loader@entry=0x7f99362a5000, formState=..., function=..., policyDecisionMode=<optimized out>)
    at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/_builddir/WTF/Headers/wtf/RawPtrTraits.h:44
#12 0x00007f999b284379 in WebCore::FrameLoader::loadWithDocumentLoader(WebCore::DocumentLoader*, WebCore::FrameLoadType, WTF::RefPtr<WebCore::FormState, WTF::RawPtrTraits<WebCore::FormState>, WTF::DefaultRefDerefTraits<WebCore::FormState> >&&, WebCore::AllowNavigationToInvalidURL, WTF::CompletionHandler<void ()>&&)
    (this=0x7f998a029ba0, loader=0x7f99362a5000, type=<optimized out>, formState=<optimized out>, allowNavigationToInvalidURL=<optimized out>, completionHandler=<optimized out>)
    at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/loader/FrameLoader.cpp:1682
#13 0x00007f999b2849d8 in WebCore::FrameLoader::loadWithNavigationAction(WebCore::ResourceRequest const&, WebCore::NavigationAction&&, WebCore::FrameLoadType, WTF::RefPtr<WebCore::FormState, WTF::RawPtrTraits<WebCore::FormState>, WTF::DefaultRefDerefTraits<WebCore::FormState> >&&, WebCore::AllowNavigationToInvalidURL, WebCore::ShouldTreatAsContinuingLoad, WTF::CompletionHandler<void ()>&&)
    (this=this@entry=0x7f998a029ba0, request=..., action=..., type=type@entry=WebCore::FrameLoadType::Standard, formState=..., allowNavigationToInvalidURL=allowNavigationToInvalidURL@entry=WebCore::AllowNavigationToInvalidURL::Yes, shouldTreatAsContinuingLoad=<optimized out>, completionHandler=<optimized out>)
    at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/_builddir/WTF/Headers/wtf/RawPtrTraits.h:44
#14 0x00007f999b2854a7 in WebCore::FrameLoader::loadURL(WebCore::FrameLoadRequest&&, WTF::String const&, WebCore::FrameLoadType, WebCore::Event*, WTF::RefPtr<WebCore::FormState, WTF::RawPtrTraits<WebCore::FormState>, WTF::DefaultRefDere--Type <RET> for more, q to quit, c to continue without paging--c
fTraits<WebCore::FormState> >&&, std::optional<WebCore::PrivateClickMeasurement>&&, WTF::CompletionHandler<void ()>&&) (this=0x7f998a029ba0, frameLoadRequest=..., referrer=<optimized out>, newLoadType=<optimized out>, event=<optimized out>, formState=<optimized out>, privateClickMeasurement=<optimized out>, completionHandler=<optimized out>) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/loader/FrameLoader.cpp:1463
#15 0x00007f999b286cef in WebCore::FrameLoader::loadFrameRequest(WebCore::FrameLoadRequest&&, WebCore::Event*, WTF::RefPtr<WebCore::FormState, WTF::RawPtrTraits<WebCore::FormState>, WTF::DefaultRefDerefTraits<WebCore::FormState> >&&, std::optional<WebCore::PrivateClickMeasurement>&&) (this=0x7f998a029ba0, request=..., event=<optimized out>, formState=<optimized out>, privateClickMeasurement=<optimized out>) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/_builddir/WTF/Headers/wtf/ThreadAssertions.h:119
#16 0x00007f999b28713a in WebCore::FrameLoader::changeLocation(WebCore::FrameLoadRequest&&, WebCore::Event*, std::optional<WebCore::PrivateClickMeasurement>&&) (this=this@entry=0x7f998a029ba0, frameRequest=..., triggeringEvent=triggeringEvent@entry=0x7f97fe09f710, privateClickMeasurement=...) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/loader/FrameLoader.cpp:462
#17 0x00007f999b287545 in WebCore::FrameLoader::changeLocation(WTF::URL const&, WTF::AtomString const&, WebCore::Event*, WebCore::ReferrerPolicy const&, WebCore::ShouldOpenExternalURLsPolicy, std::optional<WebCore::NewFrameOpenerPolicy>, WTF::AtomString const&, WebCore::SystemPreviewInfo const&, std::optional<WebCore::PrivateClickMeasurement>&&) (this=this@entry=0x7f998a029ba0, url=..., passedTarget=..., triggeringEvent=triggeringEvent@entry=0x7f97fe09f710, referrerPolicy=@0x7ffc3fc01faf: WebCore::ReferrerPolicy::EmptyString, shouldOpenExternalURLsPolicy=<optimized out>, openerPolicy=std::optional<WebCore::NewFrameOpenerPolicy> = {...}, downloadAttribute=<optimized out>, systemPreviewInfo=<optimized out>, privateClickMeasurement=<optimized out>) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/loader/FrameLoader.cpp:447
#18 0x00007f999af23914 in WebCore::HTMLAnchorElement::handleClick(WebCore::Event&) (this=0x7f97fe04a9c0, event=...) at /usr/include/c++/12.1.0/bits/refwrap.h:346
#19 0x00007f999ad65236 in WebCore::callDefaultEventHandlersInBubblingOrder (path=..., event=...) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/dom/EventDispatcher.cpp:64
#20 WebCore::EventDispatcher::dispatchEvent(WebCore::Node&, WebCore::Event&) (node=..., event=...) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/dom/EventDispatcher.cpp:206
#21 0x00007f999adcce7b in WebCore::simulateMouseEvent(WTF::AtomString const&, WebCore::Element&, WebCore::Event*, WebCore::SimulatedClickSource) (eventType=..., element=..., underlyingEvent=0x0, source=WebCore::SimulatedClickSource::Bindings) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/_builddir/WTF/Headers/wtf/Ref.h:143
#22 0x00007f999add07ea in WebCore::simulateClick(WebCore::Element&, WebCore::Event*, WebCore::SimulatedClickMouseEventOptions, WebCore::SimulatedClickVisualOptions, WebCore::SimulatedClickSource) (element=..., underlyingEvent=underlyingEvent@entry=0x0, mouseEventOptions=mouseEventOptions@entry=WebCore::SendNoEvents, visualOptions=visualOptions@entry=WebCore::DoNotShowPressedLook, creationOptions=creationOptions@entry=WebCore::SimulatedClickSource::Bindings) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/dom/SimulatedClick.cpp:105
#23 0x00007f999af3b872 in WebCore::HTMLElement::click() (this=<optimized out>) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/html/HTMLElement.cpp:689
#24 0x00007f999a13f5d9 in operator() (__closure=<optimized out>) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/_builddir/WebCore/DerivedSources/JSHTMLElement.cpp:4400
#25 WebCore::toJS<WebCore::IDLUndefined, WebCore::jsHTMLElementPrototypeFunction_clickBody(JSC::JSGlobalObject*, JSC::CallFrame*, IDLOperation<JSHTMLElement>::ClassParameter)::<lambda()> > (valueOrFunctor=<optimized out>, throwScope=<synthetic pointer>..., lexicalGlobalObject=<optimized out>) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/bindings/js/JSDOMConvertBase.h:165
#26 WebCore::jsHTMLElementPrototypeFunction_clickBody (castedThis=<optimized out>, callFrame=<optimized out>, lexicalGlobalObject=<optimized out>) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/_builddir/WebCore/DerivedSources/JSHTMLElement.cpp:4400
#27 WebCore::IDLOperation<WebCore::JSHTMLElement>::call<WebCore::jsHTMLElementPrototypeFunction_clickBody> (operationName=<optimized out>, callFrame=<optimized out>, lexicalGlobalObject=<optimized out>) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/WebCore/bindings/js/JSDOMOperation.h:63
#28 WebCore::jsHTMLElementPrototypeFunction_click(JSC::JSGlobalObject*, JSC::CallFrame*) (lexicalGlobalObject=<optimized out>, callFrame=<optimized out>) at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/_builddir/WebCore/DerivedSources/JSHTMLElement.cpp:4405
#29 0x00007f9938008038 in  ()
#30 0x00007ffc3fc02820 in  ()
#31 0x00007f99971bb76a in op_call_slow_return_location () at /usr/lib/debug/source/sdk/webkitgtk-6.0.bst/Source/JavaScriptCore/llint/LowLevelInterpreter.asm:1179
#32 0x0000000000000000 in  ()
Comment 1 Michael Catanzaro 2023-01-13 15:25:17 PST
Can't reproduce anymore. Don't know what changed.
Comment 2 Michael Catanzaro 2023-02-07 15:00:23 PST
Reopening because this crash is reproducible for some websites but not others:

Crash: https://dor.mo.gov/forms/MO-1040%20Instructions_2022.pdf

No crash: https://www.irs.gov/pub/irs-pdf/i1040gi.pdf
Comment 3 Michael Catanzaro 2024-04-11 14:17:11 PDT
So the problem here is PDFDocument::injectStyleAndContentScript expects to be called only once per PDFDocument and releases the PDFDocument's reference to the PDFDocumentEventListener. But the PDFDocumentEventListener is still valid even though PDFDocument::m_listener is null, and it calls PDFDocument::injectStyleAndContentScript a second time for the download. This results in a crash because the function assumes m_listener is never null (because it will never be null the first time it is called).

I'm still trying to figure out how to fix it.
Comment 4 Michael Catanzaro 2024-04-11 14:52:26 PDT
Well I can at least make it not crash, but I'm not sure how to make the download actually work. It's getting blocked by CSP:

[Error] Refused to load blob:webkit-pdfjs-viewer://pdfjs/39176f55-4f67-4515-9733-dc0f6d764506 because it does not appear in the frame-src directive of the Content Security Policy.

Not sure why this happens for https://dor.mo.gov/forms/MO-1040%20Instructions_2022.pdf but not for https://www.irs.gov/pub/irs-pdf/i1040gi.pdf
Comment 5 Michael Catanzaro 2024-04-11 17:27:37 PDT
Pull request: https://github.com/WebKit/WebKit/pull/27174
Comment 6 Michael Catanzaro 2024-04-11 17:37:05 PDT
The download failure might be related to bug #264355. Possibly the website's content security policy is blocking webkit-pdfjs-viewer://?
Comment 7 EWS 2024-04-12 10:49:00 PDT
Committed 277434@main (96e3800242ca): <https://commits.webkit.org/277434@main>

Reviewed commits have been landed. Closing PR #27174 and removing active labels.