freecad/retroarch/mpv: CWE-407 scan — 3 defects, mpv CLEAN

freecad-0001: ifc_generator.py done-list O(N^2) dedup MEDIUM-HIGH 499x
freecad-0002: importDXF.py processededges list O(E^2) MEDIUM 469x
retroarch-0001: playlist_entry_exists O(R*P) linear scan in content scanner HIGH 749x
mpv: CLEAN (all data structures naturally bounded)

3/3 unit tests PASS.
This commit is contained in:
russell@unturf.com 2026-03-30 14:53:03 -04:00
parent 37dc0c5179
commit e06902c99a
8 changed files with 388 additions and 0 deletions

Binary file not shown.

View file

@ -0,0 +1,140 @@
import java.util.*;
/**
* CWE-407 simulation tests for FreeCAD defects.
*
* freecad-0001: ifc_generator.py done-list O(N^2) dedup in generate_shape/generate_coin
* freecad-0002: importDXF.py processededges list O(E^2) membership
*/
public class FreeCADCwe407Test {
// ---- freecad-0001: IFC generator done-list dedup ----
/** DEFECTIVE: done = list, item.id not in done → O(N) per check, O(N^2) total */
static int ifcGeneratorDoneList_defective(int N) {
List<Integer> done = new ArrayList<>();
int ops = 0;
for (int i = 0; i < N; i++) {
int id = i; // simulate unique IFC element IDs
// O(N) linear scan
boolean found = false;
for (int j = 0; j < done.size(); j++) {
ops++;
if (done.get(j) == id) {
found = true;
break;
}
}
if (!found) {
done.add(id);
}
}
return ops;
}
/** PATCHED: done = set, item.id not in done → O(1) per check, O(N) total */
static int ifcGeneratorDoneSet_patched(int N) {
Set<Integer> done = new HashSet<>();
int ops = 0;
for (int i = 0; i < N; i++) {
int id = i;
ops++; // O(1) hash lookup
if (!done.contains(id)) {
done.add(id);
}
}
return ops;
}
// ---- freecad-0002: DXF processededges list membership ----
/** DEFECTIVE: processededges = list, hashCode not in processededges → O(E^2) */
static int dxfProcessedEdges_defective(int E) {
List<Integer> processededges = new ArrayList<>();
int ops = 0;
// Phase 1: build processededges from wires
int wiresEdges = E * 3 / 4; // 75% edges in wires
for (int i = 0; i < wiresEdges; i++) {
processededges.add(i); // hashCode of edge
}
// Phase 2: find lone edges via linear scan
for (int i = 0; i < E; i++) {
int hashCode = i;
for (int j = 0; j < processededges.size(); j++) {
ops++;
if (processededges.get(j) == hashCode) {
break;
}
}
}
return ops;
}
/** PATCHED: processededges = set → O(1) lookup per edge */
static int dxfProcessedEdges_patched(int E) {
Set<Integer> processededges = new HashSet<>();
int ops = 0;
int wiresEdges = E * 3 / 4;
for (int i = 0; i < wiresEdges; i++) {
processededges.add(i);
}
for (int i = 0; i < E; i++) {
ops++; // O(1) hash lookup
processededges.contains(i);
}
return ops;
}
public static void main(String[] args) {
int passed = 0;
int failed = 0;
// --- freecad-0001 tests ---
{
int N = 1000;
int defOps = ifcGeneratorDoneList_defective(N);
int patOps = ifcGeneratorDoneSet_patched(N);
double ratio = (double) defOps / patOps;
System.out.printf("freecad-0001 IFC generator done-list (N=%d):%n", N);
System.out.printf(" defective ops: %d%n", defOps);
System.out.printf(" patched ops: %d%n", patOps);
System.out.printf(" ratio: %.1fx%n", ratio);
// defective should be O(N^2/2) ≈ 499,500 ops; patched = N = 1000
if (ratio > 100) {
System.out.println(" PASS: ratio > 100x confirms O(N^2) vs O(N)");
passed++;
} else {
System.out.println(" FAIL: expected ratio > 100x, got " + ratio);
failed++;
}
}
// --- freecad-0002 tests ---
{
int E = 1000;
int defOps = dxfProcessedEdges_defective(E);
int patOps = dxfProcessedEdges_patched(E);
double ratio = (double) defOps / patOps;
System.out.printf("freecad-0002 DXF processededges (E=%d):%n", E);
System.out.printf(" defective ops: %d%n", defOps);
System.out.printf(" patched ops: %d%n", patOps);
System.out.printf(" ratio: %.1fx%n", ratio);
if (ratio > 50) {
System.out.println(" PASS: ratio > 50x confirms O(E^2) vs O(E)");
passed++;
} else {
System.out.println(" FAIL: expected ratio > 50x, got " + ratio);
failed++;
}
}
System.out.printf("%n%d/%d tests passed%n", passed, passed + failed);
if (failed > 0) {
System.exit(1);
}
}
}

