From 95d580aa3ab763555785d5d581acefcd1cda57c7 Mon Sep 17 00:00:00 2001 From: Jehan Date: Tue, 28 Oct 2025 15:48:57 +0100 Subject: [PATCH] Issue #14014: fix removing parasite using already freed parasite's name. gimp_image_set_simulation_intent() attachs a "image-simulation-intent" parasite which means that it first detaches and frees the one which was deserialized from the XCF. When calling gimp_parasite_get_name() on this later on, we were working on a dangling pointer. It means that the fact we didn't have crashes most of the time was the unexpected part, not the crash itself! Same for gimp_image_set_simulation_bpc() and "image-simulation-bpc" parasite. The fix is to swap the order of statements to first detach the parasite. --- app/xcf/xcf-load.c | 53 +++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/app/xcf/xcf-load.c b/app/xcf/xcf-load.c index f9a06f7241..b7803b981b 100644 --- a/app/xcf/xcf-load.c +++ b/app/xcf/xcf-load.c @@ -376,28 +376,32 @@ xcf_load_image (Gimp *gimp, "image-simulation-intent"); if (parasite) { - guint32 parasite_size; - const guint8 *intent; - GimpImagePrivate *private = GIMP_IMAGE_GET_PRIVATE (image); + guint32 parasite_size; + GimpImagePrivate *private = GIMP_IMAGE_GET_PRIVATE (image); + const guint8 *data; + GimpColorRenderingIntent intent; - intent = (const guint8 *) gimp_parasite_get_data (parasite, ¶site_size); + data = (const guint8 *) gimp_parasite_get_data (parasite, ¶site_size); + intent = (GimpColorRenderingIntent) *data; + + gimp_parasite_list_remove (private->parasites, + gimp_parasite_get_name (parasite)); if (parasite_size == 1) { - if (*intent != GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL && - *intent != GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC && - *intent != GIMP_COLOR_RENDERING_INTENT_SATURATION && - *intent != GIMP_COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC) + if (intent != GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL && + intent != GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC && + intent != GIMP_COLOR_RENDERING_INTENT_SATURATION && + intent != GIMP_COLOR_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC) { gimp_message (info->gimp, G_OBJECT (info->progress), GIMP_MESSAGE_ERROR, "Unknown simulation rendering intent: %d", - *intent); + intent); } else { - gimp_image_set_simulation_intent (image, - (GimpColorRenderingIntent) *intent); + gimp_image_set_simulation_intent (image, intent); } } else @@ -406,9 +410,6 @@ xcf_load_image (Gimp *gimp, GIMP_MESSAGE_ERROR, "Invalid simulation intent data"); } - - gimp_parasite_list_remove (private->parasites, - gimp_parasite_get_name (parasite)); } @@ -418,18 +419,19 @@ xcf_load_image (Gimp *gimp, if (parasite) { guint32 parasite_size; - const guint8 *bpc; - gboolean status = FALSE; GimpImagePrivate *private = GIMP_IMAGE_GET_PRIVATE (image); + const guint8 *data; + gboolean bpc; - bpc = (const guint8 *) gimp_parasite_get_data (parasite, ¶site_size); + data = (const guint8 *) gimp_parasite_get_data (parasite, ¶site_size); + bpc = *data ? TRUE : FALSE; + + gimp_parasite_list_remove (private->parasites, + gimp_parasite_get_name (parasite)); if (parasite_size == 1) { - if (*bpc) - status = TRUE; - - gimp_image_set_simulation_bpc (image, status); + gimp_image_set_simulation_bpc (image, bpc); } else { @@ -437,9 +439,6 @@ xcf_load_image (Gimp *gimp, GIMP_MESSAGE_ERROR, "Invalid simulation bpc data"); } - - gimp_parasite_list_remove (private->parasites, - gimp_parasite_get_name (parasite)); } /* check for a GimpGrid parasite */ @@ -479,6 +478,9 @@ xcf_load_image (Gimp *gimp, g_free (meta_string); } + gimp_parasite_list_remove (private->parasites, + gimp_parasite_get_name (parasite)); + if (metadata) { has_metadata = TRUE; @@ -486,9 +488,6 @@ xcf_load_image (Gimp *gimp, gimp_image_set_metadata (image, metadata, FALSE); g_object_unref (metadata); } - - gimp_parasite_list_remove (private->parasites, - gimp_parasite_get_name (parasite)); } /* check for symmetry parasites */