[xslt] Leaking from extension function



I have an extension function for parsing strings as XML, e.g.:

   xacf:parse('<hello-world/>')

which returns a node-set of the top-level nodes from the result of the
parse.

The extension function definition is attached below (it's split into two
C functions because I like to test the workings of an extension function
separately from the libxslt plumbing for the function).

The function is currently leaking the xmlNode created from
'<hello-world/>'.  The leak occurs with various libxslt versions,
including the latest SVN checkout.

The extension function is modelled after exsltStrTokenizeFunction() from
libexslt/strings.c [1].  exsltStrTokenizeFunction() uses xmlNewDocRawNode()
to create nodes that are added to its 'container', and I have other
extension functions that more closely follow the example and also use
xmlNewDocRawNode() that don't leak memory.

This function uses xmlDocCopyNodeList() to copy the nodes from the
parsed document to 'container', and it's the copy made by
xmlDocCopyNodeList() that's leaking.

Any pointers on where I'm going wrong or on ways to improve the
extension function would be appreciated.

Regards,


Tony Graham                         Tony Graham MenteithConsulting com
Director                                  W3C XSL FO SG Invited Expert
Menteith Consulting Ltd                               XML Guild member
XML, XSL and XSLT consulting, programming and training
Registered Office: 13 Kelly's Bay Beach, Skerries, Co. Dublin, Ireland
Registered in Ireland - No. 428599   http://www.menteithconsulting.com
  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
xmlroff XSL Formatter                               http://xmlroff.org
xslide Emacs mode                  http://www.menteith.com/wiki/xslide
Unicode: A Primer                               urn:isbn:0-7645-4625-2

[1] http://svn.gnome.org/viewvc/libxslt/trunk/libexslt/strings.c?view=markup

/**
 * _parse:
 * @string: String to parse
 *
 * Parses a sting into an xmlDoc.
 *
 * Returns: Parsed document.
 **/
static xmlDocPtr
_parse (xmlChar *string)
{
  return xmlReadDoc (string,
		     NULL,
		     NULL,
		     0);
}

/**
 * _parse_function:
 * @ctxt:  XPath context
 * @nargs: Number of arguments in @ctxt
 *
 * Parses a sting into a node-set
 *
 * Returns: node-set in @ctxt.
 **/
static void
_parse_function (xmlXPathParserContextPtr ctxt,
		 int nargs)
{
  xmlXPathObjectPtr ret = NULL;

  if (nargs != 1)
    {
      xmlXPathSetArityError (ctxt);
      return;
    }

  xmlChar *string = xmlXPathPopString (ctxt);
  if (xmlXPathCheckError (ctxt) || (string == NULL))
    {
      return;
    }

  xmlDocPtr doc = _parse (string);

  xmlFree (string);

  if (doc != NULL)
    {
      xsltTransformContextPtr tctxt = xsltXPathGetTransformContext (ctxt);
      if (tctxt == NULL)
	{
	  xsltTransformError (xsltXPathGetTransformContext(ctxt),
			      NULL,
			      NULL,
			      "{" XAC_NAMESPACE_XACF_URI "}:parse() :: internal error tctxt == NULL\n");
	  goto finish;
	}

      xmlDocPtr container = xsltCreateRVT (tctxt);
      if (container != NULL)
	{
	  xsltRegisterLocalRVT (tctxt,
				container);
	  ret = xmlXPathNewNodeSet (NULL);
	  if (ret != NULL)
	    {
	      xmlNodePtr new_node = xmlDocCopyNodeList (container,
							doc->children);
	      while (new_node != NULL)
		{
		  xmlXPathNodeSetAdd (ret->nodesetval,
				      new_node);
		  new_node = new_node->next;
		}
	      /*
	       * Mark it as a function result in order to avoid garbage
	       * collecting of tree fragments
	       */
	      xsltExtensionInstructionResultRegister(tctxt,
						     ret);
	    }
	}
    }

 finish:
  if (doc != NULL)
    {
      xmlFreeDoc (doc);
    }
  if (ret != NULL)
    {
      valuePush (ctxt,
		 ret);
    }
  else
    {
      xmlXPathReturnEmptyNodeSet (ctxt);
    }
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]