From 0dec770faa43209b6269f266ac70b154df5fc89d Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Fri, 21 Nov 2025 16:32:15 -0800 Subject: [PATCH] XML: fixed XMLAttr object. Pointer to xmlAttr to which XMLAttr used to point might become invalid when the parent XMLNode was modified. The fix is to hold a pointer to xmlNode. --- external/njs_xml_module.c | 16 ++++++++++------ external/qjs_xml_module.c | 15 +++++++-------- test/xml/xml.t.mjs | 13 +++++++++++++ 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/external/njs_xml_module.c b/external/njs_xml_module.c index 95e5024a..24382238 100644 --- a/external/njs_xml_module.c +++ b/external/njs_xml_module.c @@ -792,8 +792,8 @@ njs_xml_node_ext_attrs(njs_vm_t *vm, njs_object_prop_t *prop, uint32_t unused, return NJS_DECLINED; } - return njs_vm_external_create(vm, retval, njs_xml_attr_proto_id, - current->properties, 0); + return njs_vm_external_create(vm, retval, njs_xml_attr_proto_id, current, + 0); } @@ -1846,7 +1846,8 @@ error: static njs_int_t njs_xml_attr_ext_prop_keys(njs_vm_t *vm, njs_value_t *value, njs_value_t *keys) { - xmlAttr *node, *current; + xmlAttr *node; + xmlNode *current; njs_int_t ret; njs_value_t *push; @@ -1861,7 +1862,7 @@ njs_xml_attr_ext_prop_keys(njs_vm_t *vm, njs_value_t *value, njs_value_t *keys) return NJS_ERROR; } - for (node = current; node != NULL; node = node->next) { + for (node = current->properties; node != NULL; node = node->next) { if (node->type != XML_ATTRIBUTE_NODE) { continue; } @@ -1888,7 +1889,8 @@ njs_xml_attr_ext_prop_handler(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *retval) { size_t size; - xmlAttr *node, *current; + xmlAttr *node; + xmlNode *current; njs_int_t ret; njs_str_t name; @@ -1904,7 +1906,7 @@ njs_xml_attr_ext_prop_handler(njs_vm_t *vm, njs_object_prop_t *prop, return NJS_DECLINED; } - for (node = current; node != NULL; node = node->next) { + for (node = current->properties; node != NULL; node = node->next) { if (node->type != XML_ATTRIBUTE_NODE) { continue; } @@ -1921,6 +1923,8 @@ njs_xml_attr_ext_prop_handler(njs_vm_t *vm, njs_object_prop_t *prop, njs_strlen(node->children->content)); } + njs_value_undefined_set(retval); + return NJS_OK; } diff --git a/external/qjs_xml_module.c b/external/qjs_xml_module.c index 8f90ee5c..274eaec0 100644 --- a/external/qjs_xml_module.c +++ b/external/qjs_xml_module.c @@ -27,7 +27,7 @@ typedef struct { typedef struct { - xmlAttr *attr; + xmlNode *node; qjs_xml_doc_t *doc; } qjs_xml_attr_t; @@ -93,7 +93,7 @@ static void qjs_xml_node_finalizer(JSRuntime *rt, JSValue val); static xmlNode *qjs_xml_node(JSContext *cx, JSValueConst val, xmlDoc **doc); static JSValue qjs_xml_attr_make(JSContext *cx, qjs_xml_doc_t *doc, - xmlAttr *attr); + xmlNode *node); static int qjs_xml_attr_get_own_property(JSContext *cx, JSPropertyDescriptor *pdesc, JSValueConst obj, JSAtom prop); static int qjs_xml_attr_get_own_property_names(JSContext *cx, @@ -955,8 +955,7 @@ qjs_xml_node_get_own_property(JSContext *cx, JSPropertyDescriptor *pdesc, pdesc->flags = JS_PROP_ENUMERABLE; pdesc->getter = JS_UNDEFINED; pdesc->setter = JS_UNDEFINED; - pdesc->value = qjs_xml_attr_make(cx, current->doc, - node->properties); + pdesc->value = qjs_xml_attr_make(cx, current->doc, node); if (JS_IsException(pdesc->value)) { return -1; } @@ -1573,7 +1572,7 @@ qjs_xml_node(JSContext *cx, JSValueConst val, xmlDoc **doc) static JSValue -qjs_xml_attr_make(JSContext *cx, qjs_xml_doc_t *doc, xmlAttr *attr) +qjs_xml_attr_make(JSContext *cx, qjs_xml_doc_t *doc, xmlNode *node) { JSValue ret; qjs_xml_attr_t *current; @@ -1584,7 +1583,7 @@ qjs_xml_attr_make(JSContext *cx, qjs_xml_doc_t *doc, xmlAttr *attr) return JS_EXCEPTION; } - current->attr = attr; + current->node = node; current->doc = doc; doc->ref_count++; @@ -1623,7 +1622,7 @@ qjs_xml_attr_get_own_property(JSContext *cx, JSPropertyDescriptor *pdesc, name.length = njs_strlen(name.start); - for (attr = current->attr; attr != NULL; attr = attr->next) { + for (attr = current->node->properties; attr != NULL; attr = attr->next) { if (attr->type != XML_ATTRIBUTE_NODE) { continue; } @@ -1685,7 +1684,7 @@ qjs_xml_attr_get_own_property_names(JSContext *cx, JSPropertyEnum **ptab, return -1; } - for (attr = current->attr; attr != NULL; attr = attr->next) { + for (attr = current->node->properties; attr != NULL; attr = attr->next) { if (attr->type != XML_ATTRIBUTE_NODE) { continue; } diff --git a/test/xml/xml.t.mjs b/test/xml/xml.t.mjs index 29e2fb41..51d80217 100644 --- a/test/xml/xml.t.mjs +++ b/test/xml/xml.t.mjs @@ -275,6 +275,19 @@ let modify_tsuite = { return xml.serializeToString(doc.note.to); }, expected: `Tove` }, + { get: (doc) => { + let attrs = doc.note.to.$attrs; + doc.note.to.removeAllAttributes(); + return attrs.a; + }, + expected: undefined }, + { get: (doc) => { + let to = doc.note.to; + let attrs = doc.note.to.$attrs; + to.removeAllAttributes(); + return attrs.a; + }, + expected: undefined }, { get: (doc) => { delete doc.note.to.$attr$a; return xml.serializeToString(doc.note.to); -- 2.47.3