CESNET / libyang-cpp

C++ bindings for the libyang library
https://gerrit.cesnet.cz/q/project:CzechLight/libyang-cpp
BSD 3-Clause "New" or "Revised" License
10 stars 7 forks source link

Segmentation fault on DataNode::unlink #21

Closed safesintesi closed 4 weeks ago

safesintesi commented 4 months ago

Steps to reproduce:

auto parent = wrapUnmanagedRawNode(nodep);
auto child = wrapUnmanagedRawNode(nodec);
parent.insertChild(child);
child.unlink(); //segfault

This is because inside unlink - here - m_refs->context is accessed when m_refs is nullptr for unmanaged nodes.

void DataNode::unlink()
{
    handleLyTreeOperation(this, [this] () {
        lyd_unlink_tree(m_node);
    }, OperationScope::JustThisNode, std::make_shared<internal_refcount>(m_refs->context));
}

Since handleLyTreeOperation does not use this value if the node is unmanaged - as we have an early return in the case oldRefs is nullptr, here - I suggest inserting a check before the access.

template <typename Operation, typename OperationScope>
void handleLyTreeOperation(
    DataNode* affectedNode,
    Operation operation,
    OperationScope scope,
    std::shared_ptr<internal_refcount> newRefs)
{
    std::vector<DataNode*> wrappedSiblings{affectedNode};
    if (scope == OperationScope::AffectsFollowingSiblings) {
        //stuff ignored
    }

    auto oldRefs = affectedNode->m_refs;

    if (!oldRefs) {
        // The node is an unmanaged node, we will do nothing.
        operation();
        return;
    }
// stuff ignored
void DataNode::unlink()
{
    handleLyTreeOperation(this, [this] () {
        lyd_unlink_tree(m_node);
    }, OperationScope::JustThisNode, std::make_shared<internal_refcount>(m_refs ? m_refs->context : nullptr));
}