java-topology/defects/darktable/unit/DarktableTest.java
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

162 lines
6.2 KiB
Java
Raw 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.

import java.util.*;
/**
* CWE-407 simulation tests for darktable defects.
*
* darktable-0001: map_locations image diff via g_list_find O(N*M)
* darktable-0002: _tag_add_tags_to_list dedup via g_list_find O(T*L)
* darktable-0003: map view clustering sel_imgs g_list_find inside O(I*J) loop
*/
public class DarktableTest {
// ---------------------------------------------------------------
// darktable-0001: map_locations symmetric diff O(N*M) vs O(N+M)
// ---------------------------------------------------------------
/** Defective: g_list_find inside loop — O(N*M) */
static int mapLocationDiffDefective(List<Integer> oldImgs, List<Integer> newImgs) {
int ops = 0;
// detach old not in new
for (int id : oldImgs) {
for (int nid : newImgs) { ops++; if (nid == id) break; }
}
// attach new not in old
for (int id : newImgs) {
for (int oid : oldImgs) { ops++; if (oid == id) break; }
}
return ops;
}
/** Fixed: GHashTable for O(1) lookup — O(N+M) */
static int mapLocationDiffFixed(List<Integer> oldImgs, List<Integer> newImgs) {
int ops = 0;
Set<Integer> newSet = new HashSet<>(newImgs); ops += newImgs.size();
for (int id : oldImgs) { newSet.contains(id); ops++; }
Set<Integer> oldSet = new HashSet<>(oldImgs); ops += oldImgs.size();
for (int id : newImgs) { oldSet.contains(id); ops++; }
return ops;
}
static void testMapLocationDiff() {
int N = 1000;
List<Integer> oldImgs = new ArrayList<>();
List<Integer> newImgs = new ArrayList<>();
for (int i = 0; i < N; i++) { oldImgs.add(i); newImgs.add(i + N / 2); }
int defectOps = mapLocationDiffDefective(oldImgs, newImgs);
int fixedOps = mapLocationDiffFixed(oldImgs, newImgs);
double ratio = (double) defectOps / fixedOps;
System.out.printf("darktable-0001 map_locations diff: defect=%d fixed=%d ratio=%.1fx%n",
defectOps, fixedOps, ratio);
assert ratio > 10 : "Expected >10x ratio, got " + ratio;
System.out.println(" PASS");
}
// ---------------------------------------------------------------
// darktable-0002: tag dedup via g_list_find O(T*L) ≈ O(N²)
// ---------------------------------------------------------------
/** Defective: linear scan dedup */
static int tagAddToListDefective(List<Integer> existingTags, List<Integer> newTags) {
int ops = 0;
List<Integer> list = new ArrayList<>(existingTags);
for (int tag : newTags) {
boolean found = false;
for (int t : list) { ops++; if (t == tag) { found = true; break; } }
if (!found) list.add(tag);
}
return ops;
}
/** Fixed: HashSet companion */
static int tagAddToListFixed(List<Integer> existingTags, List<Integer> newTags) {
int ops = 0;
Set<Integer> seen = new HashSet<>(existingTags); ops += existingTags.size();
for (int tag : newTags) {
ops++;
if (!seen.contains(tag)) { seen.add(tag); }
}
return ops;
}
static void testTagAddToList() {
int N = 500;
List<Integer> existing = new ArrayList<>();
List<Integer> toAdd = new ArrayList<>();
// all unique — worst case for dedup
for (int i = 0; i < N; i++) existing.add(i);
for (int i = N; i < 2 * N; i++) toAdd.add(i);
int defectOps = tagAddToListDefective(existing, toAdd);
int fixedOps = tagAddToListFixed(existing, toAdd);
double ratio = (double) defectOps / fixedOps;
System.out.printf("darktable-0002 tag dedup: defect=%d fixed=%d ratio=%.1fx%n",
defectOps, fixedOps, ratio);
assert ratio > 50 : "Expected >50x ratio, got " + ratio;
System.out.println(" PASS");
}
// ---------------------------------------------------------------
// darktable-0003: map view sel_imgs inside O(I*J) clustering loop
// ---------------------------------------------------------------
/** Defective: g_list_find(sel_imgs, imgid) inside nested I×J loop — O(I²×S) */
static long mapViewClusterDefective(int imgCount, List<Integer> selImgs, int[] clusterIds) {
long ops = 0;
for (int i = 0; i < imgCount; i++) {
int group = clusterIds[i];
for (int j = 0; j < imgCount; j++) {
if (clusterIds[j] == group) {
// linear scan of sel_imgs
for (int s : selImgs) { ops++; if (s == j) break; }
}
}
}
return ops;
}
/** Fixed: HashSet for O(1) selection check — O(I²+S) */
static long mapViewClusterFixed(int imgCount, List<Integer> selImgs, int[] clusterIds) {
long ops = 0;
Set<Integer> selSet = new HashSet<>(selImgs); ops += selImgs.size();
for (int i = 0; i < imgCount; i++) {
int group = clusterIds[i];
for (int j = 0; j < imgCount; j++) {
if (clusterIds[j] == group) {
selSet.contains(j); ops++;
}
}
}
return ops;
}
static void testMapViewCluster() {
int I = 500;
int S = 200;
List<Integer> selImgs = new ArrayList<>();
for (int i = 0; i < S; i++) selImgs.add(i);
// All in one cluster — worst case
int[] clusterIds = new int[I];
Arrays.fill(clusterIds, 1);
long defectOps = mapViewClusterDefective(I, selImgs, clusterIds);
long fixedOps = mapViewClusterFixed(I, selImgs, clusterIds);
double ratio = (double) defectOps / fixedOps;
System.out.printf("darktable-0003 map view cluster sel: defect=%d fixed=%d ratio=%.1fx%n",
defectOps, fixedOps, ratio);
assert ratio > 10 : "Expected >10x ratio, got " + ratio;
System.out.println(" PASS");
}
// ---------------------------------------------------------------
public static void main(String[] args) {
testMapLocationDiff();
testTagAddToList();
testMapViewCluster();
System.out.println("\nAll 3 darktable CWE-407 tests PASSED.");
}
}