| <!-- |
| This is a stress test for crbug.com/1242269. |
| In the bug, a flaky use-after-free could happen depending on the ordering of |
| the Javascript ExecutionContext ContextDestroyed notification and GC finalization |
| of the GPUDevice in the page. Repeatingly creating an iframe, initializing a GPUDevice, |
| and then destroying the iframe can sometimes hit this and crash. This test does this |
| repeatedly with many iframes at once for 90 seconds. |
| --> |
| <head> |
| <script> |
| const iframes = []; |
| function removeOneIframe() { |
| setTimeout(function () { |
| document.body.removeChild(iframes.shift()); |
| }, Math.random() * 500); |
| } |
| |
| async function run() { |
| if (window.domAutomationController) { |
| window.domAutomationController.send('LOADED'); |
| setTimeout(() => { |
| // Succeed if don't crash within 90 seconds. |
| window.domAutomationController.send('SUCCESS'); |
| }, 90 * 1000); |
| } |
| |
| while (true) { |
| const iframe = document.createElement("iframe"); |
| iframe.setAttribute("id", "iframe"); |
| document.body.appendChild(iframe); |
| |
| iframes.push(iframe); |
| |
| const head = iframe.contentWindow.document.getElementsByTagName('head')[0]; |
| const script = iframe.contentWindow.document.createElement('script'); |
| script.type = 'text/javascript'; |
| script.innerText = ` |
| navigator.gpu.requestAdapter().then((adapter) => { |
| adapter.requestDevice().then((val) => { |
| parent.removeOneIframe(); |
| }); |
| }); |
| `; |
| head.appendChild(script); |
| |
| // Wait a bit to yield to the event loop. |
| await new Promise(resolve => setTimeout(resolve, 0)); |
| |
| // Avoid having too many iframes in flight. |
| while (iframes.length > 100) { |
| await new Promise(resolve => setTimeout(resolve, 100)); |
| } |
| } |
| } |
| </script> |
| </head> |
| |
| <body onload="run()"></body> |