package unit; import java.util.*; /** * RSourceTest -- CWE-407 benchmark for r-source-0001 * * Models rapply() do_one() O(k²) nested loop class matching * vs. O(k) HashSet-based class membership test. * * Real code (src/main/apply.c ~312): * for(int i=0; i < LENGTH(klass); i++) // O(k) element's classes * for(int j=0; j < length(classes); j++) // O(k) target classes * if(Seql(STRING_ELT(klass,i), STRING_ELT(classes,j))) * matched = true; * * Fix: intern classes into a set before the loop, O(k) total. */ public class RSourceTest { 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 speedup = fMs > 0 ? (double) sMs / fMs : 0; System.out.printf(" %-54s slow:%4dms (%,d ops) fast:%4dms (%,d ops) speedup:%.0fx%n", label, sMs, sOps, fMs, fOps, speedup); } // k classes per element, N elements, each element matched against k target classes static long slowRapply(int N, int k) { String[] targets = new String[k]; for (int j = 0; j < k; j++) targets[j] = "class_" + j; String[] elemClasses = new String[k]; for (int i = 0; i < k; i++) elemClasses[i] = "class_" + (i + k / 2); // partial overlap long ops = 0; for (int elem = 0; elem < N; elem++) { for (int i = 0; i < k; i++) { // O(k) element classes for (int j = 0; j < k; j++) { // O(k) target classes ops++; if (elemClasses[i].equals(targets[j])) break; } } } return ops; } static long fastRapply(int N, int k) { Set targetSet = new HashSet<>(k * 2); for (int j = 0; j < k; j++) targetSet.add("class_" + j); String[] elemClasses = new String[k]; for (int i = 0; i < k; i++) elemClasses[i] = "class_" + (i + k / 2); long ops = 0; for (int elem = 0; elem < N; elem++) { for (int i = 0; i < k; i++) { // O(k) ops++; // O(1) set lookup if (targetSet.contains(elemClasses[i])) break; } } return ops; } public static void main(String[] args) { System.out.println("RSourceTest -- r-source-0001: rapply() do_one() nested class match -> HashSet"); System.out.println(); System.out.println(" [src/main/apply.c ~312 do_one() -- O(k^2) class intersection check]"); int[][] cases = {{1000, 10, 10000}, {500, 20, 5000}, {200, 50, 2000}}; for (int[] c : cases) { int N = c[0], k = c[1], R = c[2]; bench( String.format("N=%d elements, k=%d classes each, %,d rapply() calls", N, k, R), () -> { for (int i = 0; i < R; i++) slowRapply(N, k); }, () -> { for (int i = 0; i < R; i++) fastRapply(N, k); }, (long) N * k * k * R, (long) N * k * R ); } System.out.println(); System.out.println("Defect : src/main/apply.c ~312 -- nested loop class matching O(k^2) per element"); System.out.println("Fix : intern 'classes' into pointer-set before loop -- O(k) per element"); System.out.println("Ticket : r-source-0001-rapply-class-match-nested-linear-scan.md"); System.out.println(); int pass = 0; long s0 = slowRapply(200, 50), f0 = fastRapply(200, 50); assert s0 > f0 * 5 : "r-source-0001 expected >5x; slow=" + s0 + " fast=" + f0; pass++; System.out.printf("%d/1 PASS -- r-source-0001: CWE-407 in R rapply() do_one() class matching%n", pass); System.out.printf("Hotpath: rapply() on data frames with S4 class hierarchies%n"); } }