From 24226c24e11e6bcdbbf7f63446911baa827a0db8 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> --- 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 69649eba..ff98dbf8 100644 --- a/libyang/data.py +++ b/libyang/data.py @@ -404,11 +404,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, @@ -904,11 +900,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 becb5d0c..7b3a7aa7 100644 --- a/tests/test_data.py +++ b/tests/test_data.py @@ -860,3 +860,14 @@ def test_add_defaults(self): node = dnode.find_path("/yolo-system:conf/speed") self.assertIsInstance(node, DLeaf) self.assertEqual(node.value(), 4321) + + def test_dnode_new_opaq_find_one(self): + dnode = self.ctx.parse_data_mem(self.JSON_CONFIG, "json", validate_present=True) + + hostname = dnode.find_one("hostname") + hostname.free(with_siblings=False) + + dnode.new_path("/yolo-system:conf/hostname", value=None, opt_opaq=True) + opaq_hostname = dnode.find_one("hostname") + + self.assertIsInstance(opaq_hostname, DLeaf)