mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-19 07:26:26 +00:00
Bug 544372: Reading unitialized memory in nsNodeIterator. Also fix a minor perf issue. r=peterv
This commit is contained in:
parent
ee3589ea77
commit
1c481955b5
@ -60,11 +60,13 @@ nsNodeIterator::NodePointer::NodePointer(nsINode *aNode,
|
||||
PRBool aBeforeNode) :
|
||||
mNode(aNode),
|
||||
mBeforeNode(aBeforeNode)
|
||||
{
|
||||
{
|
||||
}
|
||||
|
||||
PRBool nsNodeIterator::NodePointer::MoveToNext(nsINode *aRoot)
|
||||
{
|
||||
NS_ASSERTION(mNode, "Iterating an uninitialized NodePointer");
|
||||
|
||||
if (mBeforeNode) {
|
||||
mBeforeNode = PR_FALSE;
|
||||
return PR_TRUE;
|
||||
@ -75,6 +77,8 @@ PRBool nsNodeIterator::NodePointer::MoveToNext(nsINode *aRoot)
|
||||
|
||||
PRBool nsNodeIterator::NodePointer::MoveToPrevious(nsINode *aRoot)
|
||||
{
|
||||
NS_ASSERTION(mNode, "Iterating an uninitialized NodePointer");
|
||||
|
||||
if (!mBeforeNode) {
|
||||
mBeforeNode = PR_TRUE;
|
||||
return PR_TRUE;
|
||||
@ -100,14 +104,24 @@ void nsNodeIterator::NodePointer::AdjustAfterInsertion(nsINode *aContainer, PRIn
|
||||
mIndexInParent++;
|
||||
}
|
||||
|
||||
void nsNodeIterator::NodePointer::AdjustAfterRemoval(nsINode* aRoot, nsINode *aContainer, nsIContent *aChild, PRInt32 aIndexInContainer)
|
||||
void nsNodeIterator::NodePointer::AdjustAfterRemoval(nsINode* aRoot,
|
||||
nsINode *aContainer,
|
||||
nsIContent *aChild,
|
||||
PRInt32 aIndexInContainer)
|
||||
{
|
||||
if (!mNode)
|
||||
return;
|
||||
|
||||
// check if earlier sibling was removed
|
||||
if (aContainer == mNodeParent && aIndexInContainer < mIndexInParent)
|
||||
mIndexInParent--;
|
||||
// Check if earlier sibling was removed.
|
||||
// The mNode != aRoot check isn't strictly needed because if mNode is the
|
||||
// root, we'll never use mNodeParent or mIndexInParent. However without the
|
||||
// check valgrind will (rightly) complain about reading uninitialized
|
||||
// memory.
|
||||
if (mNode != aRoot &&
|
||||
aContainer == mNodeParent && aIndexInContainer < mIndexInParent) {
|
||||
--mIndexInParent;
|
||||
return;
|
||||
}
|
||||
|
||||
// check if ancestor was removed
|
||||
if (!nsContentUtils::ContentIsDescendantOf(mNode, aChild))
|
||||
|
@ -89,9 +89,12 @@ private:
|
||||
void Clear() { mNode = nsnull; }
|
||||
|
||||
nsINode *mNode;
|
||||
// pointer to the parent of mNode. Can be dangling if mNode is null or points to the root
|
||||
// pointer to the parent of mNode. Can be dangling if mNode is null or
|
||||
// points to the root
|
||||
nsINode *mNodeParent;
|
||||
PRBool mBeforeNode;
|
||||
// mNode's index in mNodeParent. Uninitialized if mNodeParent is null
|
||||
// or dangling (per above comment).
|
||||
PRInt32 mIndexInParent;
|
||||
};
|
||||
|
||||
|
@ -225,6 +225,7 @@ _TEST_FILES = test_bug5141.html \
|
||||
test_NodeIterator_basics_filters.xhtml \
|
||||
test_NodeIterator_mutations_1.xhtml \
|
||||
test_NodeIterator_mutations_2.html \
|
||||
test_NodeIterator_mutations_3.html \
|
||||
test_bug28293.html \
|
||||
test_bug28293.xhtml \
|
||||
file_bug28293.sjs \
|
||||
|
161
content/base/test/test_NodeIterator_mutations_3.html
Normal file
161
content/base/test/test_NodeIterator_mutations_3.html
Normal file
@ -0,0 +1,161 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>DOM Traversal: NodeIterator: Mutations (3/x)</title>
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<span id=root><span id=B></span><span id=C></span><span id=D></span><span id=E><span id=E1><span id=E11></span></span></span></span>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
function removeNode(n) {
|
||||
n.parentNode.removeChild(n);
|
||||
}
|
||||
var initInner = $('content').innerHTML;
|
||||
var content = $('content');
|
||||
|
||||
|
||||
function resetContent() {
|
||||
content.innerHTML = initInner;
|
||||
var checkIt = document.createNodeIterator(content, NodeFilter.SHOW_ELEMENT,
|
||||
testNodeFilter, false);
|
||||
var node;
|
||||
while ((node = checkIt.nextNode()) != null) {
|
||||
if (node.id) {
|
||||
window[node.id] = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function makeSpan(id) {
|
||||
var e = document.createElement('span');
|
||||
e.id = id;
|
||||
return e;
|
||||
}
|
||||
|
||||
function testNodeFilter(n) {
|
||||
if (n.tagName == 'SPAN')
|
||||
return NodeFilter.FILTER_ACCEPT;
|
||||
return NodeFilter.FILTER_SKIP;
|
||||
}
|
||||
|
||||
function checkseq(it, root, expect) {
|
||||
var checkIt = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT,
|
||||
testNodeFilter, false);
|
||||
var printedPointer = (it.referenceNode == undefined);
|
||||
var string = '';
|
||||
var node;
|
||||
while ((node = checkIt.nextNode()) != null) {
|
||||
if (!printedPointer && it.referenceNode == node) {
|
||||
printedPointer = true;
|
||||
var s = '[' + node.id + '] ';
|
||||
if (it.pointerBeforeReferenceNode)
|
||||
string += "* " + s;
|
||||
else
|
||||
string += s + "* ";
|
||||
} else {
|
||||
string += node.id + " ";
|
||||
}
|
||||
}
|
||||
is(string.slice(0, -1), expect, "sequence check");
|
||||
}
|
||||
|
||||
resetContent();
|
||||
var it = document.createNodeIterator(E, NodeFilter.SHOW_ELEMENT,
|
||||
testNodeFilter, false);
|
||||
checkseq(it, root, "root B C D * [E] E1 E11");
|
||||
|
||||
removeNode(C);
|
||||
checkseq(it, root, "root B D * [E] E1 E11");
|
||||
|
||||
it.nextNode();
|
||||
removeNode(D);
|
||||
checkseq(it, root, "root B [E] * E1 E11");
|
||||
|
||||
it.nextNode();
|
||||
removeNode(B);
|
||||
checkseq(it, root, "root E [E1] * E11");
|
||||
|
||||
it.nextNode();
|
||||
checkseq(it, root, "root E E1 [E11] *");
|
||||
|
||||
it.nextNode();
|
||||
checkseq(it, root, "root E E1 [E11] *");
|
||||
|
||||
it.previousNode();
|
||||
it.previousNode();
|
||||
it.previousNode();
|
||||
it.previousNode();
|
||||
it.previousNode();
|
||||
checkseq(it, root, "root * [E] E1 E11");
|
||||
|
||||
resetContent();
|
||||
it = document.createNodeIterator(E, NodeFilter.SHOW_ELEMENT,
|
||||
testNodeFilter, false);
|
||||
checkseq(it, root, "root B C D * [E] E1 E11");
|
||||
|
||||
it.nextNode();
|
||||
it.nextNode();
|
||||
checkseq(it, root, "root B C D E [E1] * E11");
|
||||
|
||||
it.previousNode();
|
||||
it.previousNode();
|
||||
checkseq(it, root, "root B C D * [E] E1 E11");
|
||||
|
||||
removeNode(D);
|
||||
removeNode(B);
|
||||
checkseq(it, root, "root C * [E] E1 E11");
|
||||
|
||||
n = makeSpan('n');
|
||||
root.insertBefore(n, E);
|
||||
checkseq(it, root, "root C n * [E] E1 E11");
|
||||
|
||||
n2 = makeSpan('n2');
|
||||
root.insertBefore(n2, C);
|
||||
checkseq(it, root, "root n2 C n * [E] E1 E11");
|
||||
|
||||
resetContent();
|
||||
it = document.createNodeIterator(E, NodeFilter.SHOW_ELEMENT,
|
||||
testNodeFilter, false);
|
||||
checkseq(it, root, "root B C D * [E] E1 E11");
|
||||
|
||||
removeNode(root);
|
||||
checkseq(it, root, "root B C D * [E] E1 E11");
|
||||
|
||||
removeNode(B);
|
||||
checkseq(it, root, "root C D * [E] E1 E11");
|
||||
|
||||
removeNode(D);
|
||||
checkseq(it, root, "root C * [E] E1 E11");
|
||||
|
||||
it.nextNode();
|
||||
it.nextNode();
|
||||
it.nextNode();
|
||||
checkseq(it, root, "root C E E1 [E11] *");
|
||||
|
||||
removeNode(E1);
|
||||
checkseq(it, root, "root C [E] *");
|
||||
|
||||
n = makeSpan('n');
|
||||
root.insertBefore(n, E);
|
||||
checkseq(it, root, "root C n [E] *");
|
||||
|
||||
n2 = makeSpan('n2');
|
||||
E.appendChild(n2);
|
||||
checkseq(it, root, "root C n [E] * n2");
|
||||
|
||||
it.nextNode();
|
||||
checkseq(it, root, "root C n E [n2] *");
|
||||
|
||||
removeNode(E);
|
||||
checkseq(it, root, "root C n");
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Loading…
x
Reference in New Issue
Block a user