]> gitweb.michael.orlitzky.com - libsvgtiny.git/commitdiff
src/svgtiny.c: improve select_ctx cleanup and error handling
authorMichael Orlitzky <michael@orlitzky.com>
Tue, 22 Oct 2024 11:39:50 +0000 (07:39 -0400)
committerMichael Orlitzky <michael@orlitzky.com>
Tue, 22 Oct 2024 12:06:44 +0000 (08:06 -0400)
In the "cleanup:" routine of svgtiny_parse(), we make a few
improvements:

  * The sheets are now removed from the context before destroying
    them. This avoids a potential issue where destroying the context
    itself (which we do afterwards) might try to access the sheets.

  * If we fail to obtain a pointer to a sheet, we stop processing that
    sheet. This should not happen, and if something extremely weird
    happens it can hide the problem, but that's still better than the
    segfault we'd get from trying to operate on an invalid pointer.

  * The sheets are now removed/destroyed in reverse order, last-in
    first-out.

src/svgtiny.c

index 31014936d5ae4446e03980347c698398016d2a43..53ced0afd13a543b4652734047f801555b1e1b50 100644 (file)
@@ -801,9 +801,34 @@ cleanup:
        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;
+               /* Note the use of (n_sheets - 1 - i) below to
+                * remove/destroy the sheets in reverse order, last-in
+                * first-out. */
+               css_code = css_select_ctx_get_sheet(state.select_ctx,
+                                                       n_sheets - 1 - i,
+                                                       &sheet);
+               if (css_code != CSS_OK) {
+                       if (code == svgtiny_OK) {
+                               code = svgtiny_LIBCSS_ERROR;
+                       }
+                       /* If we didn't get a new sheet, don't try to
+                        * remove/destroy whatever happens to live at
+                        * the pointer. */
+                       continue;
+               }
+               /* Remove the sheets from the context as well, since
+                * there is no promise that css_select_ctx_destroy()
+                * will not try to access them. */
+               css_code = css_select_ctx_remove_sheet(state.select_ctx, sheet);
+               if (css_code != CSS_OK) {
+                       if (code == svgtiny_OK) {
+                               code = svgtiny_LIBCSS_ERROR;
+                       }
+                       /* Don't try to destroy the sheet if removal
+                        * failed, because that would suggest that our
+                        * implied contract (that nobody else modifies
+                        * our context) has been violated. */
+                       continue;
                }
                css_code = css_stylesheet_destroy((css_stylesheet*)sheet);
                if (css_code != CSS_OK && code == svgtiny_OK) {