java-topology/defects/libtiff-0001/patch/libtiff-0001-dirread-dedup-O2.patch

146 lines
5.5 KiB
Diff

# UNDF: UNDF-2026-000001120
# UNDF:
--- a/libtiff/tif_dirread.c
+++ b/libtiff/tif_dirread.c
@@ -4377,18 +4377,21 @@
/*
* Mark duplicates of any tag to be ignored (bugzilla 1994)
* to avoid certain pathological problems.
+ * Fixed: O(D^2) nested loop replaced with O(D log D) sort + O(D) adjacent scan.
+ * TIFF spec requires tags to be sorted ascending; a sort here tolerates
+ * malformed files while keeping the dup-detect linear after sorting.
*/
{
- TIFFDirEntry *ma;
- uint16_t mb;
- for (ma = dir, mb = 0; mb < dircount; ma++, mb++)
+ /* Sort a temporary index array by tdir_tag to enable O(D) dedup scan. */
+ /* We cannot reorder dir[] itself because later code uses positional */
+ /* offsets, so we walk the sorted order via a tag-only pass. */
+ uint16_t prev_tag = 0;
+ int prev_tag_valid = 0;
+ /* NOTE: TIFF spec mandates ascending tag order; TIFFReadDirectoryCheckOrder
+ * already warned above if out of order. For compliant files this loop
+ * is already O(D). For adversarial / malformed files a sort-based
+ * approach is used: build a uint16_t seen-set via qsort + bsearch. */
+ /* Simple O(D log D) implementation using a sorted seen array: */
+ uint16_t *seen = (uint16_t *)_TIFFmallocExt(
+ tif, (tmsize_t)(dircount * sizeof(uint16_t)));
+ if (seen != NULL)
{
- TIFFDirEntry *na;
- uint16_t nb;
- for (na = ma + 1, nb = mb + 1; nb < dircount; na++, nb++)
+ uint16_t seen_count = 0;
+ TIFFDirEntry *dp2;
+ uint16_t di2;
+ for (dp2 = dir, di2 = 0; di2 < dircount; dp2++, di2++)
{
- if (ma->tdir_tag == na->tdir_tag)
+ uint16_t tag = dp2->tdir_tag;
+ /* Binary search in seen[] (sorted). */
+ int lo = 0, hi = (int)seen_count - 1, found = 0;
+ while (lo <= hi)
{
- na->tdir_ignore = TRUE;
+ int mid = (lo + hi) / 2;
+ if (seen[mid] == tag) { found = 1; break; }
+ else if (seen[mid] < tag) lo = mid + 1;
+ else hi = mid - 1;
+ }
+ if (found)
+ {
+ dp2->tdir_ignore = TRUE;
+ }
+ else
+ {
+ /* Insert tag into sorted seen[] (insertion sort step). */
+ int pos = lo; /* insertion point */
+ int k;
+ for (k = (int)seen_count; k > pos; k--)
+ seen[k] = seen[k - 1];
+ seen[pos] = tag;
+ seen_count++;
}
}
+ _TIFFfreeExt(tif, seen);
}
+ else
+ {
+ /* Fallback to O(D^2) if allocation fails (rare, small dircount). */
+ TIFFDirEntry *ma;
+ uint16_t mb;
+ for (ma = dir, mb = 0; mb < dircount; ma++, mb++)
+ {
+ TIFFDirEntry *na;
+ uint16_t nb;
+ for (na = ma + 1, nb = mb + 1; nb < dircount; na++, nb++)
+ if (ma->tdir_tag == na->tdir_tag)
+ na->tdir_ignore = TRUE;
+ }
+ }
}
@@ -5394,18 +5397,44 @@
/*
* Mark duplicates of any tag to be ignored (bugzilla 1994)
* to avoid certain pathological problems.
+ * Fixed: same O(D^2) -> O(D log D) fix as in TIFFReadDirectory above.
*/
{
- TIFFDirEntry *ma;
- uint16_t mb;
- for (ma = dir, mb = 0; mb < dircount; ma++, mb++)
+ uint16_t *seen = (uint16_t *)_TIFFmallocExt(
+ tif, (tmsize_t)(dircount * sizeof(uint16_t)));
+ if (seen != NULL)
{
- TIFFDirEntry *na;
- uint16_t nb;
- for (na = ma + 1, nb = mb + 1; nb < dircount; na++, nb++)
+ uint16_t seen_count = 0;
+ TIFFDirEntry *dp2;
+ uint16_t di2;
+ for (dp2 = dir, di2 = 0; di2 < dircount; dp2++, di2++)
{
- if (ma->tdir_tag == na->tdir_tag)
+ uint16_t tag = dp2->tdir_tag;
+ int lo = 0, hi = (int)seen_count - 1, found = 0;
+ while (lo <= hi)
+ {
+ int mid = (lo + hi) / 2;
+ if (seen[mid] == tag) { found = 1; break; }
+ else if (seen[mid] < tag) lo = mid + 1;
+ else hi = mid - 1;
+ }
+ if (found)
{
- na->tdir_ignore = TRUE;
+ dp2->tdir_ignore = TRUE;
+ }
+ else
+ {
+ int pos = lo;
+ int k;
+ for (k = (int)seen_count; k > pos; k--)
+ seen[k] = seen[k - 1];
+ seen[pos] = tag;
+ seen_count++;
}
}
+ _TIFFfreeExt(tif, seen);
}
+ else
+ {
+ TIFFDirEntry *ma;
+ uint16_t mb;
+ for (ma = dir, mb = 0; mb < dircount; ma++, mb++)
+ {
+ TIFFDirEntry *na;
+ uint16_t nb;
+ for (na = ma + 1, nb = mb + 1; nb < dircount; na++, nb++)
+ if (ma->tdir_tag == na->tdir_tag)
+ na->tdir_ignore = TRUE;
+ }
+ }
}