import java.util.*; /** * CWE-407 simulation: Swift LoadableByAddress pass linear membership tests. * * The StructLoweringState in LoadableByAddress.cpp uses SmallVector with * std::find for membership tests on largeLoadableArgs, applies, and other * instruction vectors. For each instruction in the function, std::find * performs O(A) linear scan where A = number of large loadable args. * * Defect: O(I x A) where I = instructions, A = large loadable args * Fix: SmallPtrSet shadow for O(1) membership tests -> O(I + A) * * swift-0001: LoadableByAddress largeLoadableArgs/applies linear membership */ public class SwiftTest { // --- Defective: SmallVector + std::find pattern --- static long visitApplyDefective(List largeLoadableArgs, List funcSigArgs, List applies, List applyOperands) { long ops = 0; for (Object[] operands : applyOperands) { for (Object operand : operands) { ops++; // std::find(largeLoadableArgs.begin(), ..., currOperand) boolean found = false; for (Object arg : largeLoadableArgs) { ops++; if (arg == operand) { found = true; break; } } if (!found) { // std::find(funcSigArgs.begin(), ..., currOperand) for (Object arg : funcSigArgs) { ops++; if (arg == operand) { found = true; break; } } } if (found) { // Dedup check: std::find(applies.begin(), ..., instr) Object instr = operands; // proxy for instruction for (Object a : applies) { ops++; if (a == instr) { found = false; break; } } if (found) applies.add(instr); } } } return ops; } // --- Fixed: SmallPtrSet shadow for O(1) lookup --- static long visitApplyFixed(Set largeLoadableArgsSet, Set funcSigArgsSet, Set appliesSet, List applyOperands) { long ops = 0; for (Object[] operands : applyOperands) { for (Object operand : operands) { ops++; boolean found = largeLoadableArgsSet.contains(operand); ops++; if (!found) { found = funcSigArgsSet.contains(operand); ops++; } if (found) { Object instr = operands; if (appliesSet.add(instr)) { ops++; } } } } return ops; } public static void main(String[] args) { // Simulate a function with A large loadable args and I apply instructions int[] sizes = {10, 50, 100, 200, 500}; System.out.println("swift-0001: LoadableByAddress largeLoadableArgs linear membership"); System.out.println("================================================================="); System.out.printf("%-8s %-14s %-14s %-10s %-6s%n", "A(args)", "Defective ops", "Fixed ops", "Ratio", "Status"); boolean allPass = true; for (int A : sizes) { // Create A large loadable args List largeLoadableArgs = new ArrayList<>(); Set largeLoadableArgsSet = new HashSet<>(); List funcSigArgs = new ArrayList<>(); Set funcSigArgsSet = new HashSet<>(); List applies = new ArrayList<>(); Set appliesSet = new HashSet<>(); Object[] argPool = new Object[A]; for (int i = 0; i < A; i++) { argPool[i] = new Object(); largeLoadableArgs.add(argPool[i]); largeLoadableArgsSet.add(argPool[i]); funcSigArgs.add(argPool[i]); funcSigArgsSet.add(argPool[i]); } // Create I apply instructions, each with 3 operands from the arg pool int I = A * 2; // instructions proportional to args List applyOperands = new ArrayList<>(); Random rng = new Random(42); for (int i = 0; i < I; i++) { Object[] ops = new Object[3]; for (int j = 0; j < 3; j++) { ops[j] = argPool[rng.nextInt(A)]; } applyOperands.add(ops); } long defectOps = visitApplyDefective( new ArrayList<>(largeLoadableArgs), new ArrayList<>(funcSigArgs), new ArrayList<>(applies), applyOperands); long fixedOps = visitApplyFixed( new HashSet<>(largeLoadableArgsSet), new HashSet<>(funcSigArgsSet), new HashSet<>(appliesSet), applyOperands); double ratio = (double) defectOps / fixedOps; boolean pass = ratio > 2.0; allPass &= pass; System.out.printf("%-8d %-14d %-14d %-10.1f %-6s%n", A, defectOps, fixedOps, ratio, pass ? "PASS" : "FAIL"); } System.out.println(); System.out.println(allPass ? "ALL PASS" : "SOME FAIL"); System.exit(allPass ? 0 : 1); } }