chromium/third_party/blink/web_tests/fast/block/float/remove-float-after-anonymous-block-insert-crash.html

<!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>