From ae3b32023ba5f9a5fbf52299785528e49ab8251a Mon Sep 17 00:00:00 2001 From: nvxf <68589039+nvxf@users.noreply.github.com> Date: Mon, 22 Jan 2024 11:23:47 +0100 Subject: [PATCH] data: fix DNode.new schema handling In case of a call to DNode.new with cdata containing an opaque node the new method tries to access cdata.schema.nodetype, which results in a NULL pointer dereference. To get the schema for an opaque node retrieve the schema from the context using the path of the node. Fixes: #73 Signed-off-by: nvxf <68589039+nvxf@users.noreply.github.com> Acked-by: Samuel Gauthier --- libyang/data.py | 22 ++++++++++++++++------ tests/test_data.py | 11 +++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/libyang/data.py b/libyang/data.py index f9d3301d..abc66cd6 100644 --- a/libyang/data.py +++ b/libyang/data.py @@ -417,11 +417,7 @@ def eval_xpath(self, xpath: str): return False def path(self) -> str: - path = lib.lyd_path(self.cdata, lib.LYD_PATH_STD, ffi.NULL, 0) - try: - return c2str(path) - finally: - lib.free(path) + return self._get_path(self.cdata) def validate( self, @@ -923,11 +919,25 @@ def _decorator(nodeclass): @classmethod def new(cls, context: "libyang.Context", cdata) -> "DNode": cdata = ffi.cast("struct lyd_node *", cdata) - nodecls = cls.NODETYPE_CLASS.get(cdata.schema.nodetype, None) + if not cdata.schema: + schemas = list(context.find_path(cls._get_path(cdata))) + if len(schemas) != 1: + raise LibyangError("Unable to determine schema") + nodecls = cls.NODETYPE_CLASS.get(schemas[0].nodetype(), None) + else: + nodecls = cls.NODETYPE_CLASS.get(cdata.schema.nodetype, None) if nodecls is None: raise TypeError("node type %s not implemented" % cdata.schema.nodetype) return nodecls(context, cdata) + @staticmethod + def _get_path(cdata) -> str: + path = lib.lyd_path(cdata, lib.LYD_PATH_STD, ffi.NULL, 0) + try: + return c2str(path) + finally: + lib.free(path) + # ------------------------------------------------------------------------------------- @DNode.register(SNode.CONTAINER) diff --git a/tests/test_data.py b/tests/test_data.py index 1824acba..6a160359 100644 --- a/tests/test_data.py +++ b/tests/test_data.py @@ -949,3 +949,14 @@ def test_dnode_insert_sibling(self): sibling = next(dnode1.siblings(include_self=False), None) self.assertIsInstance(sibling, DLeaf) self.assertEqual(sibling.cdata, dnode2.cdata) + + def test_dnode_new_opaq_find_one(self): + root = self.ctx.create_data_path(path="/yolo-system:conf") + root.new_path( + "hostname", + None, + opt_opaq=True, + ) + dnode = root.find_one("/yolo-system:conf/hostname") + + self.assertIsInstance(dnode, DLeaf)