java-topology/defects/darktable/patch/darktable-0003-map-view-selection-check.patch
russell@unturf.com 13db08af50 darktable+scribus: CWE-407 scan — 6 defects (3 darktable, 3 scribus)
darktable-0001: map_locations image diff g_list_find O(N*M) MEDIUM 375x
darktable-0002: tags _tag_add_tags_to_list g_list_find O(T*L) MEDIUM 375x
darktable-0003: map view clustering g_list_find(sel_imgs) O(I²×S) HIGH 160x
scribus-0001: getSortedStyleList retList.contains O(N²) MEDIUM 167x (×4 copies)
scribus-0002: getUsedPatterns results.contains O(I×R) MEDIUM 98x
scribus-0003: Selection::addItems m_SelList.contains O(N×M) MEDIUM 2100x
2026-03-30 11:28:25 -04:00

58 lines
2.7 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-000000797
# UNDF: (leave blank)
# darktable-0003: map view clustering g_list_find(sel_imgs) inside O(I*J) loop
#
# In src/views/map.c, the map clustering code iterates over all images (i-loop)
# and for each cluster, iterates again over all images (j-loop). Inside the
# j-loop, g_list_find(sel_imgs, GINT_TO_POINTER(p[j].imgid)) performs a linear
# scan of the selected-images list (length S). Total complexity: O(I*J*S)
# which for 5000 map images with 500 selected is O(5000*5000*500) = 12.5
# billion pointer comparisons.
#
# The outer i-loop also calls g_list_find(sel_imgs, ...) for NOISE points
# and cluster heads — each O(S), contributing O(I*S) additional.
#
# Fix: build a GHashTable from sel_imgs before the loop, replace g_list_find
# with g_hash_table_contains for O(1) lookup.
#
# Severity: HIGH — map view is redrawn on every pan/zoom with the full image
# collection; O(I²×S) collapses to O(I²+S).
--- a/src/views/map.c
+++ b/src/views/map.c
@@ -1506,6 +1506,12 @@
gboolean *processed = calloc(num_clusters+1,sizeof(gboolean));
GList *sel_imgs = dt_act_on_get_images(FALSE, FALSE, FALSE);
+
+ // Build hash set for O(1) selection membership test
+ GHashTable *sel_set = g_hash_table_new(g_direct_hash, g_direct_equal);
+ for(GList *si = sel_imgs; si; si = g_list_next(si))
+ g_hash_table_add(sel_set, si->data);
+
int group = -1;
for(i = 0; i< img_count; i++)
{
@@ -1523,8 +1529,7 @@
if(sel_imgs)
- entry->selected_in_group = g_list_find((GList *)sel_imgs,
- GINT_TO_POINTER(entry->imgid))
- ? TRUE : FALSE;
+ entry->selected_in_group =
+ g_hash_table_contains(sel_set, GINT_TO_POINTER(entry->imgid));
lib->images = g_slist_prepend(lib->images, entry);
@@ -1540,8 +1545,7 @@
- entry->selected_in_group = (sel_imgs && g_list_find((GList *)sel_imgs,
- GINT_TO_POINTER(p[i].imgid)))
- ? TRUE : FALSE;
+ entry->selected_in_group = sel_imgs
+ && g_hash_table_contains(sel_set, GINT_TO_POINTER(p[i].imgid));
@@ -1557,7 +1561,7 @@
if(sel_imgs && !entry->selected_in_group)
{
- if(g_list_find((GList *)sel_imgs, GINT_TO_POINTER(p[j].imgid)))
+ if(g_hash_table_contains(sel_set, GINT_TO_POINTER(p[j].imgid)))
entry->selected_in_group = TRUE;
}
}
free(processed);
+ g_hash_table_destroy(sel_set);
g_list_free(sel_imgs);