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>