import java.util.*; /** * CWE-407 simulation: OGRE3D GLSLProgramWriter inParams linear scan. * * Defect: ogre-0001 * File: Components/RTShaderSystem/src/OgreShaderGLSLProgramWriter.cpp * * In writeSourceCode(), for every function invocation atom and for every * operand within that atom, the code calls: * * std::find(inParams.begin(), inParams.end(), param) * * where inParams is a vector. This is O(P) per operand, giving * overall O(A * O * P) where: * A = atom instances (function invocations) * O = operands per atom * P = number of input parameters * * Fix: build an unordered_set from inParams before the loop, * reducing the per-operand lookup to O(1) → overall O(A * O). */ public class OgreTest { /** * Simulates the defective O(A*O*P) inParams lookup: * for each atom, for each operand, do a linear scan of inParams. * * @param numAtoms number of function invocation atoms (A) * @param numOperands operands per atom (O) * @param numInParams number of input parameters (P) * @return total comparison operations performed */ static long defectiveShaderWrite(int numAtoms, int numOperands, int numInParams) { // Simulate inParams as a list of IDs List inParams = new ArrayList<>(numInParams); for (int i = 0; i < numInParams; i++) { inParams.add(i); } long ops = 0; for (int a = 0; a < numAtoms; a++) { for (int o = 0; o < numOperands; o++) { // The operand parameter ID — picks half from inParams, half not int paramId = (a * numOperands + o) % (numInParams * 2); // std::find: O(P) scan boolean found = false; for (int p = 0; p < numInParams; p++) { ops++; if (inParams.get(p).equals(paramId)) { found = true; break; } } } } return ops; } /** * Simulates the fixed O(A*O) inParams lookup using a hash set. * * @param numAtoms number of function invocation atoms (A) * @param numOperands operands per atom (O) * @param numInParams number of input parameters (P) * @return total comparison operations performed */ static long fixedShaderWrite(int numAtoms, int numOperands, int numInParams) { Set inParamSet = new HashSet<>(numInParams); for (int i = 0; i < numInParams; i++) { inParamSet.add(i); } long ops = 0; for (int a = 0; a < numAtoms; a++) { for (int o = 0; o < numOperands; o++) { int paramId = (a * numOperands + o) % (numInParams * 2); ops++; // hash-set lookup is O(1) boolean found = inParamSet.contains(paramId); } } return ops; } public static void main(String[] args) { // --- Correctness test: both must agree on which params are "input params" --- int P = 10, A = 5, O = 4; List inParams = new ArrayList<>(); for (int i = 0; i < P; i++) inParams.add(i); Set inParamSet = new HashSet<>(inParams); List defectResults = new ArrayList<>(); List fixedResults = new ArrayList<>(); for (int a = 0; a < A; a++) { for (int o = 0; o < O; o++) { int paramId = (a * O + o) % (P * 2); defectResults.add(inParams.contains(paramId)); fixedResults.add(inParamSet.contains(paramId)); } } assert defectResults.equals(fixedResults) : "Correctness check failed: defective and fixed produce different results"; System.out.println("PASS: correctness verified for inParams membership lookup"); // --- Op-count ratio test --- System.out.println("\nOperation count ratio (defective / fixed):"); int[][] configs = { {50, 8, 20}, {100, 10, 50}, {200, 12, 100}, }; for (int[] cfg : configs) { int atoms = cfg[0], operands = cfg[1], params = cfg[2]; long dOps = defectiveShaderWrite(atoms, operands, params); long fOps = fixedShaderWrite(atoms, operands, params); double ratio = (double) dOps / fOps; System.out.printf(" A=%3d O=%2d P=%3d defect=%7d fixed=%5d ratio=%.1fx%n", atoms, operands, params, dOps, fOps, ratio); assert ratio > 2.0 : "Expected ratio > 2x, got " + ratio + " for A=" + atoms + " O=" + operands + " P=" + params; } // --- Wall-clock timing --- int bigA = 400, bigO = 20, bigP = 200; long t0 = System.nanoTime(); defectiveShaderWrite(bigA, bigO, bigP); long defectNs = System.nanoTime() - t0; t0 = System.nanoTime(); fixedShaderWrite(bigA, bigO, bigP); long fixedNs = System.nanoTime() - t0; double wallRatio = (double) defectNs / Math.max(fixedNs, 1); System.out.printf("%nWall-clock timing for A=%d O=%d P=%d:%n", bigA, bigO, bigP); System.out.printf(" defective: %6.2f ms%n", defectNs / 1e6); System.out.printf(" fixed: %6.2f ms%n", fixedNs / 1e6); System.out.printf(" ratio: %.1fx%n", wallRatio); assert wallRatio > 1.5 : "Expected wall-clock ratio > 1.5x, got " + wallRatio; System.out.println("\nPASS: all assertions passed"); } }