parser: fix memory leak in error path for depth more than 1
If parser has an unfinished stanza with depth > 1, it can happen that parser->stanza points to a child. Releasing the child doesn't free the parent stanza. Instead of releasing parser->stanza in parser_reset() and parser_free(), find the top most parent and release the whole tree. Also add a test case for this memory leak.
This commit is contained in:
@@ -295,12 +295,26 @@ char *parser_attr_name(xmpp_ctx_t *ctx, char *nsname)
|
||||
return _xml_name(ctx, nsname);
|
||||
}
|
||||
|
||||
static void _free_parent_stanza(xmpp_stanza_t *stanza)
|
||||
{
|
||||
xmpp_stanza_t *parent;
|
||||
|
||||
for (parent = stanza; parent->parent != NULL; parent = parent->parent)
|
||||
;
|
||||
xmpp_stanza_release(parent);
|
||||
}
|
||||
|
||||
/* free a parser */
|
||||
void parser_free(parser_t *parser)
|
||||
{
|
||||
if (parser->expat)
|
||||
XML_ParserFree(parser->expat);
|
||||
|
||||
if (parser->stanza) {
|
||||
_free_parent_stanza(parser->stanza);
|
||||
parser->stanza = NULL;
|
||||
}
|
||||
|
||||
if (parser->inner_text) {
|
||||
xmpp_free(parser->ctx, parser->inner_text);
|
||||
parser->inner_text = NULL;
|
||||
@@ -330,7 +344,7 @@ int parser_reset(parser_t *parser)
|
||||
}
|
||||
|
||||
if (parser->stanza) {
|
||||
xmpp_stanza_release(parser->stanza);
|
||||
_free_parent_stanza(parser->stanza);
|
||||
parser->stanza = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -262,13 +262,22 @@ char *parser_attr_name(xmpp_ctx_t *ctx, char *nsname)
|
||||
return xmpp_strdup(ctx, nsname);
|
||||
}
|
||||
|
||||
static void _free_parent_stanza(xmpp_stanza_t *stanza)
|
||||
{
|
||||
xmpp_stanza_t *parent;
|
||||
|
||||
for (parent = stanza; parent->parent != NULL; parent = parent->parent)
|
||||
;
|
||||
xmpp_stanza_release(parent);
|
||||
}
|
||||
|
||||
/* free a parser */
|
||||
void parser_free(parser_t *parser)
|
||||
{
|
||||
if (parser->xmlctx)
|
||||
xmlFreeParserCtxt(parser->xmlctx);
|
||||
if (parser->stanza)
|
||||
xmpp_stanza_release(parser->stanza);
|
||||
_free_parent_stanza(parser->stanza);
|
||||
xmpp_free(parser->ctx, parser);
|
||||
}
|
||||
|
||||
@@ -278,7 +287,7 @@ int parser_reset(parser_t *parser)
|
||||
if (parser->xmlctx)
|
||||
xmlFreeParserCtxt(parser->xmlctx);
|
||||
if (parser->stanza)
|
||||
xmpp_stanza_release(parser->stanza);
|
||||
_free_parent_stanza(parser->stanza);
|
||||
|
||||
parser->stanza = NULL;
|
||||
parser->depth = 0;
|
||||
|
||||
@@ -110,6 +110,10 @@ static void test_stanza_from_string(xmpp_ctx_t *ctx)
|
||||
assert(strcmp(buf, str) == 0);
|
||||
xmpp_free(ctx, buf);
|
||||
xmpp_stanza_release(stanza);
|
||||
|
||||
/* Error path. */
|
||||
stanza = xmpp_stanza_new_from_string(ctx, "<uu><uu>tt");
|
||||
assert(stanza == NULL);
|
||||
}
|
||||
|
||||
int main()
|
||||
|
||||
Reference in New Issue
Block a user