import java.util.*; /** * Java simulation of CPython CWE-407 defects. * * cpython-0001: codegen pattern-match stores duplicate check O(S^2) * PySequence_Contains(pc->stores, name) inside loop → O(S^2) * Fix: parallel HashSet for O(1) membership * * cpython-0002: typeobject pmerge() tail_contains O(M^2 * K) * Linear scan of merge-list tails for each MRO candidate → O(M^2 * K) * Fix: HashSet of tail elements for O(1) membership */ public class CpythonTest { // ========== cpython-0001: pattern-match stores ========== /** DEFECTIVE: O(S^2) — list.contains() per store name */ static long patternStoresDefective(int numStores) { List stores = new ArrayList<>(); long ops = 0; for (int i = 0; i < numStores; i++) { String name = "var_" + i; // PySequence_Contains(pc->stores, name) — O(S) boolean dup = stores.contains(name); ops += stores.size(); if (!dup) { stores.add(name); } } return ops; } /** FIXED: O(S) — HashSet.contains() per store name */ static long patternStoresFixed(int numStores) { List stores = new ArrayList<>(); Set storesSet = new HashSet<>(); long ops = 0; for (int i = 0; i < numStores; i++) { String name = "var_" + i; // PySet_Contains(pc->stores_set, name) — O(1) boolean dup = storesSet.contains(name); ops++; if (!dup) { stores.add(name); storesSet.add(name); } } return ops; } // ========== cpython-0002: pmerge tail_contains ========== /** * Simulate C3 MRO linearization with linear tail_contains. * Build diamond inheritance: C extends B1..BK, each Bi has MRO of length M/K. */ static long pmergeTailContainsDefective(int mroLen, int numBases) { // Build merge lists: numBases lists, each of length mroLen/numBases int listLen = Math.max(mroLen / numBases, 2); List> toLists = new ArrayList<>(); for (int k = 0; k < numBases; k++) { List lst = new ArrayList<>(); for (int j = 0; j < listLen; j++) { lst.add("Class_" + k + "_" + j); } toLists.add(lst); } // Add the bases list itself List basesList = new ArrayList<>(); for (int k = 0; k < numBases; k++) { basesList.add(toLists.get(k).get(0)); } toLists.add(basesList); int[] remain = new int[toLists.size()]; List acc = new ArrayList<>(); long ops = 0; boolean progress = true; while (progress) { progress = false; for (int i = 0; i < toLists.size(); i++) { List cur = toLists.get(i); if (remain[i] >= cur.size()) continue; String candidate = cur.get(remain[i]); boolean inTail = false; // tail_contains: linear scan of tails — O(M) for (int j = 0; j < toLists.size() && !inTail; j++) { List jLst = toLists.get(j); for (int t = remain[j] + 1; t < jLst.size(); t++) { ops++; if (jLst.get(t).equals(candidate)) { inTail = true; break; } } } if (!inTail) { acc.add(candidate); for (int j = 0; j < toLists.size(); j++) { List jLst = toLists.get(j); if (remain[j] < jLst.size() && jLst.get(remain[j]).equals(candidate)) { remain[j]++; } } progress = true; break; } } } return ops; } /** FIXED: O(M * K) — HashSet for tail membership */ static long pmergeTailContainsFixed(int mroLen, int numBases) { int listLen = Math.max(mroLen / numBases, 2); List> toLists = new ArrayList<>(); for (int k = 0; k < numBases; k++) { List lst = new ArrayList<>(); for (int j = 0; j < listLen; j++) { lst.add("Class_" + k + "_" + j); } toLists.add(lst); } List basesList = new ArrayList<>(); for (int k = 0; k < numBases; k++) { basesList.add(toLists.get(k).get(0)); } toLists.add(basesList); int[] remain = new int[toLists.size()]; List acc = new ArrayList<>(); long ops = 0; // Build tail set: all elements in tail positions Set tailSet = new HashSet<>(); for (List lst : toLists) { for (int j = 1; j < lst.size(); j++) { tailSet.add(lst.get(j)); } } boolean progress = true; while (progress) { progress = false; for (int i = 0; i < toLists.size(); i++) { List cur = toLists.get(i); if (remain[i] >= cur.size()) continue; String candidate = cur.get(remain[i]); ops++; // O(1) set lookup boolean inTail = tailSet.contains(candidate); if (!inTail) { acc.add(candidate); for (int j = 0; j < toLists.size(); j++) { List jLst = toLists.get(j); if (remain[j] < jLst.size() && jLst.get(remain[j]).equals(candidate)) { remain[j]++; // Remove consumed head from tail set if new head exists if (remain[j] < jLst.size()) { // The element at remain[j] is now a head, not a tail // But it may still be a tail in other lists, so don't remove } } } // Rebuild tail set (simplified; real fix would be incremental) tailSet.clear(); for (List lst : toLists) { int r = remain[toLists.indexOf(lst)]; for (int t = r + 1; t < lst.size(); t++) { tailSet.add(lst.get(t)); } } progress = true; break; } } } return ops; } // ========== Test harness ========== static void test0001() { System.out.println("=== cpython-0001: codegen pattern-match stores ==="); int[] sizes = {10, 50, 100, 200}; for (int s : sizes) { long defOps = patternStoresDefective(s); long fixOps = patternStoresFixed(s); double ratio = (double) defOps / fixOps; System.out.printf(" S=%3d: defective=%6d fixed=%4d ratio=%.1fx%n", s, defOps, fixOps, ratio); if (s >= 50 && ratio < 5.0) { throw new AssertionError("Expected ratio >= 5x at S=" + s + ", got " + ratio); } } // Verify O(N^2) growth long ops50 = patternStoresDefective(50); long ops200 = patternStoresDefective(200); double growth = (double) ops200 / ops50; System.out.printf(" Growth 50->200: %.1fx (expect ~16x for O(N^2))%n", growth); if (growth < 10.0) { throw new AssertionError("Expected quadratic growth, got " + growth + "x"); } System.out.println(" PASS"); } static void test0002() { System.out.println("=== cpython-0002: typeobject pmerge tail_contains ==="); int[][] params = {{20, 5}, {50, 10}, {100, 10}, {200, 10}}; for (int[] p : params) { int M = p[0], K = p[1]; long defOps = pmergeTailContainsDefective(M, K); long fixOps = pmergeTailContainsFixed(M, K); double ratio = (double) defOps / Math.max(fixOps, 1); System.out.printf(" M=%3d K=%2d: defective=%7d fixed=%5d ratio=%.1fx%n", M, K, defOps, fixOps, ratio); if (M >= 50 && ratio < 3.0) { throw new AssertionError("Expected ratio >= 3x at M=" + M + ", got " + ratio); } } System.out.println(" PASS"); } public static void main(String[] args) { test0001(); test0002(); System.out.println("\nAll CPython CWE-407 tests PASSED"); } }