1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/xpconnect/crashtests/786142-iframe.html Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,81 @@ 1.4 +<!DOCTYPE html> 1.5 +<html> 1.6 +<head> 1.7 +<script> 1.8 + 1.9 +// Morph a slim wrapper into an XPCWN by generating a cross-compartment wrapper 1.10 +// for it (we Morph in WrapperFactory::PrepareForWrapping). 1.11 +function makeNonSlim(elem) { 1.12 + window.parent.someCCW = elem; 1.13 + delete window.parent.someCCW; 1.14 +} 1.15 + 1.16 +function doTest() { 1.17 + 1.18 + // Get a slim wrapper for |form|. This lives in scope 1. 1.19 + var form = document.getElementById('myform'); 1.20 + 1.21 + // The gist here is that we want to create an input element that isn't part 1.22 + // of a form, so that its PreCreate hook will cause it to be parented to the 1.23 + // document. However, there are several considerations that make this more 1.24 + // complicted. 1.25 + // 1.26 + // First, the crashtest becomes non-deterministics if we morph |form| before 1.27 + // getting to scope 3 (as explained below). This means that we can't trigger 1.28 + // the PreCreate hook for |input|, because that will call WrapNativeParent 1.29 + // on the form, which will end up making a cross-compartment wrapper, which 1.30 + // will morph form. But this puts us in a pickle, because appendChild returns 1.31 + // the apppended child, which will trigger the PreCreate hook in 1.32 + // NativeInterface2JSObject. So we do this little hack where we append a buch 1.33 + // of dummy <div> children to the form, and use replaceChild (which returns 1.34 + // the replacer, not the replacee) to stick the input elements as children of 1.35 + // the form. 1.36 + // 1.37 + // Second, the crashtest can also be non-deterministics if the final call to 1.38 + // MoveWrappers iterates over the hashtable in such a way that it fixes up 1.39 + // the Document before it fixes up the Input. If so, the Input will become 1.40 + // orphaned, and we'll detect it and fix things up at the top of MoveWrapper. 1.41 + // Since we can't control the hashtable ordering here, we just make 100 input 1.42 + // elements, to make it a near-certainty (statistically) that we'll encounter 1.43 + // one of them during iteration before encountering the Document. 1.44 + // 1.45 + // With all this, this testcase deterministically crashes on my machine. Whew! 1.46 + 1.47 + // Create an input element. This isn't part of a form right now, so it gets 1.48 + // parented to the document. 1.49 + var inputs = []; 1.50 + var placeHolders = []; 1.51 + for (var i = 0; i < 100; ++i) { 1.52 + var dummyDiv = form.appendChild(document.createElement('div')); 1.53 + var input = document.createElement('input'); 1.54 + makeNonSlim(input); 1.55 + inputs.push(input); 1.56 + placeHolders.push(dummyDiv); 1.57 + } 1.58 + 1.59 + // Blow away the document, forcing a transplan of all the XPCWNs in scope. This 1.60 + // will transplant |input|, but |form| stays in the old scope (since it's slim). 1.61 + document.open(); 1.62 + document.close(); 1.63 + 1.64 + // Now we're in scope 2. Associate |input| with |form| so that the next call to 1.65 + // PreCreate will parent |input| to |form| rather than the document. But make 1.66 + // sure to do it with replaceChild, rather than appendChild, so that we don't 1.67 + // end up triggering the PreCreate hook for |form| in scope 2, which would make 1.68 + // make it non-slim. If we didn't, the ensuing call to MoveWrappers might find 1.69 + // |form| before |input| while iterating over the hashtable. If so, |form| 1.70 + // would be rescued as an orphan and everything would be fixed before getting to // |input|. 1.71 + for (var i = 0; i < inputs.length; ++i) 1.72 + form.replaceChild(inputs[i], placeHolders[i]); 1.73 + 1.74 + // Blow away the document a second time. This should cause the crash in 1.75 + // unpatched builds. 1.76 + document.open(); 1.77 + document.close(); 1.78 +} 1.79 +</script> 1.80 +</head> 1.81 +<body> 1.82 +<form id="myform"></form> 1.83 +</body> 1.84 +</html>