Binary file not shown.

View file

@ -0,0 +1,95 @@
import java.util.*;
/**
* CWE-407 simulation test for RetroArch defect.
*
* retroarch-0001: playlist_entry_exists O(P) linear scan called per scan result
* in content scanner loop → O(R*P) total.
*/
public class RetroArchCwe407Test {
/**
* DEFECTIVE: For each scan result, linear scan through playlist entries.
* Simulates playlist_entry_exists called from task_database.c scan loop.
*/
static int playlistEntryExists_defective(int R, int P) {
// Build initial playlist with P entries
List<String> playlist = new ArrayList<>();
for (int i = 0; i < P; i++) {
playlist.add("/roms/game" + i + ".rom");
}
int ops = 0;
// Scan R new results, each checks playlist_entry_exists
for (int r = 0; r < R; r++) {
String path = "/roms/game" + (P + r) + ".rom"; // new content not in playlist
// Linear scan through all P entries
boolean found = false;
for (int j = 0; j < playlist.size(); j++) {
ops++;
if (playlist.get(j).equals(path)) {
found = true;
break;
}
}
if (!found) {
playlist.add(path); // push to playlist
}
}
return ops;
}
/**
* PATCHED: Use hash set for O(1) existence check.
*/
static int playlistEntryExists_patched(int R, int P) {
Set<String> pathSet = new HashSet<>();
for (int i = 0; i < P; i++) {
pathSet.add("/roms/game" + i + ".rom");
}
int ops = 0;
for (int r = 0; r < R; r++) {
String path = "/roms/game" + (P + r) + ".rom";
ops++; // O(1) hash lookup
if (!pathSet.contains(path)) {
pathSet.add(path);
}
}
return ops;
}
public static void main(String[] args) {
int passed = 0;
int failed = 0;
{
int R = 500; // scan results
int P = 500; // existing playlist entries
int defOps = playlistEntryExists_defective(R, P);
int patOps = playlistEntryExists_patched(R, P);
double ratio = (double) defOps / patOps;
System.out.printf("retroarch-0001 playlist_entry_exists (R=%d, P=%d):%n", R, P);
System.out.printf(" defective ops: %d%n", defOps);
System.out.printf(" patched ops: %d%n", patOps);
System.out.printf(" ratio: %.1fx%n", ratio);
// Defective: each of R=500 new entries scans growing list (~500..999)
// ~500*500 + 500*499/2 ≈ 374,750 ops
// Patched: R = 500 ops
if (ratio > 100) {
System.out.println(" PASS: ratio > 100x confirms O(R*P) vs O(R)");
passed++;
} else {
System.out.println(" FAIL: expected ratio > 100x, got " + ratio);
failed++;
}
}
System.out.printf("%n%d/%d tests passed%n", passed, passed + failed);
if (failed > 0) {
System.exit(1);
}
}
}