package unit; import java.util.*; /** * MattermostTest — CWE-407 benchmark * * Defects: * 0001: CheckRolesExist() nested loop O(n×m) — linear scan of roles slice per role name * (server/channels/app/role.go:258–278) */ public class MattermostTest { static void bench(String label, Runnable slow, Runnable fast, long sOps, long fOps) { slow.run(); fast.run(); long t0 = System.nanoTime(); slow.run(); long sMs = (System.nanoTime()-t0)/1_000_000; long t1 = System.nanoTime(); fast.run(); long fMs = (System.nanoTime()-t1)/1_000_000; double r = fOps > 0 ? (double)sOps/fOps : 0; System.out.printf(" %-56s slow:%4dms (%,d ops) fast:%4dms (%,d ops) speedup:%.0fx%n", label, sMs, sOps, fMs, fOps, r); } // ------------------------------------------------------------------------- // Defect 0001: CheckRolesExist nested loop // n = role names to check, m = roles returned from DB // ------------------------------------------------------------------------- static long slowCheckRolesExist(List roleNames, List roles) { long ops = 0; for (String name : roleNames) { // outer O(n) boolean found = false; for (String role : roles) { // inner O(m) ops++; if (name.equals(role)) { found = true; break; } } // found check omitted for pure measurement } return ops; } static long fastCheckRolesExist(List roleNames, List roles) { long ops = 0; Set roleSet = new HashSet<>(roles); ops += roles.size(); // O(m) to build set for (String name : roleNames) { ops++; roleSet.contains(name); // O(1) } return ops; } public static void main(String[] args) { System.out.println("MattermostTest — CWE-407"); // Realistic: 40 role names to check, 40 roles returned (same size) // Stress: batch role assignment with 200 names final int N_SMALL = 40; final int M_SMALL = 40; final int N_LARGE = 200; final int M_LARGE = 200; List roleNamesSmall = new ArrayList<>(N_SMALL); List rolesSmall = new ArrayList<>(M_SMALL); for (int i = 0; i < N_SMALL; i++) roleNamesSmall.add("role_name_" + i); for (int i = 0; i < M_SMALL; i++) rolesSmall.add("role_name_" + i); List roleNamesLarge = new ArrayList<>(N_LARGE); List rolesLarge = new ArrayList<>(M_LARGE); for (int i = 0; i < N_LARGE; i++) roleNamesLarge.add("role_name_" + i); for (int i = 0; i < M_LARGE; i++) rolesLarge.add("role_name_" + i); // Repeat many times to get measurable timing final int ITERS = 50_000; System.out.println("\n [0001] CheckRolesExist nested loop (n=" + N_SMALL + ", m=" + M_SMALL + ", x" + ITERS + " iters)"); bench("0001 roles nested loop vs map lookup", () -> { for (int k = 0; k < ITERS; k++) slowCheckRolesExist(roleNamesSmall, rolesSmall); }, () -> { for (int k = 0; k < ITERS; k++) fastCheckRolesExist(roleNamesSmall, rolesSmall); }, (long) ITERS * N_SMALL * M_SMALL / 2, (long) ITERS * (N_SMALL + M_SMALL)); System.out.println("\n [0001b] CheckRolesExist large batch (n=" + N_LARGE + ", m=" + M_LARGE + ", x" + ITERS + " iters)"); bench("0001b large batch nested loop vs map lookup", () -> { for (int k = 0; k < ITERS; k++) slowCheckRolesExist(roleNamesLarge, rolesLarge); }, () -> { for (int k = 0; k < ITERS; k++) fastCheckRolesExist(roleNamesLarge, rolesLarge); }, (long) ITERS * N_LARGE * M_LARGE / 2, (long) ITERS * (N_LARGE + M_LARGE)); // Assertions int pass = 0, total = 2; long slow1 = 0, fast1 = 0; for (int k = 0; k < ITERS; k++) slow1 += slowCheckRolesExist(roleNamesSmall, rolesSmall); for (int k = 0; k < ITERS; k++) fast1 += fastCheckRolesExist(roleNamesSmall, rolesSmall); long slowPerIter = slow1 / ITERS; long fastPerIter = fast1 / ITERS; // slow should do ~N*M/2 ops, fast should do ~N+M ops per iter if (slowPerIter > fastPerIter * (N_SMALL / 4)) { pass++; System.out.println(" PASS 0001: slow ops/iter=" + slowPerIter + " >> fast ops/iter=" + fastPerIter); } else { System.out.println(" FAIL 0001: slow=" + slowPerIter + " fast=" + fastPerIter); } long slow2 = 0, fast2 = 0; for (int k = 0; k < ITERS; k++) slow2 += slowCheckRolesExist(roleNamesLarge, rolesLarge); for (int k = 0; k < ITERS; k++) fast2 += fastCheckRolesExist(roleNamesLarge, rolesLarge); long slowPerIter2 = slow2 / ITERS; long fastPerIter2 = fast2 / ITERS; if (slowPerIter2 > fastPerIter2 * (N_LARGE / 4)) { pass++; System.out.println(" PASS 0001b: slow ops/iter=" + slowPerIter2 + " >> fast ops/iter=" + fastPerIter2); } else { System.out.println(" FAIL 0001b: slow=" + slowPerIter2 + " fast=" + fastPerIter2); } System.out.printf("%n%d/%d PASS%n", pass, total); if (pass < total) System.exit(1); } }