tor-browser

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

786142-iframe.html (3679B)


      1 <!DOCTYPE html>
      2 <html>
      3 <head>
      4 <script>
      5 
      6 // Morph a slim wrapper into an XPCWN by generating a cross-compartment wrapper
      7 // for it (we Morph in WrapperFactory::PrepareForWrapping).
      8 function makeNonSlim(elem) {
      9  window.parent.someCCW = elem;
     10  delete window.parent.someCCW;
     11 }
     12 
     13 function doTest() {
     14 
     15  // Get a slim wrapper for |form|. This lives in scope 1.
     16  var form = document.getElementById('myform');
     17 
     18  // The gist here is that we want to create an input element that isn't part
     19  // of a form, so that its PreCreate hook will cause it to be parented to the
     20  // document. However, there are several considerations that make this more
     21  // complicted.
     22  //
     23  // First, the crashtest becomes non-deterministics if we morph |form| before
     24  // getting to scope 3 (as explained below). This means that we can't trigger
     25  // the PreCreate hook for |input|, because that will call WrapNativeParent
     26  // (Well... No, it won't: there is no WrapNativeParent, but there are also no
     27  // more pre-create hooks, slimwrappers, parenting to the form, or any of the
     28  // stuff this test is trying to test.)
     29  // on the form, which will end up making a cross-compartment wrapper, which
     30  // will morph form. But this puts us in a pickle, because appendChild returns
     31  // the apppended child, which will trigger the PreCreate hook in
     32  // NativeInterface2JSObject. So we do this little hack where we append a buch
     33  // of dummy <div> children to the form, and use replaceChild (which returns
     34  // the replacer, not the replacee) to stick the input elements as children of
     35  // the form.
     36  //
     37  // Second, the crashtest can also be non-deterministics if the final call to
     38  // MoveWrappers iterates over the hashtable in such a way that it fixes up
     39  // the Document before it fixes up the Input. If so, the Input will become
     40  // orphaned, and we'll detect it and fix things up at the top of MoveWrapper.
     41  // Since we can't control the hashtable ordering here, we just make 100 input
     42  // elements, to make it a near-certainty (statistically) that we'll encounter
     43  // one of them during iteration before encountering the Document.
     44  //
     45  // With all this, this testcase deterministically crashes on my machine. Whew!
     46 
     47  // Create an input element. This isn't part of a form right now, so it gets
     48  // parented to the document.
     49  var inputs = [];
     50  var placeHolders = [];
     51  for (var i = 0; i < 100; ++i) {
     52    var dummyDiv = form.appendChild(document.createElement('div'));
     53    var input = document.createElement('input');
     54    makeNonSlim(input);
     55    inputs.push(input);
     56    placeHolders.push(dummyDiv);
     57  }
     58 
     59  // Blow away the document, forcing a transplan of all the XPCWNs in scope. This
     60  // will transplant |input|, but |form| stays in the old scope (since it's slim).
     61  document.open();
     62  document.close();
     63 
     64  // Now we're in scope 2. Associate |input| with |form| so that the next call to
     65  // PreCreate will parent |input| to |form| rather than the document. But make
     66  // sure to do it with replaceChild, rather than appendChild, so that we don't
     67  // end up triggering the PreCreate hook for |form| in scope 2, which would make
     68  // make it non-slim. If we didn't, the ensuing call to MoveWrappers might find
     69  // |form| before |input| while iterating over the hashtable. If so, |form|
     70  // would be rescued as an orphan and everything would be fixed before getting to  // |input|.
     71  for (var i = 0; i < inputs.length; ++i)
     72    form.replaceChild(inputs[i], placeHolders[i]);
     73 
     74  // Blow away the document a second time. This should cause the crash in
     75  // unpatched builds.
     76  document.open();
     77  document.close();
     78 }
     79 </script>
     80 </head>
     81 <body>
     82 <form id="myform"></form>
     83 </body>
     84 </html>