Bug 80020 - [Crash] Adding <content> into a ShadowRoot causes crash.
Summary: [Crash] Adding <content> into a ShadowRoot causes crash.
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: DOM (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Shinya Kawanaka
URL:
Keywords:
: 80087 (view as bug list)
Depends on:
Blocks: 72352
  Show dependency treegraph
 
Reported: 2012-03-01 04:04 PST by Shinya Kawanaka
Modified: 2012-05-30 18:56 PDT (History)
6 users (show)

See Also:


Attachments
Patch (6.40 KB, patch)
2012-03-04 21:21 PST, Shinya Kawanaka
no flags Details | Formatted Diff | Diff
Patch (6.17 KB, patch)
2012-03-05 02:30 PST, Shinya Kawanaka
no flags Details | Formatted Diff | Diff
Patch (10.31 KB, patch)
2012-03-06 20:44 PST, Shinya Kawanaka
no flags Details | Formatted Diff | Diff
Patch (9.75 KB, patch)
2012-03-11 19:09 PDT, Shinya Kawanaka
no flags Details | Formatted Diff | Diff
Patch (10.10 KB, patch)
2012-03-14 23:12 PDT, Shinya Kawanaka
no flags Details | Formatted Diff | Diff
Patch (12.05 KB, patch)
2012-03-15 00:26 PDT, Shinya Kawanaka
no flags Details | Formatted Diff | Diff
Patch for landing (12.11 KB, patch)
2012-03-15 01:11 PDT, Shinya Kawanaka
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Shinya Kawanaka 2012-03-01 04:04:39 PST
Repro:

<div>DIV1</div><div id='div2'>DIV2</div><div>DIV3</div>
<script>
var div = document.getElementById('div2');
var root = new WebKitShadowRoot(div);
root.innerHTML = "<content></content>";
</script>
Comment 1 Shinya Kawanaka 2012-03-04 21:21:17 PST
Created attachment 130055 [details]
Patch
Comment 2 Shinya Kawanaka 2012-03-05 02:30:47 PST
Created attachment 130085 [details]
Patch
Comment 3 Dimitri Glazkov (Google) 2012-03-05 09:42:11 PST
Comment on attachment 130085 [details]
Patch

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

Introducing two different paths for attaching seems like a bad idea. Can you help me understand why you need this?

> Source/WebCore/ChangeLog:8
> +        When layouting a shadow tree, we're currently assuming that the whole tree is re-created.

layouting -> laying out.

> Source/WebCore/ChangeLog:9
> +        However, when appending a child, subtree attaching occurs.

And why is that bad?

> Source/WebCore/dom/ShadowTree.cpp:41
>  ShadowTree::ShadowTree()

Also: why is this called a Tree? It's really a ShadowTreeStack, isn't it?
Comment 4 Hajime Morrita 2012-03-05 16:51:52 PST
(In reply to comment #3)
> 
> Also: why is this called a Tree? It's really a ShadowTreeStack, isn't it?
This is going to encapsulate whole Shadow subtree concept. "stack" is only part of that.
May be we should split stack (or list) to a separate object. I feel it a bit premature though.
Comment 5 Hajime Morrita 2012-03-05 18:21:22 PST
> > Also: why is this called a Tree? It's really a ShadowTreeStack, isn't it?
> This is going to encapsulate whole Shadow subtree concept. "stack" is only part of that.
> May be we should split stack (or list) to a separate object. I feel it a bit premature though.
My comment above wasn't clear enough.
Point here is that the ShadowTree class is no longer simple list, or stack.
It's now encapsulating whole shadow dom lifecycle.
That's why it's it7s renamed from ShadowRootList to ShadowTree.

One suggested name was ShadowForest.
Then I objected introducing another out-of-standard noun here.
I hope we have good name for that.
Maybe ElementShadow is sufficient.
Comment 6 Hajime Morrita 2012-03-05 18:22:13 PST
By the way, it looks attach and layout is mixed here. Which are you talking about?
Comment 7 Shinya Kawanaka 2012-03-05 18:40:54 PST
> > Source/WebCore/ChangeLog:9
> > +        However, when appending a child, subtree attaching occurs.
> 
> And why is that bad?

It's because recalculating distribution is performed in attaching. If only we attach only subtree, we cannot calculate distribution correctly.
Comment 8 Dimitri Glazkov (Google) 2012-03-05 19:35:30 PST
(In reply to comment #5)
> > > Also: why is this called a Tree? It's really a ShadowTreeStack, isn't it?
> > This is going to encapsulate whole Shadow subtree concept. "stack" is only part of that.
> > May be we should split stack (or list) to a separate object. I feel it a bit premature though.
> My comment above wasn't clear enough.
> Point here is that the ShadowTree class is no longer simple list, or stack.
> It's now encapsulating whole shadow dom lifecycle.
> That's why it's it7s renamed from ShadowRootList to ShadowTree.
> 
> One suggested name was ShadowForest.
> Then I objected introducing another out-of-standard noun here.
> I hope we have good name for that.
> Maybe ElementShadow is sufficient.

Hmm... I had a mental stumble trying to understand the purpose of this class. I am sure I won't be the only one. I understand now what you mean. This is a Tree of Trees, and a dynamically maintained structure, according to the spec. It's the ReifiedTree, right?

I wonder if, from the software engineering perspective, we would be better off by making the data-holding structures remain only Stacks and Subtrees. Then, a reified tree is just an iterator that encapsulates the logic in which this tree is perceived when rendering. Does this make sense?
Comment 9 Dimitri Glazkov (Google) 2012-03-06 08:55:18 PST
(In reply to comment #8)
> (In reply to comment #5)
> > > > Also: why is this called a Tree? It's really a ShadowTreeStack, isn't it?
> > > This is going to encapsulate whole Shadow subtree concept. "stack" is only part of that.
> > > May be we should split stack (or list) to a separate object. I feel it a bit premature though.
> > My comment above wasn't clear enough.
> > Point here is that the ShadowTree class is no longer simple list, or stack.
> > It's now encapsulating whole shadow dom lifecycle.
> > That's why it's it7s renamed from ShadowRootList to ShadowTree.
> > 
> > One suggested name was ShadowForest.
> > Then I objected introducing another out-of-standard noun here.
> > I hope we have good name for that.
> > Maybe ElementShadow is sufficient.
> 
> Hmm... I had a mental stumble trying to understand the purpose of this class. I am sure I won't be the only one. I understand now what you mean. This is a Tree of Trees, and a dynamically maintained structure, according to the spec. It's the ReifiedTree, right?
> 
> I wonder if, from the software engineering perspective, we would be better off by making the data-holding structures remain only Stacks and Subtrees. Then, a reified tree is just an iterator that encapsulates the logic in which this tree is perceived when rendering. Does this make sense?

Hayato-san is implementing this iterator in bug 79197, it seems.
Comment 10 Hajime Morrita 2012-03-06 18:42:47 PST
(In reply to comment #8)

> 
> Hmm... I had a mental stumble trying to understand the purpose of this class. I am sure I won't be the only one. I understand now what you mean. This is a Tree of Trees, and a dynamically maintained structure, according to the spec. It's the ReifiedTree, right?
> 

I'm not sure. The list of trees isn't reified without the traverser. 
I can think it as a reified view of the whole shadow stuff.

> I wonder if, from the software engineering perspective, we would be better off by making the data-holding structures remain only Stacks and Subtrees. Then, a reified tree is just an iterator that encapsulates the logic in which this tree is perceived when rendering. Does this make sense?

In the engineering perspective, I agree that.
Especially because we have no such thing like ShadowTree in the standard.

On the other hand, this assumes that we have some consistent way to traverse
the whole shadow trees, which we don't have it yet in reality.

Without such abstractions, the tree traversal code around Node, Element, ContainerNode, etc.
will be really ugly and make folks who don't care shadow DOM uncomfortable.
So I thought that isolating such shadow-aware traversals into ShadowTree was a reasonable idea.

ReifiedTreeTraversal might help in certain level, but not all,
because many existing code relies recursion. which the traverser doesn't care about.
Also there are traversals in non-reified manner. 

Also, we maintain a data for node distribution which is owned by ShadowTree. 
We need to find a place for it.

Honestly I don't have good big picture of whole multiple shadow tree stuff yet.
Hopefully shinyak@ an hayato@ show their opinion here.
Comment 11 Shinya Kawanaka 2012-03-06 20:43:19 PST
I agree that ideally we should not have ShadowTree structure.
However, as morrita says, we have to have this kind of abstraction now.

Currently we perform node distribution in attach(). However, attach() is called not only constructing whole shadow tree but also constructing subtree (e.g. appendChild(), which causes this bug).

It would be good we can check shadow tree construction is necessary or not in appendChild(), however I'm hesitating to add such check from the view point of performance. I'm thinking we should be able to know context of attach() (e.g. the element is in shadow, we need recalculate shadow tree, etc.), but it needs a lot of refactoring.

I want to remove ShadowTree finally, however I don't think the day comes near future.
Comment 12 Shinya Kawanaka 2012-03-06 20:44:27 PST
Created attachment 130530 [details]
Patch
Comment 13 Hayato Ito 2012-03-07 04:35:33 PST
I agree that a class of ShadowTree has a lot of responsibilities, such as:

- Responsibility for maintaining a stack of ShadowRoots.
- Responsibility for attach()/detach() for all nodes in Shadow DOM subtrees.
- Responsibility for managing the result of node distribution algorithm, which ReifiedTreeTraversal uses.

It's not easy to separate these concerns so far since these are tightly related. It should be, but it requires some non-trivial refactoring. I guess ShadowTree is like a 'Greatest common divisor' name.
If we can separate these concerns nicely, we don't have difficulties to have a intuitive name.

(In reply to comment #11)
> I agree that ideally we should not have ShadowTree structure.
> However, as morrita says, we have to have this kind of abstraction now.
> 
> Currently we perform node distribution in attach(). However, attach() is called not only constructing whole shadow tree but also constructing subtree (e.g. appendChild(), which causes this bug).
> 
> It would be good we can check shadow tree construction is necessary or not in appendChild(), however I'm hesitating to add such check from the view point of performance. I'm thinking we should be able to know context of attach() (e.g. the element is in shadow, we need recalculate shadow tree, etc.), but it needs a lot of refactoring.
> 
> I want to remove ShadowTree finally, however I don't think the day comes near future.
Comment 14 Dimitri Glazkov (Google) 2012-03-07 09:06:22 PST
(In reply to comment #13)
> 
> I want to remove ShadowTree finally, however I don't think the day comes near future.

Ok. Please file a bug on this.
Comment 15 Dimitri Glazkov (Google) 2012-03-07 09:47:18 PST
Comment on attachment 130530 [details]
Patch

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

I am not sure what this patch does. I am sorry. I tried to undestand, but I couldn't figure it out.

It seems to me that as soon as there's a <content> element inserted into document, we should immediately look at its treescope, reset distribution, and mark to reattach the shadow dom tree. Right?

> Source/WebCore/ChangeLog:8
> +        The problem is <content> try to select host children though it is not prepared.

What does "prepared" mean in this context? Also, the sentence is grammatically incorrect.

> Source/WebCore/ChangeLog:9
> +        Since populating host children for insertion points is performed just before

Perhaps you meant "distributing host children into insertion points"?

> Source/WebCore/ChangeLog:10
> +        attaching a shadow tree, we should recalculate whole shadow tree if <content> is

We should re-run distribution algorithm?

> Source/WebCore/ChangeLog:13
> +        However, element->appendChild() does not know the element is in a shadow tree or not.

"does not know the element" -> "is not aware whether the element"

> Source/WebCore/ChangeLog:14
> +        We have to ensure reattaching whole shadow tree here.

ensure reattaching -> ensure that we reattach

> Source/WebCore/ChangeLog:16
> +        So this patch ensures HTMLContentSelector exists only if it is prepared. If not,

Again, the word "prepared" is used here. What does it mean?

> Source/WebCore/ChangeLog:17
> +        we cannot select anything, but we have to enable a flag to reattach whole shadow tree.

we add a flag?

> Source/WebCore/ChangeLog:48
> +        When layouting a shadow tree, we're currently assuming that the whole tree is re-created.

layouting --> laying out

> Source/WebCore/ChangeLog:52
> +        do layout only when the flag is enabled.

I think this log entry is old :)

> Source/WebCore/dom/ShadowTree.h:87
> +    void populate();
> +    bool isPopulated();

are these used anywhere?

> Source/WebCore/html/shadow/HTMLContentSelector.h:138
> +    bool isSelecting() const { return m_isSelecting; }

Why do we need this?

> Source/WebCore/html/shadow/HTMLContentSelector.h:142
> +    void populateIfNesessary(Element* shadowHost);
> +    bool isPopulated() const { return m_isPopulated; }

let's keep the language closely aligned with selection: selectIfNecessary and hasSelected. It appears that hasSelected is closely related to hasCandidates: the former is always true when the latter is true.
Comment 16 Shinya Kawanaka 2012-03-08 21:24:37 PST
Sorry for late response..

Maybe I mistook updating ChangeLog in the previous patch.

I believe we all agree that the current implementation of shadow trees is far from ideal one. We have to make code clear. BTW, we have to fix the bug though.

After fixing this, let's do a lot of refactoring to make code sane.
Comment 17 Shinya Kawanaka 2012-03-08 22:03:04 PST
The name selectIfNecessary seems very confusing, since we have 'select' method already and the roles of 'select' and 'selectIfNecessary' are completely different.

I think populateIfNecessary() is better. It is taken from the spec.

BTW I agree that the current code is too messy to understand.
Comment 18 Dimitri Glazkov (Google) 2012-03-09 09:06:56 PST
(In reply to comment #17)
> The name selectIfNecessary seems very confusing, since we have 'select' method already and the roles of 'select' and 'selectIfNecessary' are completely different.
> 
> I think populateIfNecessary() is better. It is taken from the spec.
> 
> BTW I agree that the current code is too messy to understand.

Ok. There are still parts of the patch that I don't understand. Maybe Morrita-san could give it a look.
Comment 19 Dimitri Glazkov (Google) 2012-03-09 09:08:26 PST
(In reply to comment #16)
> Sorry for late response..
> 
> Maybe I mistook updating ChangeLog in the previous patch.
> 
> I believe we all agree that the current implementation of shadow trees is far from ideal one. We have to make code clear. BTW, we have to fix the bug though.
> 
> After fixing this, let's do a lot of refactoring to make code sane.

I am fine with fixing the bug, but you have a few things that are just sloppy code, like methods that aren't called anywhere.
Comment 20 Shinya Kawanaka 2012-03-11 19:09:05 PDT
Created attachment 131271 [details]
Patch
Comment 21 Shinya Kawanaka 2012-03-11 19:14:11 PDT
> I am fine with fixing the bug, but you have a few things that are just sloppy code, like methods that aren't called anywhere.

Ya, sorry, I didn't notice that there was sloppy code.
Comment 22 Shinya Kawanaka 2012-03-14 23:12:30 PDT
Created attachment 131992 [details]
Patch
Comment 23 Hajime Morrita 2012-03-14 23:40:50 PDT
Comment on attachment 131992 [details]
Patch

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

What makes this patch cryptic is that this changes both lifetime of the HTMLContentSelector and adding a re-entrant guard in distribution.
Ideally these could be done in separate patch. But I think this is OK for now to fix crash asap.

> Source/WebCore/ChangeLog:8
> +        The problem is <content> try to select host children though it is not prepared.

s/try/tries

> Source/WebCore/dom/ShadowTree.cpp:183
> +    ensureSelector()->willSelect();

It looks we no longer need ensurSelector(). that means we no longer need to allocate it in the heap.

> Source/WebCore/html/shadow/HTMLContentSelector.cpp:167
> +    ASSERT(m_phase == NotPopulatedHostChildren);

This looks too obvious.

> Source/WebCore/html/shadow/HTMLContentSelector.h:147
> +        NotPopulatedHostChildren,

Please consider to avoid negation.

> Source/WebCore/html/shadow/InsertionPoint.cpp:115
> +        selector->select(this, &m_selections);

Please consider early return. I think we can just return unless the selector is available.
Comment 24 Shinya Kawanaka 2012-03-15 00:26:17 PDT
(In reply to comment #23)
> (From update of attachment 131992 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=131992&action=review
> 
> What makes this patch cryptic is that this changes both lifetime of the HTMLContentSelector and adding a re-entrant guard in distribution.
> Ideally these could be done in separate patch. But I think this is OK for now to fix crash asap.
> 
> > Source/WebCore/ChangeLog:8
> > +        The problem is <content> try to select host children though it is not prepared.
> 
> s/try/tries

Done.

> 
> > Source/WebCore/dom/ShadowTree.cpp:183
> > +    ensureSelector()->willSelect();
> 
> It looks we no longer need ensurSelector(). that means we no longer need to allocate it in the heap.

Done.

> 
> > Source/WebCore/html/shadow/HTMLContentSelector.cpp:167
> > +    ASSERT(m_phase == NotPopulatedHostChildren);
> 
> This looks too obvious.

Done.

> 
> > Source/WebCore/html/shadow/HTMLContentSelector.h:147
> > +        NotPopulatedHostChildren,
> 
> Please consider to avoid negation.

Done.

> 
> > Source/WebCore/html/shadow/InsertionPoint.cpp:115
> > +        selector->select(this, &m_selections);
> 
> Please consider early return. I think we can just return unless the selector is available.

Done.
Comment 25 Shinya Kawanaka 2012-03-15 00:26:45 PDT
Created attachment 131997 [details]
Patch
Comment 26 Hajime Morrita 2012-03-15 01:02:26 PDT
Comment on attachment 131997 [details]
Patch

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

> Source/WebCore/ChangeLog:16
> +        So this patch ensures HTMLContentSelector exists only if it is prepared. If not,

It looks this is no longer true.
Comment 27 Shinya Kawanaka 2012-03-15 01:08:51 PDT
(In reply to comment #26)
> (From update of attachment 131997 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=131997&action=review
> 
> > Source/WebCore/ChangeLog:16
> > +        So this patch ensures HTMLContentSelector exists only if it is prepared. If not,
> 
> It looks this is no longer true.

Done.
Comment 28 Shinya Kawanaka 2012-03-15 01:11:45 PDT
Created attachment 132000 [details]
Patch for landing
Comment 29 WebKit Review Bot 2012-03-15 20:20:44 PDT
Comment on attachment 132000 [details]
Patch for landing

Clearing flags on attachment: 132000

Committed r110935: <http://trac.webkit.org/changeset/110935>
Comment 30 WebKit Review Bot 2012-03-15 20:20:49 PDT
All reviewed patches have been landed.  Closing bug.
Comment 31 Hajime Morrita 2012-05-29 00:15:20 PDT
*** Bug 80087 has been marked as a duplicate of this bug. ***