From dcf3a28beeacfef28843b320a03d51fb9cae9dce Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 20 Oct 2024 11:55:16 -0400 Subject: [PATCH] src/svgtiny.c: deallocate stylesheets before destroying their context We allocate stylesheets in svgtiny_parse_style_element() and append them to our global select_ctx, but the select_ctx retains only a const reference to them and is not responsible for freeing their resources. Instead, we have to do it, right before we destroy the context itself. This is a little ugly because we have to de-const the sheet references before we can destroy them. This relies on the non-local knowledge that every sheet appended to the context does in fact originate in the one function svgtiny_parse_style_element(). On the other hand, using the context to keep track of these sheets saves us the trouble of maintaining a duplicate array that would differ only in type signature. --- src/svgtiny.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/svgtiny.c b/src/svgtiny.c index b83b766..7550610 100644 --- a/src/svgtiny.c +++ b/src/svgtiny.c @@ -786,9 +786,30 @@ cleanup: dom_node_unref(svg); dom_node_unref(document); - /* Only override the true exit code with a failure from this - * "destroy" if a more meaningful error code is not already - * set. */ + /* Clean up the select_ctx and any sheets that were appended + * to it along the way. These sheets are allocated in + * svgtiny_parse_style_element(), and the only references we + * have to them are the ones in state.select_ctx->sheets. + * Those are const, but we are indeed responsible for the + * resources, so the un-const cast below is kosher. + * + * Some of these destructors can technically fail, but we only + * override the exit code with a failure from a destructor if + * a more meaningful error code is not already set. */ + unsigned int i; + uint32_t n_sheets; + const css_stylesheet* sheet; + css_select_ctx_count_sheets(state.select_ctx, &n_sheets); + for (i = 0; i < n_sheets; i++) { + css_code = css_select_ctx_get_sheet(state.select_ctx, i, &sheet); + if (css_code != CSS_OK && code == svgtiny_OK) { + code = svgtiny_LIBCSS_ERROR; + } + css_code = css_stylesheet_destroy((css_stylesheet*)sheet); + if (css_code != CSS_OK && code == svgtiny_OK) { + code = svgtiny_LIBCSS_ERROR; + } + } css_code = css_select_ctx_destroy(state.select_ctx); if (css_code != CSS_OK && code == svgtiny_OK) { code = svgtiny_LIBCSS_ERROR; @@ -876,6 +897,11 @@ svgtiny_code svgtiny_parse_style_element(dom_element *style, } dom_string_unref(data); + + /* The only reference we retain to the newly-allocated "sheet" + * is via state.select_ctx->sheets. Eventually, we will + * destroy the sheet immediately prior to destroying the + * context. */ return svgtiny_OK; } -- 2.44.2