import java.util.*; /** * CWE-407 simulation tests for GIMP defects. * * gimp-0001: layer stack dedup — O(S² × L²) via nested g_list_find * gimp-0002: remove_from_layer_stack — O(C × S × L) nested g_list_remove */ public class GimpTest { // --------------------------------------------------------------- // gimp-0001: layer stack dedup O(S² × L²) // --------------------------------------------------------------- /** Simulate GList-based layer stack comparison (defective) */ static long layerStackCmpDefective(List layers1, List layers2) { long ops = 0; // g_list_length — O(L) each ops += layers1.size(); // simulated traversal ops += layers2.size(); if (layers1.size() != layers2.size()) return ops; // g_list_find in loop — O(L²) for (Object item : layers1) { for (Object item2 : layers2) { ops++; if (item == item2) break; } } return ops; } /** Simulate GHashTable-based comparison (fixed) */ static long layerStackCmpFixed(List layers1, List layers2) { long ops = 0; ops += layers1.size(); ops += layers2.size(); if (layers1.size() != layers2.size()) return ops; // Build hash set from layers2: O(L) Set set = new HashSet<>(layers2); ops += layers2.size(); // Membership test: O(L) for (Object item : layers1) { ops++; if (!set.contains(item)) break; } return ops; } /** Simulate rec_remove_layer_stack_dups — defective O(S² × cmp) */ static long recRemoveDupsDefective(List> stack) { long ops = 0; for (int i = 0; i < stack.size(); i++) { // g_slist_find_custom scans remaining entries for (int j = i + 1; j < stack.size(); j++) { ops += layerStackCmpDefective(stack.get(i), stack.get(j)); } } return ops; } /** Simulate fixed dedup — O(S × L) using hash */ static long recRemoveDupsFixed(List> stack) { long ops = 0; Set> seen = new HashSet<>(); for (List entry : stack) { Set entrySet = new HashSet<>(entry); ops += entry.size(); // building set ops++; // hash lookup seen.add(entrySet); } return ops; } static void testLayerStackDedup() { int S = 50; // stack entries (undo states) int L = 10; // layers per selection // Build stack with unique selections (worst case) List> stack = new ArrayList<>(); for (int i = 0; i < S; i++) { List selection = new ArrayList<>(); for (int j = 0; j < L; j++) { selection.add(new Object()); // unique objects } stack.add(selection); } long defectOps = recRemoveDupsDefective(stack); long fixedOps = recRemoveDupsFixed(stack); double ratio = (double) defectOps / fixedOps; System.out.printf("gimp-0001 layer stack dedup:%n"); System.out.printf(" S=%d L=%d defect_ops=%d fixed_ops=%d ratio=%.1fx%n", S, L, defectOps, fixedOps, ratio); assert ratio > 20.0 : "Expected significant overhead, got " + ratio; System.out.println(" PASS"); } // --------------------------------------------------------------- // gimp-0002: remove_from_layer_stack O(C × S × L) // --------------------------------------------------------------- /** Simulate defective removal: g_list_remove per child per stack entry */ static long removeFromStackDefective(int children, int stackSize, int layersPerEntry) { long ops = 0; // For each child (plus the layer itself = children+1) for (int c = 0; c < children + 1; c++) { // For each stack entry for (int s = 0; s < stackSize; s++) { // g_list_remove scans the list: O(L) for (int l = 0; l < layersPerEntry; l++) { ops++; } } } return ops; } /** Simulate fixed removal: hash set + single pass per stack entry */ static long removeFromStackFixed(int children, int stackSize, int layersPerEntry) { long ops = 0; // Build hash set of all layers to remove: O(C) ops += children + 1; // Single pass over each stack entry: O(S × L) for (int s = 0; s < stackSize; s++) { for (int l = 0; l < layersPerEntry; l++) { ops++; // hash lookup per layer } } return ops; } static void testRemoveFromLayerStack() { int C = 20; // children in group layer int S = 50; // undo stack entries int L = 20; // layers per stack entry long defectOps = removeFromStackDefective(C, S, L); long fixedOps = removeFromStackFixed(C, S, L); double ratio = (double) defectOps / fixedOps; System.out.printf("gimp-0002 remove_from_layer_stack:%n"); System.out.printf(" C=%d S=%d L=%d defect_ops=%d fixed_ops=%d ratio=%.1fx%n", C, S, L, defectOps, fixedOps, ratio); assert ratio > 10.0 : "Expected significant overhead, got " + ratio; System.out.println(" PASS"); } // --------------------------------------------------------------- // Main // --------------------------------------------------------------- public static void main(String[] args) { testLayerStackDedup(); testRemoveFromLayerStack(); System.out.println("\nAll GIMP CWE-407 tests PASS"); } }