blob: 5cdf0a7872195a1156e63ef177cc9c01fd28a075 [file] [log] [blame]
<!DOCTYPE html>
<div id="container">
<span id="inlineBlock" style="display:inline-block; width:50px;">
<div>
<br>
<span style="padding-left:30px;"><span style="padding-left:30px;"><div id="victim" style="float:left;"></div>
</span></span>
</div>
</span>
<div id="intruder" style="display:none;"></div>
</div>
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script>
test(() => {
// The comments here assume that crbug.com/835613 is unfixed.
// Trigger layout.
document.body.offsetTop;
// Make two specific tree changes in the same style
// update. Inserting #intruder will require #container to have block
// children (it had inline children up until this point). It will
// have to insert an anonymous block around #inlineBlock. As part of
// inserting an anonymous block, all the children that get wrapped
// inside it will have their FloatingObjects cleared. The code that
// does this is in LayoutBoxModelObject::MoveChildTo(). It calls
// RemoveFloatingObjectsFromDescendants() (although that's really
// there to cope with a completely different scenario than this, and
// it's actually pretty unnecessary to clear the float in this case
// (the float is even inside a new formatting context)). Anyway, the
// bug is that we forget about RootInlineBox objects that may hold
// pointers to the FloatingObjects that it's removing.
//
// Then #intruder can be inserted after the new anonymous block.
intruder.style.display = "block";
// When we move on and remove #victim (the float), it will attempt
// to remove its FloatingObject(s).
// LayoutBlockFlow::MarkAllDescendantsWithFloatsForLayout() will
// call RemoveFloatingObject() to look for the FloatingObject, but
// it's already gone! So we won't get to the part where we'd
// otherwise mark the line that contains the FloatingObject dirty.
// It requires a rather special tree [1] to actually trigger a
// read-after-free, though.
//
// [1] The ex-float must be adjacent to an inline that's inside
// another inline, and the sum of the inline-start border/padding of
// those inlines must be larger than the inline size of the
// containing block. Aaand we need a line in front of all this
// (hence the BR).
victim.style.display = "none";
}, "PASS if no assertion failure or heap-use-after-free");
</script>