tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

srcdoc-lifecycle-crash-crbug-1472607.https.html (3255B)


      1 <!doctype html>
      2 <meta charset=utf-8>
      3 <title>Chromium regression test for a Promise-related lifecycle crash in about:srcdoc iframes</title>
      4 <script src=/resources/testharness.js></script>
      5 <script src=/resources/testharnessreport.js></script>
      6 <script src=/resources/testdriver.js></script>
      7 <script src=/resources/testdriver-vendor.js></script>
      8 
      9 <body>
     10 <script>
     11 promise_test(async t => {
     12  await test_driver.set_permission({ name: 'storage-access' }, 'granted');
     13 }, "common setup");
     14 
     15 // In Chromium, this test would previously crash the renderer process. See
     16 // documentation below.
     17 promise_test(async t => {
     18  const new_iframe = document.createElement('iframe');
     19  // Having this come before `append()` keeps the iframe on the "initial empty
     20  // Document" (see [1]) while the about:srcdoc navigation loads asynchronously.
     21  //
     22  // [1]: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/dom/document.h;l=2574;drc=69640c83afac0bde8247ceac5fe259f13a5265a7.
     23  new_iframe.srcdoc = 'stuff';
     24  document.body.append(new_iframe);
     25 
     26  // It is not clear why this is needed, but it appears to reliably slow the
     27  // *next*/last `requestStorageAccess()` call down such that the IPC coming
     28  // from the browser to resolve its promise comes after the about:srcdoc
     29  // navigation commits (and after the initial empty document is detached).
     30  //
     31  // If for some reason the about:srcdoc navigation commits after this first
     32  // call to `requestStorageAccess()` resolves, then the next assert will fail.
     33  await new_iframe.contentDocument.requestStorageAccess();
     34 
     35  assert_equals(new_iframe.contentDocument.URL, "about:blank");
     36  // Now we're set up to trigger the Chromium bug that this test is exercising.
     37  // The series of events that we're relying on, and trying to trigger, is:
     38  //  1. Call `requestStorageAccess()` from the initial empty about:blank
     39  //     Document, before it gets replaced by a same-origin navigation (to
     40  //     about:srcdoc in this case).
     41  //  2. While waiting for the Promise to resolve, the Document gets replaced by
     42  //     the navigation. This new Document shares a Window with the old
     43  //     now-detached initial one (per spec) since it is the first same-origin
     44  //     navigation after the initial empty Document, and those "special" in
     45  //     that they are done with replacement, and share the same Window.
     46  //  3. After the navigation commits and the initial empty about:blank Document
     47  //     is replaced, the `requestStorageAccess()` Promise finally resolves. The
     48  //     callback runs in the renderer, since the lifetime of the callback is
     49  //     tied to the Window.
     50  //
     51  // In Chromium, this previously put us in a weird state where the callback ran
     52  // against a live Window, but was associated with a detached Document, which
     53  // bucked some assumptions and crashed the renderer; see
     54  // https://crbug.com/40937729. The root cause of this is discussed here:
     55  // https://docs.google.com/document/d/1wmvqbNZGtp1QluxW1sntZd_W1o1XsHlQd-ywNqwyu-Y/edit.
     56  return new_iframe.contentDocument.requestStorageAccess();
     57 }, "requestStorageAccess() from about:blank Document before it gets " +
     58   "replaced with a srcdoc resource does not crash the host process");
     59 </script>
     60 </body>