Bug 212461

Summary: AutoTrader crashed while browsing search results
Product: WebKit Reporter: Dean Jackson <dino>
Component: New BugsAssignee: Dean Jackson <dino>
Status: RESOLVED FIXED    
Severity: Normal CC: cdumez, changseok, esprehn+autocc, ews-watchlist, graouts, gyuyoung.kim, kangil.han, kbr, kondapallykalyan, noam, sam, simon.fraser, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
Bug Depends on:    
Bug Blocks: 214660, 210153, 212271, 212647, 218177    
Attachments:
Description Flags
Patch
none
Patch
none
Patch sam: review+

Dean Jackson
Reported 2020-05-28 05:12:56 PDT
AutoTrader crashed while browsing search results
Attachments
Patch (28.87 KB, patch)
2020-05-28 06:39 PDT, Dean Jackson
no flags
Patch (30.70 KB, patch)
2020-05-29 17:24 PDT, Dean Jackson
no flags
Patch (31.94 KB, patch)
2020-05-29 19:13 PDT, Dean Jackson
sam: review+
Dean Jackson
Comment 1 2020-05-28 05:16:20 PDT
We've noticed lots of crashes on iOS since swapping to the ANGLE backend. In every case, the stack trace points to the main thread performing some GL operations instead of the web thread. This indicates it is specific to WebKit1, and the fact that CoreAnimation is the one that calls WebGLLayer's display method on a separate thread.
Dean Jackson
Comment 2 2020-05-28 05:16:24 PDT
Dean Jackson
Comment 3 2020-05-28 05:17:10 PDT
The fix for this looks like it might address 212251 as well.
Dean Jackson
Comment 4 2020-05-28 06:39:51 PDT
Dean Jackson
Comment 5 2020-05-28 06:49:21 PDT
I was seeing some strange failures in WebGL tests locally (test timeouts), but only on WK2. Looking forward to the EWS results. I wonder if there could be an issue with the timing of the prepare v display calls. If possible, I'd love to know there is a guarantee that display will always be called after prepare, and we'd never get two displays or prepares in a row.
Sam Weinig
Comment 6 2020-05-28 07:27:13 PDT
Comment on attachment 400450 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=400450&action=review > Source/WebCore/html/CanvasBase.cpp:55 > +HashSet<CanvasBase*>& CanvasBase::instancesRequiringPreparationForDisplay() > +{ > + static NeverDestroyed<HashSet<CanvasBase*>> instances; > + return instances; > +} I think doing this in CanvasBase is probably a mistake, given it is not safe to use this from multiple threads (and I think OffscreenCanvas works on a non-main thread). I realize this is not a problem currently, as needsPreparationForDisplay() is only true for HTMLCanvasElement, but I think to make this a bit more robust, I would move this set up to HTMLCanvasElement as well. One way to do this would be to replace needsPreparationForDisplay() with a virtual function like addToRequiringPreparationForDisplaySetIfNeeded() (but with a better name) that only HTMLCanvasElement would implement in a meaningful way. I am also generally dubious of global state like this, and if possible aim to avoid it. Can the set of HTMLCanvasElements live on the Page or something like that instead?
Dean Jackson
Comment 7 2020-05-28 07:32:03 PDT
Comment on attachment 400450 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=400450&action=review >> Source/WebCore/html/CanvasBase.cpp:55 >> +} > > I think doing this in CanvasBase is probably a mistake, given it is not safe to use this from multiple threads (and I think OffscreenCanvas works on a non-main thread). I realize this is not a problem currently, as needsPreparationForDisplay() is only true for HTMLCanvasElement, but I think to make this a bit more robust, I would move this set up to HTMLCanvasElement as well. One way to do this would be to replace needsPreparationForDisplay() with a virtual function like addToRequiringPreparationForDisplaySetIfNeeded() (but with a better name) that only HTMLCanvasElement would implement in a meaningful way. > > I am also generally dubious of global state like this, and if possible aim to avoid it. Can the set of HTMLCanvasElements live on the Page or something like that instead? I originally started with Page calling forEachDocument which would then find the HTMLCanvasElements that the Document considered dirty. Maybe that's a better solution - keep the set there. I ended up with the current approach when I realised I could take a shortcut. I'll fix it to have Page call into each Document, and the set of canvii that need preparation will live there. An HTMLCanvasElement always has a Document.
Kenneth Russell
Comment 8 2020-05-28 12:53:52 PDT
Does this address both Bug 212271 and Bug 210153? May I block those two bugs on this one since it sounds like the first fix will be done here?
Kenneth Russell
Comment 9 2020-05-28 13:05:03 PDT
Comment on attachment 400450 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=400450&action=review > Source/WebCore/html/CanvasBase.h:106 > + static HashSet<CanvasBase*>& instancesRequiringPreparationForDisplay(); In the next iteration of this patch, could you add some documentation indicating that the set of canvases is transient, and cleared out at the end of each rendered frame? That would help address concerns about the lifetime of the entries in the collection. Also wondering whether this should hold RefPtrs to the target canvases for GC safety. > Tools/TestWebKitAPI/Tests/WebKitLegacy/ios/WebGLPrepareDisplayOnWebThread.mm:102 > + [jsContext evaluateScript:@"loadColorIntoTexture(128, 128, 255, 255)"]; Is this color verified by the test harness? It would be ideal if it were.
Dean Jackson
Comment 10 2020-05-28 13:24:46 PDT
Comment on attachment 400450 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=400450&action=review >> Source/WebCore/html/CanvasBase.h:106 >> + static HashSet<CanvasBase*>& instancesRequiringPreparationForDisplay(); > > In the next iteration of this patch, could you add some documentation indicating that the set of canvases is transient, and cleared out at the end of each rendered frame? That would help address concerns about the lifetime of the entries in the collection. > > Also wondering whether this should hold RefPtrs to the target canvases for GC safety. This is a good point. I think it is a mistake in the current patch that the set is cleared by Page. Instead Page should not need to know it must clear the set, and instead call into something that does the preparation and clears itself. Also agree on RefPtr.
Dean Jackson
Comment 11 2020-05-28 13:27:41 PDT
Comment on attachment 400450 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=400450&action=review >> Tools/TestWebKitAPI/Tests/WebKitLegacy/ios/WebGLPrepareDisplayOnWebThread.mm:102 >> + [jsContext evaluateScript:@"loadColorIntoTexture(128, 128, 255, 255)"]; > > Is this color verified by the test harness? It would be ideal if it were. It isn't. The goal here was to be doing something from outside the UIWebView that would cause a conflict. However, I'm pretty sure this doesn't do that any more than simply calling draw would. I do want to get to a point where I can have an API test that manipulates the WebGL and gets back the contents of the canvas.
Dean Jackson
Comment 12 2020-05-29 17:24:28 PDT
Dean Jackson
Comment 13 2020-05-29 17:27:23 PDT
*** Bug 210153 has been marked as a duplicate of this bug. ***
Sam Weinig
Comment 14 2020-05-29 17:33:16 PDT
Comment on attachment 400638 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=400638&action=review > Source/WebCore/ChangeLog:41 > + need to run code before being composited. Collect > + these objects in a static HashSet, so that the Page You don't have a static set anymore, but a per-document one. > Source/WebCore/html/HTMLCanvasElement.cpp:1010 > + document().canvasNeedsPreparationForDisplay(this); Seems like the HTMLCanvasElement needs to also remove itself from the Document::canvasNeedsPreparationForDisplay set if its destroyed. It may also want to reset any of this state if it moves between documents. > Source/WebCore/html/HTMLCanvasElement.h:187 > + bool m_hasInformedNeedForDisplayPreparation { false }; This variable name is a bit awkward.
Dean Jackson
Comment 15 2020-05-29 18:26:57 PDT
Comment on attachment 400638 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=400638&action=review >> Source/WebCore/ChangeLog:41 >> + these objects in a static HashSet, so that the Page > > You don't have a static set anymore, but a per-document one. :thumbsup: >> Source/WebCore/html/HTMLCanvasElement.cpp:1010 >> + document().canvasNeedsPreparationForDisplay(this); > > Seems like the HTMLCanvasElement needs to also remove itself from the Document::canvasNeedsPreparationForDisplay set if its destroyed. It may also want to reset any of this state if it moves between documents. Will do. >> Source/WebCore/html/HTMLCanvasElement.h:187 >> + bool m_hasInformedNeedForDisplayPreparation { false }; > > This variable name is a bit awkward. I'm getting rid of it as I move to making Document a CanvasObserver. I worried about the (slight) cost of the hash lookup each time the canvas draws something (although the document will ask the canvas if it needs preparation before doing that).
Kenneth Russell
Comment 16 2020-05-29 18:50:52 PDT
Comment on attachment 400638 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=400638&action=review Looks good overall; a couple of questions. > Source/WebCore/ChangeLog:27 > + which had been difficult to diagnose. This block should be removed now that it's been determined that https://bugs.webkit.org/show_bug.cgi?id=212277 was the root cause. > Source/WebCore/dom/Document.h:1819 > + HashSet<HTMLCanvasElement*> m_canvasesNeedingDisplayPreparation; Is RefPtr<HTMLCanvasElement> not an option because it will introduce a graph cycle? That might address the lifetime consideration. >> Source/WebCore/html/HTMLCanvasElement.cpp:1010 >> + document().canvasNeedsPreparationForDisplay(this); > > Seems like the HTMLCanvasElement needs to also remove itself from the Document::canvasNeedsPreparationForDisplay set if its destroyed. It may also want to reset any of this state if it moves between documents. Is document() typically non-null in HTMLCanvasElement::~HTMLCanvasElement? If not, when would be a good time to unregister it?
Dean Jackson
Comment 17 2020-05-29 19:13:04 PDT
Dean Jackson
Comment 18 2020-05-31 16:13:30 PDT
Comment on attachment 400638 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=400638&action=review >> Source/WebCore/ChangeLog:27 >> + which had been difficult to diagnose. > > This block should be removed now that it's been determined that https://bugs.webkit.org/show_bug.cgi?id=212277 was the root cause. Removed. >> Source/WebCore/dom/Document.h:1819 >> + HashSet<HTMLCanvasElement*> m_canvasesNeedingDisplayPreparation; > > Is RefPtr<HTMLCanvasElement> not an option because it will introduce a graph cycle? That might address the lifetime consideration. It probably would be fine to use a RefPtr but other sets/lists on document don't. As long as the lifetime is guaranteed via CanvasObserver I think we're ok. >>>> Source/WebCore/html/HTMLCanvasElement.cpp:1010 >>>> + document().canvasNeedsPreparationForDisplay(this); >>> >>> Seems like the HTMLCanvasElement needs to also remove itself from the Document::canvasNeedsPreparationForDisplay set if its destroyed. It may also want to reset any of this state if it moves between documents. >> >> Will do. > > Is document() typically non-null in HTMLCanvasElement::~HTMLCanvasElement? If not, when would be a good time to unregister it? document() is always a Ref<>, never null.
Dean Jackson
Comment 19 2020-05-31 16:21:35 PDT
Ryan Haddad
Comment 20 2020-06-01 21:40:54 PDT
(In reply to Dean Jackson from comment #19) > Committed r262366: <https://trac.webkit.org/changeset/262366> As win-ews detected, this change broke the Windows build: C:\cygwin\worker\win10-release\build\Source\WebCore\html/HTMLCanvasElement.cpp(1028,61): error C2027: use of undefined type 'WebCore::WebGLRenderingContextBase' (compiling source file C:\cygwin\worker\win10-release\build\WebKitBuild\Release\DerivedSources\WebCore\unified-sources\UnifiedSource-950a39b6-5.cpp) [C:\cygwin\worker\win10-release\build\WebKitBuild\Release\Source\WebCore\WebCore.vcxproj] https://build.webkit.org/builders/Apple%20Win%2010%20Release%20%28Build%29/builds/13995/steps/compile-webkit/logs/stdio
Ryan Haddad
Comment 21 2020-06-02 11:51:34 PDT
(In reply to Ryan Haddad from comment #20) > (In reply to Dean Jackson from comment #19) > > Committed r262366: <https://trac.webkit.org/changeset/262366> > As win-ews detected, this change broke the Windows build: > C:\cygwin\worker\win10-release\build\Source\WebCore\html/HTMLCanvasElement. > cpp(1028,61): error C2027: use of undefined type > 'WebCore::WebGLRenderingContextBase' (compiling source file > C:\cygwin\worker\win10- > release\build\WebKitBuild\Release\DerivedSources\WebCore\unified- > sources\UnifiedSource-950a39b6-5.cpp) > [C:\cygwin\worker\win10- > release\build\WebKitBuild\Release\Source\WebCore\WebCore.vcxproj] > > https://build.webkit.org/builders/Apple%20Win%2010%20Release%20%28Build%29/ > builds/13995/steps/compile-webkit/logs/stdio This was fixed with https://trac.webkit.org/changeset/262418/webkit
Simon Fraser (smfr)
Comment 22 2020-06-03 19:47:11 PDT
Comment on attachment 400646 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=400646&action=review > Source/WebCore/dom/Document.cpp:8590 > + auto refCountedCanvas = makeRefPtr(canvas); Normally we call this protectedFoo, > Source/WebCore/dom/Document.cpp:8601 > + auto* canvas = downcast<HTMLCanvasElement>(&canvasBase); > + if (canvas->needsPreparationForDisplay()) > + m_canvasesNeedingDisplayPreparation.add(canvas); Would be nicer if canvas were a reference. > Source/WebCore/dom/Document.h:1823 > + HashSet<HTMLCanvasElement*> m_canvasesNeedingDisplayPreparation; Should this have been a weak hash set? > Source/WebCore/platform/graphics/cocoa/WebGLLayer.h:65 > + BOOL _prepared; preparedForWhat? > Tools/TestWebKitAPI/Tests/WebKitLegacy/ios/WebGLPrepareDisplayOnWebThread.mm:39 > +@interface WebGLPrepareDisplayOnWebThreadDelegate : NSObject <UIWebViewDelegate> { > +} Are the {} necessary?
Dean Jackson
Comment 23 2020-06-04 18:56:19 PDT
Note You need to log in before you can comment on or make changes to this bug.