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
This commit is contained in:
parent
f4593ef84a
commit
13db08af50
10 changed files with 776 additions and 0 deletions
BIN
defects/scribus/unit/ScribusTest.class
Normal file
BIN
defects/scribus/unit/ScribusTest.class
Normal file
Binary file not shown.
195
defects/scribus/unit/ScribusTest.java
Normal file
195
defects/scribus/unit/ScribusTest.java
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
import java.util.*;
|
||||
|
||||
/**
|
||||
* CWE-407 simulation tests for Scribus defects.
|
||||
*
|
||||
* scribus-0001: getSortedStyleList retList.contains O(N²) dedup
|
||||
* scribus-0002: getUsedPatterns results.contains O(I×R) pattern accumulation
|
||||
* scribus-0003: Selection::addItems m_SelList.contains O(N×M) selection dedup
|
||||
*/
|
||||
public class ScribusTest {
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// scribus-0001: getSortedStyleList — QList<int>::contains inside loop
|
||||
// Simulates walking parent chains and deduplicating into retList
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/** Defective: List.contains O(N) inside O(N) loop */
|
||||
static int sortedStyleListDefective(int styleCount, int[] parentIdx) {
|
||||
int ops = 0;
|
||||
List<Integer> retList = new ArrayList<>();
|
||||
for (int i = 0; i < styleCount; i++) {
|
||||
// Check if already in retList
|
||||
for (int x : retList) { ops++; if (x == i) break; }
|
||||
if (!retList.contains(i)) {
|
||||
// Walk parent chain
|
||||
List<Integer> chain = new ArrayList<>();
|
||||
chain.add(i);
|
||||
int p = parentIdx[i];
|
||||
while (p >= 0) {
|
||||
boolean found = false;
|
||||
for (int x : chain) { ops++; if (x == p) { found = true; break; } }
|
||||
if (!found) chain.add(0, p);
|
||||
p = parentIdx[p];
|
||||
}
|
||||
// Merge chain into retList with contains check
|
||||
for (int idx : chain) {
|
||||
boolean found = false;
|
||||
for (int x : retList) { ops++; if (x == idx) { found = true; break; } }
|
||||
if (!found) retList.add(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
/** Fixed: QSet<int> companion */
|
||||
static int sortedStyleListFixed(int styleCount, int[] parentIdx) {
|
||||
int ops = 0;
|
||||
List<Integer> retList = new ArrayList<>();
|
||||
Set<Integer> retSet = new HashSet<>();
|
||||
for (int i = 0; i < styleCount; i++) {
|
||||
ops++;
|
||||
if (!retSet.contains(i)) {
|
||||
List<Integer> chain = new ArrayList<>();
|
||||
Set<Integer> chainSet = new HashSet<>();
|
||||
chain.add(i); chainSet.add(i); ops++;
|
||||
int p = parentIdx[i];
|
||||
while (p >= 0) {
|
||||
ops++;
|
||||
if (!chainSet.contains(p)) { chain.add(0, p); chainSet.add(p); }
|
||||
p = parentIdx[p];
|
||||
}
|
||||
for (int idx : chain) {
|
||||
ops++;
|
||||
if (!retSet.contains(idx)) { retList.add(idx); retSet.add(idx); }
|
||||
}
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
static void testSortedStyleList() {
|
||||
int N = 500;
|
||||
int[] parentIdx = new int[N];
|
||||
// Linear parent chain: 0←1←2←...←N-1 (worst case)
|
||||
parentIdx[0] = -1;
|
||||
for (int i = 1; i < N; i++) parentIdx[i] = i - 1;
|
||||
|
||||
int defectOps = sortedStyleListDefective(N, parentIdx);
|
||||
int fixedOps = sortedStyleListFixed(N, parentIdx);
|
||||
double ratio = (double) defectOps / fixedOps;
|
||||
|
||||
System.out.printf("scribus-0001 sorted style list: defect=%d fixed=%d ratio=%.1fx%n",
|
||||
defectOps, fixedOps, ratio);
|
||||
assert ratio > 10 : "Expected >10x ratio, got " + ratio;
|
||||
System.out.println(" PASS");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// scribus-0002: getUsedPatterns — QStringList::contains inside item loop
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/** Defective: linear scan for each pattern check */
|
||||
static int getUsedPatternsDefective(String[][] itemPatterns) {
|
||||
int ops = 0;
|
||||
List<String> results = new ArrayList<>();
|
||||
for (String[] pats : itemPatterns) {
|
||||
for (String pat : pats) {
|
||||
if (pat == null || pat.isEmpty()) continue;
|
||||
boolean found = false;
|
||||
for (String r : results) { ops++; if (r.equals(pat)) { found = true; break; } }
|
||||
if (!found) results.add(pat);
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
/** Fixed: HashSet companion */
|
||||
static int getUsedPatternsFixed(String[][] itemPatterns) {
|
||||
int ops = 0;
|
||||
Set<String> resultSet = new HashSet<>();
|
||||
for (String[] pats : itemPatterns) {
|
||||
for (String pat : pats) {
|
||||
if (pat == null || pat.isEmpty()) continue;
|
||||
ops++;
|
||||
if (!resultSet.contains(pat)) resultSet.add(pat);
|
||||
}
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
static void testGetUsedPatterns() {
|
||||
int items = 2000;
|
||||
int patsPerItem = 3; // fill, stroke, mask
|
||||
int uniquePatterns = 200;
|
||||
Random rng = new Random(42);
|
||||
String[][] itemPatterns = new String[items][patsPerItem];
|
||||
for (int i = 0; i < items; i++)
|
||||
for (int j = 0; j < patsPerItem; j++)
|
||||
itemPatterns[i][j] = "pattern_" + rng.nextInt(uniquePatterns);
|
||||
|
||||
int defectOps = getUsedPatternsDefective(itemPatterns);
|
||||
int fixedOps = getUsedPatternsFixed(itemPatterns);
|
||||
double ratio = (double) defectOps / fixedOps;
|
||||
|
||||
System.out.printf("scribus-0002 used patterns: defect=%d fixed=%d ratio=%.1fx%n",
|
||||
defectOps, fixedOps, ratio);
|
||||
assert ratio > 10 : "Expected >10x ratio, got " + ratio;
|
||||
System.out.println(" PASS");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// scribus-0003: Selection::addItems — m_SelList.contains inside loop
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/** Defective: QList::contains O(M) for each of N items */
|
||||
static int selectionAddItemsDefective(int existing, int toAdd) {
|
||||
int ops = 0;
|
||||
List<Integer> selList = new ArrayList<>();
|
||||
for (int i = 0; i < existing; i++) selList.add(i);
|
||||
|
||||
for (int i = existing; i < existing + toAdd; i++) {
|
||||
// linear scan
|
||||
for (int s : selList) { ops++; if (s == i) break; }
|
||||
selList.add(i);
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
/** Fixed: QSet companion for O(1) check */
|
||||
static int selectionAddItemsFixed(int existing, int toAdd) {
|
||||
int ops = 0;
|
||||
Set<Integer> selSet = new HashSet<>();
|
||||
for (int i = 0; i < existing; i++) { selSet.add(i); ops++; }
|
||||
|
||||
for (int i = existing; i < existing + toAdd; i++) {
|
||||
ops++;
|
||||
if (!selSet.contains(i)) selSet.add(i);
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
static void testSelectionAddItems() {
|
||||
int existing = 2000;
|
||||
int toAdd = 3000;
|
||||
|
||||
int defectOps = selectionAddItemsDefective(existing, toAdd);
|
||||
int fixedOps = selectionAddItemsFixed(existing, toAdd);
|
||||
double ratio = (double) defectOps / fixedOps;
|
||||
|
||||
System.out.printf("scribus-0003 selection addItems: 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) {
|
||||
testSortedStyleList();
|
||||
testGetUsedPatterns();
|
||||
testSelectionAddItems();
|
||||
System.out.println("\nAll 3 Scribus CWE-407 tests PASSED.");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue