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);
|
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 */
|
/* free a parser */
|
||||||
void parser_free(parser_t *parser)
|
void parser_free(parser_t *parser)
|
||||||
{
|
{
|
||||||
if (parser->expat)
|
if (parser->expat)
|
||||||
XML_ParserFree(parser->expat);
|
XML_ParserFree(parser->expat);
|
||||||
|
|
||||||
|
if (parser->stanza) {
|
||||||
|
_free_parent_stanza(parser->stanza);
|
||||||
|
parser->stanza = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (parser->inner_text) {
|
if (parser->inner_text) {
|
||||||
xmpp_free(parser->ctx, parser->inner_text);
|
xmpp_free(parser->ctx, parser->inner_text);
|
||||||
parser->inner_text = NULL;
|
parser->inner_text = NULL;
|
||||||
@@ -330,7 +344,7 @@ int parser_reset(parser_t *parser)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (parser->stanza) {
|
if (parser->stanza) {
|
||||||
xmpp_stanza_release(parser->stanza);
|
_free_parent_stanza(parser->stanza);
|
||||||
parser->stanza = NULL;
|
parser->stanza = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -262,13 +262,22 @@ char *parser_attr_name(xmpp_ctx_t *ctx, char *nsname)
|
|||||||
return xmpp_strdup(ctx, 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 */
|
/* free a parser */
|
||||||
void parser_free(parser_t *parser)
|
void parser_free(parser_t *parser)
|
||||||
{
|
{
|
||||||
if (parser->xmlctx)
|
if (parser->xmlctx)
|
||||||
xmlFreeParserCtxt(parser->xmlctx);
|
xmlFreeParserCtxt(parser->xmlctx);
|
||||||
if (parser->stanza)
|
if (parser->stanza)
|
||||||
xmpp_stanza_release(parser->stanza);
|
_free_parent_stanza(parser->stanza);
|
||||||
xmpp_free(parser->ctx, parser);
|
xmpp_free(parser->ctx, parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,7 +287,7 @@ int parser_reset(parser_t *parser)
|
|||||||
if (parser->xmlctx)
|
if (parser->xmlctx)
|
||||||
xmlFreeParserCtxt(parser->xmlctx);
|
xmlFreeParserCtxt(parser->xmlctx);
|
||||||
if (parser->stanza)
|
if (parser->stanza)
|
||||||
xmpp_stanza_release(parser->stanza);
|
_free_parent_stanza(parser->stanza);
|
||||||
|
|
||||||
parser->stanza = NULL;
|
parser->stanza = NULL;
|
||||||
parser->depth = 0;
|
parser->depth = 0;
|
||||||
|
|||||||
@@ -110,6 +110,10 @@ static void test_stanza_from_string(xmpp_ctx_t *ctx)
|
|||||||
assert(strcmp(buf, str) == 0);
|
assert(strcmp(buf, str) == 0);
|
||||||
xmpp_free(ctx, buf);
|
xmpp_free(ctx, buf);
|
||||||
xmpp_stanza_release(stanza);
|
xmpp_stanza_release(stanza);
|
||||||
|
|
||||||
|
/* Error path. */
|
||||||
|
stanza = xmpp_stanza_new_from_string(ctx, "<uu><uu>tt");
|
||||||
|
assert(stanza == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
|
|||||||
Reference in New Issue
Block a user