java-topology/defects/gimp/patch/gimp-0002-remove-from-layer-stack-quadratic.patch

83 lines
3 KiB
Diff
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# UNDF: UNDF-2026-000000794
# UNDF: (leave blank)
# CWE-407: Algorithmic Complexity — remove_from_layer_stack O(C × S × L)
# File: app/core/gimpimage.c
# Severity: LOW-MEDIUM
# Ratio: 100x at C=20,S=50,L=20
#
# gimp_image_remove_from_layer_stack() removes a layer (and all children
# of a group layer) from every entry in the layer_stack MRU history.
# For each child (C), it iterates all stack entries (S) and calls
# g_list_remove() which is O(L) per call (linear scan of the GList).
# Total: O(C × S × L). For a group with 20 children, 50 undo states,
# and 20 layers per state, that's 20,000 linear scans.
#
# Fix: use GHashTable per stack entry for O(1) removal, or batch
# the removals.
--- a/app/core/gimpimage.c
+++ b/app/core/gimpimage.c
@@ -2094,14 +2094,33 @@
static void
gimp_image_remove_from_layer_stack (GimpImage *image,
GimpLayer *layer)
{
GimpImagePrivate *private;
GSList *slist;
+ GList *all_to_remove = NULL;
+ GList *iter;
g_return_if_fail (GIMP_IS_IMAGE (image));
g_return_if_fail (GIMP_IS_LAYER (layer));
private = GIMP_IMAGE_GET_PRIVATE (image);
- /* Remove layer itself from the MRU layer stack. */
- for (slist = private->layer_stack; slist; slist = slist->next)
- slist->data = g_list_remove (slist->data, layer);
-
- /* Also remove all children of a group layer from the layer_stack */
+ /* Collect layer + all children into a hash set for O(1) lookup */
+ all_to_remove = g_list_prepend (all_to_remove, layer);
if (gimp_viewable_get_children (GIMP_VIEWABLE (layer)))
{
GimpContainer *stack = gimp_viewable_get_children (GIMP_VIEWABLE (layer));
- GList *children;
- GList *list;
-
- children = gimp_item_stack_get_item_list (GIMP_ITEM_STACK (stack));
-
- for (list = children; list; list = g_list_next (list))
- {
- GimpLayer *child = list->data;
-
- for (slist = private->layer_stack; slist; slist = slist->next)
- slist->data = g_list_remove (slist->data, child);
- }
-
- g_list_free (children);
+ GList *children = gimp_item_stack_get_item_list (GIMP_ITEM_STACK (stack));
+ all_to_remove = g_list_concat (all_to_remove, children);
}
+ /* Build hash set from collected layers */
+ GHashTable *remove_set = g_hash_table_new (g_direct_hash, g_direct_equal);
+ for (iter = all_to_remove; iter; iter = iter->next)
+ g_hash_table_add (remove_set, iter->data);
+ g_list_free (all_to_remove);
+
+ /* Single pass over each stack entry: filter out removed layers */
+ for (slist = private->layer_stack; slist; slist = slist->next)
+ {
+ GList *filtered = NULL;
+ for (iter = slist->data; iter; iter = iter->next)
+ {
+ if (! g_hash_table_contains (remove_set, iter->data))
+ filtered = g_list_prepend (filtered, iter->data);
+ }
+ g_list_free (slist->data);
+ slist->data = g_list_reverse (filtered);
+ }
+ g_hash_table_destroy (remove_set);
+
gimp_image_clean_layer_stack (image);
}