Fix for bug 548463 (Disallow adopting node into a different document from adoptNode). r=sicking.

--HG--
extra : rebase_source : 5c00c3b6c65491997984d216f5c61052ccc0a77b
This commit is contained in:
Peter Van der Beken 2010-03-17 15:40:35 +01:00
parent a1e02e2b1a
commit 6469f57d89
5 changed files with 113 additions and 8 deletions

View File

@ -6056,6 +6056,10 @@ nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult)
PR_FALSE);
NS_ENSURE_SUCCESS(rv, rv);
if (adoptedNode->GetOwnerDoc() != this) {
return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
}
return CallQueryInterface(adoptedNode, aResult);
}

View File

@ -3766,13 +3766,15 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
}
nsIDocument *doc = container->GetOwnerDoc();
// DocumentType nodes are the only nodes that can have a null
// ownerDocument according to the DOM spec, and we need to allow
// inserting them w/o calling AdoptNode().
if (!container->HasSameOwnerDoc(newContent) &&
(nodeType != nsIDOMNode::DOCUMENT_TYPE_NODE ||
newContent->GetOwnerDoc())) {
nsCOMPtr<nsIDOM3Document> domDoc = do_QueryInterface(aDocument);
nsCOMPtr<nsIDOM3Document> domDoc = do_QueryInterface(doc);
if (domDoc) {
nsCOMPtr<nsIDOMNode> adoptedKid;
@ -3780,6 +3782,9 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(adoptedKid == aNewChild, "Uh, adopt node changed nodes?");
NS_ASSERTION(container->HasSameOwnerDoc(newContent) &&
doc == container->GetOwnerDoc(),
"ownerDocument changed again after adopting!");
}
}
@ -3854,12 +3859,16 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
mutated = mutated || guard.Mutated(1);
}
// If we've had any unexpeted mutations so far we need to recheck that
// If we've had any unexpected mutations so far we need to recheck that
// the child can still be inserted.
if (mutated) {
for (i = 0; i < count; ++i) {
// Get the n:th child from the array.
nsIContent* childContent = fragChildren[i];
if (!container->HasSameOwnerDoc(childContent) ||
doc != childContent->GetOwnerDoc()) {
return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
}
nsCOMPtr<nsIDOMNode> tmpNode = do_QueryInterface(childContent);
PRUint16 tmpType = 0;
@ -3911,7 +3920,6 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
}
// Fire mutation events. Optimize for the case when there are no listeners
nsIDocument* doc = container->GetOwnerDoc();
nsPIDOMWindow* window = nsnull;
if (doc && (window = doc->GetInnerWindow()) &&
window->HasMutationListeners(NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
@ -3969,6 +3977,10 @@ nsGenericElement::doReplaceOrInsertBefore(PRBool aReplace,
}
if (guard.Mutated(1)) {
if (doc != newContent->GetOwnerDoc()) {
return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
}
insPos = refContent ? container->IndexOf(refContent) :
container->GetChildCount();
if (insPos < 0) {

View File

@ -41,16 +41,14 @@
#include "nsDOMAttributeMap.h"
#include "nsIDOMNode.h"
#include "nsIMutationObserver.h"
#include "nsINode.h"
struct JSContext;
struct JSObject;
class nsINode;
class nsNodeInfoManager;
class nsIVariant;
class nsIDOMUserDataHandler;
template<class E> class nsCOMArray;
class nsCycleCollectionTraversalCallback;
struct CharacterDataChangeInfo;
class nsNodeUtils
{
@ -193,8 +191,14 @@ public:
JSObject *aNewScope,
nsCOMArray<nsINode> &aNodesWithProperties)
{
return CloneAndAdopt(aNode, PR_FALSE, PR_TRUE, aNewNodeInfoManager, aCx,
aOldScope, aNewScope, aNodesWithProperties, nsnull);
nsresult rv = CloneAndAdopt(aNode, PR_FALSE, PR_TRUE, aNewNodeInfoManager,
aCx, aOldScope, aNewScope, aNodesWithProperties,
nsnull);
if (NS_SUCCEEDED(rv)) {
nsMutationGuard::DidMutate();
}
return rv;
}
/**

View File

@ -358,6 +358,7 @@ _TEST_FILES = test_bug5141.html \
file_CSP_evalscript_main.js \
test_bug540854.html \
bug540854.sjs \
test_bug548463.html \
$(NULL)
# This test fails on the Mac for some reason

View File

@ -0,0 +1,84 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=548463
-->
<head>
<title>Test for Bug 548463</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=548463">Mozilla Bug 548463</a>
<p id="display"></p>
<iframe id="otherDoc"></iframe>
<div id="content" style="display: none">
<p id="elem1"></p>
<p id="elem2"></p>
</div>
<div id="otherContent" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 548463 **/
var otherDoc = document.getElementById("otherDoc").contentDocument;
var content = document.getElementById("content");
var elem1 = document.getElementById("elem1");
var elem2 = document.getElementById("elem2");
function testAdoptFromDOMNodeRemoved(nodeToAppend, nodeRemoved, nodeToAdopt)
{
function reparent(event)
{
if (event.target == nodeRemoved) {
nodeRemoved.removeEventListener("DOMNodeRemoved", arguments.callee, false);
otherDoc.adoptNode(nodeToAdopt);
}
}
nodeRemoved.addEventListener("DOMNodeRemoved", reparent, false);
var thrown = false;
try {
document.getElementById("otherContent").appendChild(nodeToAppend);
}
catch (e) {
thrown = true;
}
ok(thrown, "adoptNode while appending should throw");
}
var frag = document.createDocumentFragment();
frag.appendChild(elem1);
frag.appendChild(elem2);
testAdoptFromDOMNodeRemoved(frag, elem1, elem2);
content.appendChild(elem1);
testAdoptFromDOMNodeRemoved(elem1, elem1, content);
content.appendChild(elem1);
var thrown = false;
function changeOwnerDocument()
{
elem1.setUserData("foo", null, null);
otherDoc.adoptNode(elem1);
}
elem1.setUserData("foo", "bar", changeOwnerDocument);
try {
document.adoptNode(elem1);
}
catch (e) {
thrown = true;
}
ok(thrown, "adoptNode while adopting should throw");
</script>
</pre>
</body>
</html>