After upgrading to 5.0.4, a script of mine that relies on the DocumentFragment
object suddenly started to segfault. Some debugging of the script found the line
 that was causing the segfault to be a call to DOMNode::replaceChild(). The
script is complex enough that it's turning out to be rather difficult to reduce
the code to a small script that can reproduce the error. I was, however, able to
track the error down with gdb:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 1024 (LWP 30537)]
0x403490ac in zif_dom_node_replace_child (ht=2, return_value=0x835c0cc,
    this_ptr=0x835c10c, return_value_used=0)
    at /home/james/php-5.0.4/ext/dom/node.c:1150
1150                                            prevsib->next = newchild;

The problem seems to be related to the fix for bug #32011 (Fixed bug #32011
(Fragments which replaced Nodes are not globaly useable)).

The relevant code from node.c being:

xmlNodePtr fragment, prevsib, nextsib;
fragment = newchild;
prevsib = oldchild->prev;
nextsib = oldchild->next;
newchild = fragment->children;

xmlUnlinkNode(oldchild);

if (prevsib == NULL && nextsib == NULL) {
    nodep->children = newchild;
    nodep->last = fragment->last;
} else {
    if (newchild) {
        prevsib->next = newchild;    <--- segfault is here
        newchild->prev = prevsib;

        fragment->last->next = nextsib;
        if (nextsib) {
            nextsib->prev = fragment->last;
        } else {
            nodep->last = fragment->last;
        }
    }
}

It turns out that I am somehow encountering a situation in which prevsib is NULL, which the code doesn't account for.

The following "fix" "works" for me:

1150,1155c1150,1151
<                                       if (prevsib) {
<                                               prevsib->next = newchild;
<                                               newchild->prev = prevsib;
<                                       } else {
<                                               nodep->children = newchild;
<                                       }
---
                                      prevsib->next = newchild;
                                      newchild->prev = prevsib;

(Note: fix and works are in quotes because a) i know very very little C, b) i know nothing about working with zend extensions, and c) the Apache error_log is reporting memory leaks due to my change :( )

I should also note that the code added for bug #32011 changes the behavior of
DocumentFragments slightly, in that prior to the fix, one was able to reference
the child nodes of a fragment after some node was replaced by the fragment. That
is no longer the case, as after the replacement, the fragment has no child 
nodes.

Now, that may in fact be the proper way to handle things... however, it was very
handy to be able to replace a single node with multiple top level nodes (what
DocumentFragments are good for in the first place), and then being able to
further process all those top level nodes by referencing the DocumentFragment,
rather than writing a bunch of code to try and figure out which nodes were newly
added.

-james

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Reply via email to