WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
Bug 175444
Followup (
r220289
): RenderImageResourceStyleImage code clean up
https://bugs.webkit.org/show_bug.cgi?id=175444
Summary
Followup (r220289): RenderImageResourceStyleImage code clean up
Said Abou-Hallawa
Reported
2017-08-10 14:51:57 PDT
Adding and removing the m_renderer of the RenderImageResourceStyleImage as a client to its m_cachedImage should be done by the same class. -- If RenderImageResourceStyleImage has StyleImage of type StyleCachedImage, adding and removing m_renderer is done through StyleCachedImage::addClient() and removeClient() which are called from RenderImageResourceStyleImage::initialize() and shutdown() respectively. -- If RenderImageResourceStyleImage has StyleImage of type StyleGeneratedImage, adding and removing m_renderer will be done through RenderImageResource::setCachedImage(). This function is called from ImageLoader::updateRenderer() when the CachedImage finishes loading. It adds m_renderer as a client of the CachedImage. To remove m_renderer from the set of the CachedImage clients, RenderImageResource::setCachedImage() will be called with nullptr form RenderImageResourceStyleImage::shutdown() via RenderImageResource::shutdown().
Attachments
Patch
(10.83 KB, patch)
2017-08-10 14:55 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Patch
(10.95 KB, patch)
2017-08-10 16:13 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Archive of layout-test-results from ews115 for mac-elcapitan
(2.11 MB, application/zip)
2017-08-10 17:59 PDT
,
Build Bot
no flags
Details
Patch
(11.02 KB, patch)
2017-08-11 12:41 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Patch
(16.59 KB, patch)
2017-08-14 13:43 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Patch
(16.14 KB, patch)
2017-08-17 14:14 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Patch
(15.99 KB, patch)
2017-08-18 12:13 PDT
,
Said Abou-Hallawa
no flags
Details
Formatted Diff
Diff
Show Obsolete
(6)
View All
Add attachment
proposed patch, testcase, etc.
Said Abou-Hallawa
Comment 1
2017-08-10 14:55:14 PDT
Created
attachment 317856
[details]
Patch
Said Abou-Hallawa
Comment 2
2017-08-10 16:13:26 PDT
Created
attachment 317872
[details]
Patch
Build Bot
Comment 3
2017-08-10 17:59:42 PDT
Comment on
attachment 317872
[details]
Patch
Attachment 317872
[details]
did not pass mac-debug-ews (mac): Output:
http://webkit-queues.webkit.org/results/4292649
New failing tests: fast/canvas/webgl/css-webkit-canvas.html fast/canvas/canvas-as-image-incremental-repaint.html fast/canvas/canvas-as-image-hidpi.html fast/canvas/canvas-as-image.html fast/canvas/webgl/css-webkit-canvas-repaint.html
Build Bot
Comment 4
2017-08-10 17:59:43 PDT
Created
attachment 317896
[details]
Archive of layout-test-results from ews115 for mac-elcapitan The attached test failures were seen while running run-webkit-tests on the mac-debug-ews. Bot: ews115 Port: mac-elcapitan Platform: Mac OS X 10.11.6
Said Abou-Hallawa
Comment 5
2017-08-11 12:41:15 PDT
Created
attachment 317950
[details]
Patch
Said Abou-Hallawa
Comment 6
2017-08-11 14:38:08 PDT
(In reply to Build Bot from
comment #3
)
> Comment on
attachment 317872
[details]
> Patch > >
Attachment 317872
[details]
did not pass mac-debug-ews (mac): > Output:
http://webkit-queues.webkit.org/results/4292649
> > New failing tests: > fast/canvas/webgl/css-webkit-canvas.html > fast/canvas/canvas-as-image-incremental-repaint.html > fast/canvas/canvas-as-image-hidpi.html > fast/canvas/canvas-as-image.html > fast/canvas/webgl/css-webkit-canvas-repaint.html
These crashes were happening because I put m_styleImage->removeClient() before calling RenderImageResource::shutdown(). RenderImageResource::shutdown() has to be last becasue CSSImageGeneratorValue::removeClient() will deref() itself if m_renderer is the last client. RenderImageResource::shutdown() calls StyleGeneratedImage::image() which calls CSSImageGeneratorValue::image(). This may end up calling a function of an object after it was freed.
Darin Adler
Comment 7
2017-08-14 09:05:47 PDT
Comment on
attachment 317950
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=317950&action=review
Looks like a step in the right direction, but I think it might need a little more work.
> Source/WebCore/rendering/RenderImageResource.h:43 > virtual void initialize(RenderElement*);
This function should take a reference, not a pointer.
> Source/WebCore/rendering/RenderImageResource.h:60 > - virtual bool errorOccurred() const; > + virtual bool errorOccurred() const { return m_cachedImage && m_cachedImage->errorOccurred(); } > > virtual void setContainerSizeForRenderer(const IntSize&); > - virtual bool imageHasRelativeWidth() const; > - virtual bool imageHasRelativeHeight() const; > > - virtual LayoutSize imageSize(float multiplier) const; > - virtual LayoutSize intrinsicSize(float multiplier) const; > + virtual bool imageHasRelativeWidth() const { return m_cachedImage && m_cachedImage->imageHasRelativeWidth(); } > + virtual bool imageHasRelativeHeight() const { return m_cachedImage && m_cachedImage->imageHasRelativeHeight(); } > + > + LayoutSize imageSize(float multiplier) const { return imageSize(multiplier, CachedImage::UsedSize); } > + LayoutSize intrinsicSize(float multiplier) const { return imageSize(multiplier, CachedImage::UsedSize); }
What’s the rationale for moving these function bodies into the class definition? Maybe we want inlining?
> Source/WebCore/rendering/RenderImageResource.h:65 > protected: > + virtual LayoutSize imageSize(float multiplier, CachedImage::SizeType) const;
Why make this protected rather than private? The old version of this function was private. As far as I can tell, the protected members of this class are all things that should be private. The strange code in this patch comes from setting m_cachedImage directly in a derived class, and in my opinion making this function protected instead of private adds (slightly) to that problem.
> Source/WebCore/rendering/RenderImageResourceStyleImage.cpp:55 > + // Revert what initialize() did for m_cachedImage before calling shutdown() of the base class. > + if (m_styleImage->isCachedImage()) > + m_cachedImage = nullptr;
I don’t think this comment is clear enough. I think the issue here is that in RenderImageResourceStyleImage::initialize we set m_cachedImage, bypassing the setCachedImage function, and so we did not do an addClient and so we must not do a removeClient. Setting m_cachedImage to nullptr prevents that from happening. But this is dangerous for any call to setCachedImage, not just for the call inside the shutdown function. I think a better design requires the base class understanding that m_cachedImage is in this state so that setCachedImage will work properly. I see seven different call sites for setCachedImage and it’s not easy for me to prove to myself that none of them can be called on a RenderImageResourceStyleImage object. Maybe we can make m_cachedImage private and use setCachedImage here? Would it be OK to call addClient/removeClient on the style image?
> Source/WebCore/rendering/RenderImageResourceStyleImage.h:53 > + LayoutSize imageSize(float multiplier, CachedImage::SizeType) const override { return LayoutSize(m_styleImage->imageSize(m_renderer, multiplier)); }
Our coding style guideline stays we should use final instead of override, here and in the other functions in this class.
Said Abou-Hallawa
Comment 8
2017-08-14 13:43:57 PDT
Created
attachment 318056
[details]
Patch
Said Abou-Hallawa
Comment 9
2017-08-14 16:37:33 PDT
Comment on
attachment 317950
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=317950&action=review
>> Source/WebCore/rendering/RenderImageResource.h:43 >> virtual void initialize(RenderElement*); > > This function should take a reference, not a pointer.
Done.
>> Source/WebCore/rendering/RenderImageResource.h:60 >> + LayoutSize intrinsicSize(float multiplier) const { return imageSize(multiplier, CachedImage::UsedSize); } > > What’s the rationale for moving these function bodies into the class definition? Maybe we want inlining?
Yes I think we want inlining for these functions.
>> Source/WebCore/rendering/RenderImageResource.h:65 >> + virtual LayoutSize imageSize(float multiplier, CachedImage::SizeType) const; > > Why make this protected rather than private? The old version of this function was private. > > As far as I can tell, the protected members of this class are all things that should be private. The strange code in this patch comes from setting m_cachedImage directly in a derived class, and in my opinion making this function protected instead of private adds (slightly) to that problem.
I made all the members be private and I managed to change m_cachedImage only from the base class.
>> Source/WebCore/rendering/RenderImageResourceStyleImage.cpp:55 >> + m_cachedImage = nullptr; > > I don’t think this comment is clear enough. > > I think the issue here is that in RenderImageResourceStyleImage::initialize we set m_cachedImage, bypassing the setCachedImage function, and so we did not do an addClient and so we must not do a removeClient. Setting m_cachedImage to nullptr prevents that from happening. But this is dangerous for any call to setCachedImage, not just for the call inside the shutdown function. I think a better design requires the base class understanding that m_cachedImage is in this state so that setCachedImage will work properly. I see seven different call sites for setCachedImage and it’s not easy for me to prove to myself that none of them can be called on a RenderImageResourceStyleImage object. > > Maybe we can make m_cachedImage private and use setCachedImage here? Would it be OK to call addClient/removeClient on the style image?
I added two protected methods in the base class: initialize() and shutdown(). Each of them takes a pointer to CachedImage. If m_styleImage is of type StyleCachedImage, a pointer to the CachedImage will be passed to these new methods. RenderImageResource will not add or remove m_renderer to or from the clients of its CachedImage if the passed CachedImage is not null. This is will be handled by the calls m_styleImage->addClient) and m_styleImage->removeClient() which are invoked by this class.
>> Source/WebCore/rendering/RenderImageResourceStyleImage.h:53 >> + LayoutSize imageSize(float multiplier, CachedImage::SizeType) const override { return LayoutSize(m_styleImage->imageSize(m_renderer, multiplier)); } > > Our coding style guideline stays we should use final instead of override, here and in the other functions in this class.
Fixed.
Darin Adler
Comment 10
2017-08-15 09:10:52 PDT
Comment on
attachment 317950
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=317950&action=review
>>> Source/WebCore/rendering/RenderImageResourceStyleImage.cpp:55 >>> + m_cachedImage = nullptr; >> >> I don’t think this comment is clear enough. >> >> I think the issue here is that in RenderImageResourceStyleImage::initialize we set m_cachedImage, bypassing the setCachedImage function, and so we did not do an addClient and so we must not do a removeClient. Setting m_cachedImage to nullptr prevents that from happening. But this is dangerous for any call to setCachedImage, not just for the call inside the shutdown function. I think a better design requires the base class understanding that m_cachedImage is in this state so that setCachedImage will work properly. I see seven different call sites for setCachedImage and it’s not easy for me to prove to myself that none of them can be called on a RenderImageResourceStyleImage object. >> >> Maybe we can make m_cachedImage private and use setCachedImage here? Would it be OK to call addClient/removeClient on the style image? > > I added two protected methods in the base class: initialize() and shutdown(). Each of them takes a pointer to CachedImage. If m_styleImage is of type StyleCachedImage, a pointer to the CachedImage will be passed to these new methods. RenderImageResource will not add or remove m_renderer to or from the clients of its CachedImage if the passed CachedImage is not null. This is will be handled by the calls m_styleImage->addClient) and m_styleImage->removeClient() which are invoked by this class.
This does not resolve the potential problem I mentioned above. If a caller calls setCachedImage then we will call removeClient on m_cachedImage even though we did not call addClient when setting m_cachedImage. We can fix this a variety of ways: 1) Record the fact that we did not add a client for a given image, perhaps with a boolean alongside m_cachedImage, and respect that boolean in setCachedImage. 2) Ensure setCachedImage can never be called in such cases, somehow. 3) Add the renderer as a client even though we don’t need to, if it would do no harm. I’m sure there are other solutions as well.
Said Abou-Hallawa
Comment 11
2017-08-17 14:14:06 PDT
Created
attachment 318418
[details]
Patch
Said Abou-Hallawa
Comment 12
2017-08-17 14:20:15 PDT
Comment on
attachment 317950
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=317950&action=review
>>>> Source/WebCore/rendering/RenderImageResourceStyleImage.cpp:55 >>>> + m_cachedImage = nullptr; >>> >>> I don’t think this comment is clear enough. >>> >>> I think the issue here is that in RenderImageResourceStyleImage::initialize we set m_cachedImage, bypassing the setCachedImage function, and so we did not do an addClient and so we must not do a removeClient. Setting m_cachedImage to nullptr prevents that from happening. But this is dangerous for any call to setCachedImage, not just for the call inside the shutdown function. I think a better design requires the base class understanding that m_cachedImage is in this state so that setCachedImage will work properly. I see seven different call sites for setCachedImage and it’s not easy for me to prove to myself that none of them can be called on a RenderImageResourceStyleImage object. >>> >>> Maybe we can make m_cachedImage private and use setCachedImage here? Would it be OK to call addClient/removeClient on the style image? >> >> I added two protected methods in the base class: initialize() and shutdown(). Each of them takes a pointer to CachedImage. If m_styleImage is of type StyleCachedImage, a pointer to the CachedImage will be passed to these new methods. RenderImageResource will not add or remove m_renderer to or from the clients of its CachedImage if the passed CachedImage is not null. This is will be handled by the calls m_styleImage->addClient) and m_styleImage->removeClient() which are invoked by this class. > > This does not resolve the potential problem I mentioned above. If a caller calls setCachedImage then we will call removeClient on m_cachedImage even though we did not call addClient when setting m_cachedImage. > > We can fix this a variety of ways: > > 1) Record the fact that we did not add a client for a given image, perhaps with a boolean alongside m_cachedImage, and respect that boolean in setCachedImage. > 2) Ensure setCachedImage can never be called in such cases, somehow. > 3) Add the renderer as a client even though we don’t need to, if it would do no harm. > > I’m sure there are other solutions as well.
I added the bool RenderImageResource::m_cachedImageClientAddedExternally which is initialized to false. It will be set to true if RenderImageResource::initialize() is passed a valid styleCachedImage. In this case the StyleImage is of type StyleCachedImage. RenderImageResourceStyleImage::initialize() and shutdown() will call StyleCachedImage::addClient() and removeClient() which will take care of adding and removing the renderer as a client to the CachedImage. RenderImageResource::setCachedImage() will respect this flag by not calling CachedImage::removeClient() unless this flag is false.
Darin Adler
Comment 13
2017-08-18 09:12:22 PDT
Comment on
attachment 318418
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=318418&action=review
OK, thanks. That fixes the "setCachedImage is dangerous" issue. I’m not sure I love the name of “m_cachedImageClientAddedExternally” but I don’t have a better name to suggest at the moment. I also would have put the inline function bodies outside the class definitions to keep them cleaner, but that’s a style question upon which it seems various reasonable people differ. Side question about the original code (not the new code). What guarantees that m_cachedImage->removeClient is called if a RenderImageResource object is destroyed without first calling setCachedImage(nullptr)?
> Source/WebCore/rendering/RenderImageResource.h:46 > + RenderElement* renderer() const { return m_renderer; }
Can this be protected instead of public, please?
Said Abou-Hallawa
Comment 14
2017-08-18 12:13:09 PDT
Created
attachment 318525
[details]
Patch
Said Abou-Hallawa
Comment 15
2017-08-18 12:46:57 PDT
(In reply to Darin Adler from
comment #13
)
> Comment on
attachment 318418
[details]
> Patch > > View in context: >
https://bugs.webkit.org/attachment.cgi?id=318418&action=review
> > OK, thanks. That fixes the "setCachedImage is dangerous" issue. I’m not sure > I love the name of “m_cachedImageClientAddedExternally” but I don’t have a > better name to suggest at the moment. I also would have put the inline > function bodies outside the class definitions to keep them cleaner, but > that’s a style question upon which it seems various reasonable people differ. >
I renamed the boolean to m_cachedImageRemoveClientIsNeeded which has the opposite meaning of m_cachedImageClientAddedExternally.
> Side question about the original code (not the new code). What guarantees > that m_cachedImage->removeClient is called if a RenderImageResource object > is destroyed without first calling setCachedImage(nullptr)? >
The RenderImage class calls RenderImageResource::initialize() from RenderImage::styleWillChange() when a style is applied for the first time. It calls RenderImageResource::shutdown() from RenderImage::willBeDestroyed() is called. -- So RenderImage::willBeDestroyed() will be called before the renderer is destroyed. That means RenderImageResource::shutdown() or RenderImageResourceStyleImage::shutdown() will be called before the renderer is destroyed. If RenderImage has its ImageResource of type RenderImageResource, it will have its m_cachedImageRemoveClientIsNeeded = true since this is the default. -- So CachedImage::removeClient() will be called in RenderImageResource::setCachedImage() only if m_cachedImage isn't nullptr. This can only happen if setCachedImage() is called directly from ImageLoader::updateRenderer(). If RenderImage has its ImageResource of type RenderImageResourceStyleImage and its m_styleImage of type CachedStyleImage, its m_cachedImageRemoveClientIsNeeded = false because RenderImageResource::initialize() will be called with a valid styleCachedImage. -- So CachedImage::removeClient() won't be called in RenderImageResource::setCachedImage(). But CachedImage::removeClient() will be called form StyleCachedImage::removeClient() which is called from RenderImageResourceStyleImage::shutdown(). If RenderImage has its ImageResource of type RenderImageResourceStyleImage and its m_styleImage of type StyleGeneratedImage, its m_cachedImageRemoveClientIsNeeded = true because RenderImageResource::initialize() will be called with a null styleCachedImage. -- So CachedImage::removeClient() will be called in RenderImageResource::setCachedImage() only if m_cachedImage isn't nullptr. This can only happen if setCachedImage() is called directly from ImageLoader::updateRenderer().
> > Source/WebCore/rendering/RenderImageResource.h:46 > > + RenderElement* renderer() const { return m_renderer; } > > Can this be protected instead of public, please?
Done.
WebKit Commit Bot
Comment 16
2017-08-18 14:40:46 PDT
Comment on
attachment 318525
[details]
Patch Clearing flags on attachment: 318525 Committed
r220934
: <
http://trac.webkit.org/changeset/220934
>
WebKit Commit Bot
Comment 17
2017-08-18 14:40:47 PDT
All reviewed patches have been landed. Closing bug.
Radar WebKit Bug Importer
Comment 18
2017-08-18 14:42:12 PDT
<
rdar://problem/33970434
>
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug