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>