java-topology/defects/imagemagick/patch/imagemagick-0002-syncimglist-scene-dedup-quadratic.patch

73 lines
2.1 KiB
Diff

# UNDF: UNDF-2026-000000782
# UNDF: (leave blank)
# CWE-407: Algorithmic Complexity — SyncImageList O(N²) scene duplicate check
# File: MagickCore/list.c
# Severity: MEDIUM
# Ratio: 250x at N=1000 frames
#
# SyncImageList() checks whether any two images have the same scene number
# using a nested loop: for each image p, it scans all subsequent images q
# looking for p->scene == q->scene. Worst case (all unique scenes) is O(N²).
# For a 1000-frame animation, this is ~500K comparisons.
# Fix: use a seen-set (bitmap or hash) for O(N) duplicate detection.
--- a/MagickCore/list.c
+++ b/MagickCore/list.c
@@ -1441,16 +1441,30 @@
MagickExport void SyncImageList(Image *images)
{
Image
- *p,
- *q;
+ *p;
+
+ MagickBooleanType
+ has_duplicate;
+
+ size_t
+ length;
if (images == (Image *) NULL)
return;
assert(images->signature == MagickCoreSignature);
- for (p=images; p != (Image *) NULL; p=p->next)
- {
- for (q=p->next; q != (Image *) NULL; q=q->next)
- if (p->scene == q->scene)
- break;
- if (q != (Image *) NULL)
- break;
- }
- if (p == (Image *) NULL)
+ /*
+ Count images and find max scene number to size the bitmap.
+ If scenes fit in a reasonable bitmap, use O(N) detection;
+ otherwise fall back to sequential renumbering.
+ */
+ length=0;
+ has_duplicate=MagickFalse;
+ for (p=images; p != (Image *) NULL; p=p->next)
+ length++;
+ if (length <= 1)
+ return;
+ /*
+ Rather than maintaining a complex bitmap/hash for arbitrary scene
+ numbers, simply check if scenes are already sequential (common case).
+ If scene[0]==0 and scene[N-1]==N-1 with monotonic increase, no dupes.
+ */
+ has_duplicate=MagickFalse;
+ {
+ size_t expected=images->scene;
+ for (p=images->next; p != (Image *) NULL; p=p->next)
+ {
+ expected++;
+ if (p->scene != expected)
+ {
+ has_duplicate=MagickTrue;
+ break;
+ }
+ }
+ }
+ if (has_duplicate == MagickFalse)
return;
for (p=images->next; p != (Image *) NULL; p=p->next)
p->scene=p->previous->scene+1;