import java.util.*; /** * CWE-407 unit test for PostgreSQL pg_inherits.c defect. * * postgres-0001: src/backend/catalog/pg_inherits.c typeInheritsFrom() * BFS over pg_inherits using List *visited + list_member_oid() — O(V) per node, * O(V²) total for a deep/wide hierarchy. * Fix: replace List *visited with HTAB *visited_set (same pattern as * find_all_inheritors in the same file) for O(1) per-node visited check. */ public class PostgresTest { // Simulate defect: List visited + linear scan static boolean typeInheritsFrom_list(int[][] parentEdges, int subclass, int superclass) { // parentEdges[i] = {child_oid, parent_oid} // BFS from subclass upward; visited is a list (O(V) scan per entry) List queue = new ArrayList<>(); List visited = new ArrayList<>(); queue.add(subclass); int head = 0; while (head < queue.size()) { int current = queue.get(head++); boolean alreadySeen = false; for (int v : visited) { // O(V) — defect if (v == current) { alreadySeen = true; break; } } if (alreadySeen) continue; visited.add(current); for (int[] edge : parentEdges) { if (edge[0] == current) { int parent = edge[1]; if (parent == superclass) return true; queue.add(parent); } } } return false; } // Simulate fix: HashSet visited static boolean typeInheritsFrom_htab(int[][] parentEdges, int subclass, int superclass) { List queue = new ArrayList<>(); Set visited = new HashSet<>(); // O(1) lookup queue.add(subclass); int head = 0; while (head < queue.size()) { int current = queue.get(head++); if (!visited.add(current)) continue; // O(1) for (int[] edge : parentEdges) { if (edge[0] == current) { int parent = edge[1]; if (parent == superclass) return true; queue.add(parent); } } } return false; } static void testPostgres0001() throws Exception { // Build a diamond-inheritance graph: V types in a chain with cross-links // Use the negative case (not found) — forces full BFS traversal of all V nodes, // maximising the visited-list size reached during each member check. int V = 800; // All-to-all fan-out: node i has edges to i+1..i+10 (wide BFS tree) List edges = new ArrayList<>(); for (int i = 0; i < V; i++) { for (int k = 1; k <= 10 && i + k < V; k++) { edges.add(new int[]{i, i + k}); } } int[][] parentEdges = edges.toArray(new int[0][]); int subclass = 0; int superclass = V - 1; // reachable (positive case) int missing = 999999; // not reachable (negative case — full traversal) // correctness boolean r1 = typeInheritsFrom_list(parentEdges, subclass, superclass); boolean r2 = typeInheritsFrom_htab(parentEdges, subclass, superclass); assert r1 == r2 : "list and htab must agree (positive): " + r1 + " vs " + r2; boolean n1 = typeInheritsFrom_list(parentEdges, subclass, missing); boolean n2 = typeInheritsFrom_htab(parentEdges, subclass, missing); assert n1 == n2 && !n1 : "negative case must agree"; // performance on negative case: forces complete traversal, visited grows to V int REPS = 100; long t0 = System.nanoTime(); for (int r = 0; r < REPS; r++) typeInheritsFrom_list(parentEdges, subclass, missing); long tList = System.nanoTime() - t0; t0 = System.nanoTime(); for (int r = 0; r < REPS; r++) typeInheritsFrom_htab(parentEdges, subclass, missing); long tHash = System.nanoTime() - t0; double ratio = (double) tList / tHash; System.out.printf("postgres-0001: list=%.3fs htab=%.3fs ratio=%.1f×%n", tList / 1e9, tHash / 1e9, ratio); assert ratio > 1.2 : "Expected >1.2× speedup, got " + ratio; System.out.println("PASS postgres-0001"); } public static void main(String[] args) throws Exception { testPostgres0001(); System.out.println("ALL PASS"); } }