Bug 200954 - REGRESSION (r248807): Objects stored in ElementRareData are leaked
Summary: REGRESSION (r248807): Objects stored in ElementRareData are leaked
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: New Bugs (show other bugs)
Version: Other
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Ryosuke Niwa
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2019-08-20 17:24 PDT by Ryan Haddad
Modified: 2019-08-28 08:15 PDT (History)
15 users (show)

See Also:


Attachments
Fixes the bug (1.81 KB, patch)
2019-08-23 16:53 PDT, Ryosuke Niwa
no flags Details | Formatted Diff | Diff
Address Antti's comment (5.65 KB, patch)
2019-08-27 21:09 PDT, Ryosuke Niwa
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Ryan Haddad 2019-08-20 17:24:39 PDT
@ r248804, the Mojave Leaks bot showed 401 unique leaks
https://build.webkit.org/builders/Apple%20Mojave%20%28Leaks%29/builds/4031

@ r248807, it showed 3519 unique leaks
https://build.webkit.org/builders/Apple%20Mojave%20%28Leaks%29/builds/4032
Comment 1 Radar WebKit Bug Importer 2019-08-20 17:24:58 PDT
<rdar://problem/54536113>
Comment 2 Radar WebKit Bug Importer 2019-08-20 17:25:11 PDT
<rdar://problem/54536121>
Comment 3 Ryan Haddad 2019-08-20 17:26:27 PDT
Looking at the revisions in the range, this looks like a change that could be responsible:

Don't use union to store NodeRareData* and RenderObject*
https://trac.webkit.org/changeset/248807/webkit
Comment 4 Ryan Haddad 2019-08-20 17:40:13 PDT
I can't get the leaks viewer to show any data, it hangs at loading 26/66 files
https://build.webkit.org/LeaksViewer/?url=%2Fresults%2FApple%20Mojave%20%28Leaks%29%2Fr248807%20%284032%29%2F

I see a bunch of 503 errors in the console, but clicking the links for those resources works.
Comment 5 Ryosuke Niwa 2019-08-23 16:53:21 PDT
Created attachment 377181 [details]
Fixes the bug
Comment 6 David Kilzer (:ddkilzer) 2019-08-23 16:59:24 PDT
Comment on attachment 377181 [details]
Fixes the bug

View in context: https://bugs.webkit.org/attachment.cgi?id=377181&action=review

r=me

> Source/WebCore/dom/NodeRareData.h:277
> +    virtual ~NodeRareData()
> +    { }

Do we need to declare this inline?  I recall saving space by not inlining destructors of some classes.  (I guess this is rare, though? :)
Comment 7 Ryosuke Niwa 2019-08-23 17:07:48 PDT
Comment on attachment 377181 [details]
Fixes the bug

View in context: https://bugs.webkit.org/attachment.cgi?id=377181&action=review

>> Source/WebCore/dom/NodeRareData.h:277
>> +    { }
> 
> Do we need to declare this inline?  I recall saving space by not inlining destructors of some classes.  (I guess this is rare, though? :)

Otherwise ElementRareData::~ElementRareData would make an actual function call, which would be silly.
We used to not inline virtual functions to make compilation faster but I don't think it matters for this file.
Comment 8 Ryosuke Niwa 2019-08-23 17:20:59 PDT
Committed r249076: <https://trac.webkit.org/changeset/249076>
Comment 9 Said Abou-Hallawa 2019-08-23 18:27:08 PDT
Comment on attachment 377181 [details]
Fixes the bug

View in context: https://bugs.webkit.org/attachment.cgi?id=377181&action=review

> Source/WebCore/ChangeLog:9
> +        NodeRareData didn't have a virtual destructor. As a result, member variables
> +        of ElementRareData did not get destructed properly.

