import java.util.*; /** * Unit tests for PPSSPP CWE-407 defects. * * ppsspp-0001: sceKernelThread waitingThreads vector dedup O(W^2) * ppsspp-0002: sceKernelSemaphore waitingThreads vector dedup O(W^2) * ppsspp-0003: IRJit byPage_ block removal O(P*B) * ppsspp-0004: sceKernelMutex waitingThreads vector dedup O(W^2) -- 4 sites */ public class PpssppKernelDedup { // --- ppsspp-0001/0002: waitingThreads dedup --- /** DEFECTIVE: linear scan before push_back */ static void addWaiter_defective(List waiters, int threadId) { if (!waiters.contains(threadId)) { waiters.add(threadId); } } /** FIXED: hash set for O(1) dedup */ static void addWaiter_fixed(List waiters, Set waiterSet, int threadId) { if (waiterSet.add(threadId)) { waiters.add(threadId); } } // --- ppsspp-0003: byPage block removal --- /** DEFECTIVE: linear scan for removal */ static boolean removeBlock_defective(List pageBlocks, int blockIndex) { int idx = pageBlocks.indexOf(blockIndex); if (idx >= 0) { pageBlocks.remove(idx); return true; } return false; } /** FIXED: set-based removal */ static boolean removeBlock_fixed(Set pageBlockSet, int blockIndex) { return pageBlockSet.remove(blockIndex); } public static void main(String[] args) { int passed = 0; int failed = 0; // --- Test 1: ppsspp-0001 correctness --- { List defect = new ArrayList<>(); List fixed = new ArrayList<>(); Set fixedSet = new HashSet<>(); for (int i = 0; i < 50; i++) { addWaiter_defective(defect, i); addWaiter_defective(defect, i); // dup from tight-loop timeout addWaiter_fixed(fixed, fixedSet, i); addWaiter_fixed(fixed, fixedSet, i); } boolean ok = defect.size() == 50 && fixed.size() == 50; System.out.println((ok ? "PASS" : "FAIL") + " ppsspp-0001 correctness: thread waiter dedup"); if (ok) passed++; else failed++; } // --- Test 2: ppsspp-0001 performance --- { int N = 5000; List defect = new ArrayList<>(); long t0 = System.nanoTime(); for (int i = 0; i < N; i++) addWaiter_defective(defect, i); long defectNs = System.nanoTime() - t0; List fixed = new ArrayList<>(); Set fixedSet = new HashSet<>(); t0 = System.nanoTime(); for (int i = 0; i < N; i++) addWaiter_fixed(fixed, fixedSet, i); long fixedNs = System.nanoTime() - t0; double ratio = (double) defectNs / Math.max(fixedNs, 1); boolean ok = ratio > 5.0; System.out.printf("%s ppsspp-0001 performance: N=%d defect=%.1fms fixed=%.1fms ratio=%.1fx%n", ok ? "PASS" : "FAIL", N, defectNs / 1e6, fixedNs / 1e6, ratio); if (ok) passed++; else failed++; } // --- Test 3: ppsspp-0002 correctness (same pattern, sema context) --- { List defect = new ArrayList<>(); List fixed = new ArrayList<>(); Set fixedSet = new HashSet<>(); // Simulate tight-loop timeout adding same threads repeatedly for (int round = 0; round < 10; round++) { for (int tid = 0; tid < 20; tid++) { addWaiter_defective(defect, tid); addWaiter_fixed(fixed, fixedSet, tid); } } boolean ok = defect.size() == 20 && fixed.size() == 20; System.out.println((ok ? "PASS" : "FAIL") + " ppsspp-0002 correctness: sema waiter dedup"); if (ok) passed++; else failed++; } // --- Test 4: ppsspp-0002 performance (many unique waiters) --- { int N = 5000; List defect = new ArrayList<>(); long t0 = System.nanoTime(); for (int tid = 0; tid < N; tid++) { addWaiter_defective(defect, tid); } long defectNs = System.nanoTime() - t0; List fixed = new ArrayList<>(); Set fixedSet = new HashSet<>(); t0 = System.nanoTime(); for (int tid = 0; tid < N; tid++) { addWaiter_fixed(fixed, fixedSet, tid); } long fixedNs = System.nanoTime() - t0; double ratio = (double) defectNs / Math.max(fixedNs, 1); boolean ok = ratio > 5.0; System.out.printf("%s ppsspp-0002 performance: N=%d defect=%.1fms fixed=%.1fms ratio=%.1fx%n", ok ? "PASS" : "FAIL", N, defectNs / 1e6, fixedNs / 1e6, ratio); if (ok) passed++; else failed++; } // --- Test 5: ppsspp-0003 correctness --- { List defectPage = new ArrayList<>(); Set fixedPage = new HashSet<>(); for (int i = 0; i < 100; i++) { defectPage.add(i); fixedPage.add(i); } boolean d = removeBlock_defective(defectPage, 50); boolean f = removeBlock_fixed(fixedPage, 50); boolean ok = d && f && defectPage.size() == 99 && fixedPage.size() == 99; System.out.println((ok ? "PASS" : "FAIL") + " ppsspp-0003 correctness: byPage block removal"); if (ok) passed++; else failed++; } // --- Test 6: ppsspp-0003 performance --- { int N = 5000; List defectPage = new ArrayList<>(); Set fixedPage = new HashSet<>(); for (int i = 0; i < N; i++) { defectPage.add(i); fixedPage.add(i); } long t0 = System.nanoTime(); for (int i = N - 1; i >= 0; i--) { removeBlock_defective(defectPage, i); } long defectNs = System.nanoTime() - t0; t0 = System.nanoTime(); for (int i = N - 1; i >= 0; i--) { removeBlock_fixed(fixedPage, i); } long fixedNs = System.nanoTime() - t0; double ratio = (double) defectNs / Math.max(fixedNs, 1); boolean ok = ratio > 5.0; System.out.printf("%s ppsspp-0003 performance: N=%d defect=%.1fms fixed=%.1fms ratio=%.1fx%n", ok ? "PASS" : "FAIL", N, defectNs / 1e6, fixedNs / 1e6, ratio); if (ok) passed++; else failed++; } // --- Test 7: ppsspp-0004 correctness (mutex, 4 sites, same pattern) --- // Models sceKernelLockMutex / sceKernelLockMutexCB / // sceKernelLockLwMutex / sceKernelLockLwMutexCB tight-loop timeout. { int nThreads = 30; int nRetries = 20; // each thread retries 20x under timeout List defect = new ArrayList<>(); List fixed = new ArrayList<>(); Set fixedSet = new HashSet<>(); for (int retry = 0; retry < nRetries; retry++) { for (int tid = 0; tid < nThreads; tid++) { addWaiter_defective(defect, tid); addWaiter_fixed(fixed, fixedSet, tid); } } boolean ok = defect.size() == nThreads && fixed.size() == nThreads; System.out.println((ok ? "PASS" : "FAIL") + " ppsspp-0004 correctness: mutex waiter dedup (4 sites)"); if (ok) passed++; else failed++; } // --- Test 8: ppsspp-0004 performance (mutex contention scale) --- { int W = 3000; List defect = new ArrayList<>(); long t0 = System.nanoTime(); for (int tid = 0; tid < W; tid++) addWaiter_defective(defect, tid); long defectNs = System.nanoTime() - t0; List fixed = new ArrayList<>(); Set fixedSet = new HashSet<>(); t0 = System.nanoTime(); for (int tid = 0; tid < W; tid++) addWaiter_fixed(fixed, fixedSet, tid); long fixedNs = System.nanoTime() - t0; double ratio = (double) defectNs / Math.max(fixedNs, 1); boolean ok = ratio > 5.0; System.out.printf("%s ppsspp-0004 performance: W=%d defect=%.1fms fixed=%.1fms ratio=%.1fx%n", ok ? "PASS" : "FAIL", W, defectNs / 1e6, fixedNs / 1e6, ratio); if (ok) passed++; else failed++; } System.out.printf("%n%d/%d tests passed%n", passed, passed + failed); if (failed > 0) System.exit(1); } }