[njs] Fixed memory leak when exception happens at xml.exclusiveC14n().

Dmitry Volyntsev xeioex at nginx.com
Tue Jan 31 16:36:07 UTC 2023


details:   https://hg.nginx.org/njs/rev/948b167202b2
branches:  
changeset: 2034:948b167202b2
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Mon Jan 30 18:19:16 2023 -0800
description:
Fixed memory leak when exception happens at xml.exclusiveC14n().

Found by Coverity (CID 1520596).

diffstat:

 external/njs_xml_module.c |  45 ++++++++++++++++-----------------------------
 src/test/njs_unit_test.c  |   4 ++++
 2 files changed, 20 insertions(+), 29 deletions(-)

diffs (136 lines):

diff -r 4f1e0dcd3c91 -r 948b167202b2 external/njs_xml_module.c
--- a/external/njs_xml_module.c	Mon Jan 30 17:43:59 2023 -0800
+++ b/external/njs_xml_module.c	Mon Jan 30 18:19:16 2023 -0800
@@ -69,8 +69,7 @@ static njs_int_t njs_xml_node_ext_text(n
     njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
 
 static njs_xml_nset_t *njs_xml_nset_create(njs_vm_t *vm, xmlDoc *doc,
-    xmlNodeSet *nodes, njs_xml_nset_type_t type);
-static njs_xml_nset_t *njs_xml_nset_children(njs_vm_t *vm, xmlNode *parent);
+    xmlNode *current, njs_xml_nset_type_t type);
 static njs_xml_nset_t *njs_xml_nset_add(njs_xml_nset_t *nset,
     njs_xml_nset_t *add);
 static void njs_xml_nset_cleanup(void *data);
@@ -971,7 +970,6 @@ njs_xml_ext_canonicalization(njs_vm_t *v
     njs_str_t        data, string;
     njs_chb_t        chain;
     njs_bool_t       comments;
-    xmlNodeSet       *nodes;
     njs_value_t      *excluding, *prefixes;
     njs_xml_doc_t    *tree;
     njs_xml_nset_t   *nset, *children;
@@ -997,17 +995,11 @@ njs_xml_ext_canonicalization(njs_vm_t *v
     buf = xmlOutputBufferCreateIO(njs_xml_buf_write_cb, NULL, &chain, NULL);
     if (njs_slow_path(buf == NULL)) {
         njs_vm_error(vm, "xmlOutputBufferCreateIO() failed");
-        goto error;
+        return NJS_ERROR;
     }
 
     comments = njs_value_bool(njs_arg(args, nargs, 3));
 
-    nodes = xmlXPathNodeSetCreate(current);
-    if (njs_slow_path(nodes == NULL)) {
-        njs_vm_memory_error(vm);
-        goto error;
-    }
-
     excluding = njs_arg(args, nargs, 2);
 
     if (!njs_value_is_null_or_undefined(excluding)) {
@@ -1017,13 +1009,14 @@ njs_xml_ext_canonicalization(njs_vm_t *v
             goto error;
         }
 
-        nset = njs_xml_nset_create(vm, current->doc, nodes,
+        nset = njs_xml_nset_create(vm, current->doc, current,
                                    XML_NSET_TREE_NO_COMMENTS);
         if (njs_slow_path(nset == NULL)) {
             goto error;
         }
 
-        children = njs_xml_nset_children(vm, node);
+        children = njs_xml_nset_create(vm, node->doc, node,
+                                       XML_NSET_TREE_INVERT);
         if (njs_slow_path(children == NULL)) {
             goto error;
         }
@@ -1031,7 +1024,7 @@ njs_xml_ext_canonicalization(njs_vm_t *v
         nset = njs_xml_nset_add(nset, children);
 
     } else {
-        nset = njs_xml_nset_create(vm, current->doc, nodes,
+        nset = njs_xml_nset_create(vm, current->doc, current,
                                    comments ? XML_NSET_TREE
                                             : XML_NSET_TREE_NO_COMMENTS);
         if (njs_slow_path(nset == NULL)) {
@@ -1088,6 +1081,8 @@ njs_xml_ext_canonicalization(njs_vm_t *v
 
 error:
 
+    (void) xmlOutputBufferClose(buf);
+
     njs_chb_destroy(&chain);
 
     return NJS_ERROR;
@@ -1176,9 +1171,10 @@ njs_xml_attr_ext_prop_handler(njs_vm_t *
 
 
 static njs_xml_nset_t *
-njs_xml_nset_create(njs_vm_t *vm, xmlDoc *doc, xmlNodeSet *nodes,
+njs_xml_nset_create(njs_vm_t *vm, xmlDoc *doc, xmlNode *current,
     njs_xml_nset_type_t type)
 {
+    xmlNodeSet        *nodes;
     njs_xml_nset_t    *nset;
     njs_mp_cleanup_t  *cln;
 
@@ -1194,6 +1190,12 @@ njs_xml_nset_create(njs_vm_t *vm, xmlDoc
         return NULL;
     }
 
+    nodes = xmlXPathNodeSetCreate(current);
+    if (njs_slow_path(nodes == NULL)) {
+        njs_vm_memory_error(vm);
+        return NULL;
+    }
+
     cln->handler = njs_xml_nset_cleanup;
     cln->data = nset;
 
@@ -1207,21 +1209,6 @@ njs_xml_nset_create(njs_vm_t *vm, xmlDoc
 
 
 static njs_xml_nset_t *
-njs_xml_nset_children(njs_vm_t *vm, xmlNode *parent)
-{
-    xmlNodeSet  *nodes;
-
-    nodes = xmlXPathNodeSetCreate(parent);
-    if (njs_slow_path(nodes == NULL)) {
-        njs_vm_memory_error(vm);
-        return NULL;
-    }
-
-    return njs_xml_nset_create(vm, parent->doc, nodes, XML_NSET_TREE_INVERT);
-}
-
-
-static njs_xml_nset_t *
 njs_xml_nset_add(njs_xml_nset_t *nset, njs_xml_nset_t *add)
 {
     if (nset == NULL) {
diff -r 4f1e0dcd3c91 -r 948b167202b2 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Mon Jan 30 17:43:59 2023 -0800
+++ b/src/test/njs_unit_test.c	Mon Jan 30 18:19:16 2023 -0800
@@ -21545,6 +21545,10 @@ static njs_unit_test_t  njs_xml_test[] =
       njs_str("{\"note\":{\"$name\":\"note\",\"$tags\":"
               "[{\"$name\":\"to\",\"$attrs\":{\"b\":\"bar\",\"a\":\"foo\"},"
               "\"$text\":\"Tove\"},{\"$name\":\"from\",\"$text\":\"Jani\"}]}}") },
+
+    { njs_str("var xml = require('xml');"
+              "var doc = xml.parse(`<r></r>`); xml.exclusiveC14n(doc, 1)"),
+      njs_str("Error: \"excluding\" argument is not a XMLNode object") },
 };
 
 


More information about the nginx-devel mailing list