Usually the complier gives an error/warning if a class is a base class and it does not have a virtual destructor. I wonder what was the reason for having the complier silent in the case of NodeRareData.
Comment 10 Ryosuke Niwa 2019-08-23 19:17:35 PDT
(In reply to Said Abou-Hallawa from comment #9)
> Comment on attachment 377181 [details]
> Fixes the bug
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=377181&action=review
> 
> > Source/WebCore/ChangeLog:9
> > +        NodeRareData didn't have a virtual destructor. As a result, member variables
> > +        of ElementRareData did not get destructed properly.
> 
> Usually the complier gives an error/warning if a class is a base class and
> it does not have a virtual destructor. I wonder what was the reason for
> having the complier silent in the case of NodeRareData.

There is no virtual function in ElementRareData. I wish clang did warn about it too.

Also confirmed that this fixed most of the leak:
https://build.webkit.org/builders/Apple%20Mojave%20%28Leaks%29/builds/4132
Comment 11 Antti Koivisto 2019-08-23 23:52:59 PDT
We shouldn't virtualize a performance sensitive type like this just to be able to destroy it (blot from unnecessary pointer, extra virtual function call, another vtable to corrupt). 

Please revert this patch and implement destruction manually like it was done before.
Comment 12 Ryosuke Niwa 2019-08-23 23:57:04 PDT
Comment on attachment 377181 [details]
Fixes the bug

I don't think it makes sense to mark this patch as r- since it has already been landed.
Comment 13 Ryosuke Niwa 2019-08-24 00:00:30 PDT
(In reply to Antti Koivisto from comment #11)
> We shouldn't virtualize a performance sensitive type like this just to be
> able to destroy it (blot from unnecessary pointer, extra virtual function
> call, another vtable to corrupt). 

I'm not sure about that. vtable pointer in NodeRareData shouldn't matter because we'd create it for a far fewer DOM nodes after r248807.

> Please revert this patch and implement destruction manually like it was done before.

I've thought about this approach and in fact wrote such a patch locally but decided not to do that because:
1. We won't be able to use unique_ptr or rather defeats the point of it if we had to leakPtr and delete it manually.
2. Relying on Node::m_flags to decide which destructor to use can result in a type confusion if Node::m_flags was heap overrun.
Comment 14 Ryosuke Niwa 2019-08-24 00:10:07 PDT
I think a good alternative is what Saam suggested which is to override deleter, and we can use a single bit of m_connectedFrameCount to record whether it's NodeRareData or not.

This will avoid (1) as well as (2). The flag in NodeRareData being heap overran is a moot point since such an overrun can also override vtable pointer.
Comment 15 Antti Koivisto 2019-08-24 00:18:49 PDT
> I've thought about this approach and in fact wrote such a patch locally but
> decided not to do that because:
> 1. We won't be able to use unique_ptr or rather defeats the point of it if
> we had to leakPtr and delete it manually.

I don't think the aesthetic concern is worth an otherwise unnecessary vptr in this particular code (it may be in other places).

> 2. Relying on Node::m_flags to decide which destructor to use can result in
> a type confusion if Node::m_flags was heap overrun.

Is vptr somehow more secure? This pattern has been used here for a long time.
Comment 16 Ryosuke Niwa 2019-08-24 00:22:27 PDT
(In reply to Antti Koivisto from comment #15)
> > I've thought about this approach and in fact wrote such a patch locally but
> > decided not to do that because:
> > 1. We won't be able to use unique_ptr or rather defeats the point of it if
> > we had to leakPtr and delete it manually.
> 
> I don't think the aesthetic concern is worth an otherwise unnecessary vptr
> in this particular code (it may be in other places).

It's not an aesthetic concern. It's easy to introduce bugs when exotic memory management mechanisms are used.

> > 2. Relying on Node::m_flags to decide which destructor to use can result in
> > a type confusion if Node::m_flags was heap overrun.
> 
> Is vptr somehow more secure? This pattern has been used here for a long time.

Yes. With vtable pointer, only memory corruption of NodeRareData itself would result in  type confusion whereas the old code would have let Node::m_nodeFlags to cause a type confusion in NodeRareData itself. Since the whole point of r248807 is not let that kind of type confusion happen (which had been a source of number of security bugs), going back to the old model isn't desirable.
Comment 17 Ryosuke Niwa 2019-08-24 00:30:54 PDT
Let's go with the deleter approach.
Comment 18 Antti Koivisto 2019-08-24 00:36:35 PDT
(In reply to Ryosuke Niwa from comment #14)
> I think a good alternative is what Saam suggested which is to override
> deleter, and we can use a single bit of m_connectedFrameCount to record
> whether it's NodeRareData or not.
> 
> This will avoid (1) as well as (2). The flag in NodeRareData being heap
> overran is a moot point since such an overrun can also override vtable
> pointer.

That seems like a good plan. 

Clearly my review of r248807 was too hasty, it shouldn't have been r+'d in the first place considering this obvious issue. Sorry about that.
Comment 19 Ryosuke Niwa 2019-08-24 00:39:38 PDT
(In reply to Antti Koivisto from comment #18)
> (In reply to Ryosuke Niwa from comment #14)
> > I think a good alternative is what Saam suggested which is to override
> > deleter, and we can use a single bit of m_connectedFrameCount to record
> > whether it's NodeRareData or not.
> > 
> > This will avoid (1) as well as (2). The flag in NodeRareData being heap
> > overran is a moot point since such an overrun can also override vtable
> > pointer.
> 
> That seems like a good plan. 
> 
> Clearly my review of r248807 was too hasty, it shouldn't have been r+'d in
> the first place considering this obvious issue. Sorry about that.

Wanna use a new bug to override deleter? I was thinking that I can just re-open this bug and post a new patch.
Comment 20 Antti Koivisto 2019-08-24 00:40:40 PDT
Re-opening is good.
Comment 21 Ryosuke Niwa 2019-08-24 01:04:04 PDT
Reopening.
Comment 22 Ryosuke Niwa 2019-08-24 01:30:33 PDT
Ugh... I have to fix makeUnique because it doesn't know how to take Deleter or default_delete. Probably have to do that on Monday.
Comment 23 Ryosuke Niwa 2019-08-27 21:09:29 PDT
Created attachment 377423 [details]
Address Antti's comment
Comment 24 Antti Koivisto 2019-08-27 22:56:27 PDT
Comment on attachment 377423 [details]
Address Antti's comment

This is a good way to do this.
Comment 25 Ryosuke Niwa 2019-08-28 08:15:53 PDT
Comment on attachment 377423 [details]
Address Antti's comment

Clearing flags on attachment: 377423

Committed r249198: <https://trac.webkit.org/changeset/249198>
Comment 26 Ryosuke Niwa 2019-08-28 08:15:55 PDT
All reviewed patches have been landed.  Closing bug.