package unit; import java.util.*; /** * LuaTest -- CWE-407 benchmark for lua-0001 * * Models searchupvalue() O(M*N) linear scan per variable reference * vs. O(M) HashMap-based upvalue index. * * Real code (lparser.c ~360): * for (i = 0; i < fs->nups; i++) // O(N) per variable reference * if (eqstr(up[i].name, name)) return i; * * Fix: small hash map (TString->index) in FuncState, O(1) lookup. */ public class LuaTest { 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); } // Simulate searchupvalue O(N) linear scan static long slowSearchUpvalue(int N, int M) { String[] upvalues = new String[N]; for (int i = 0; i < N; i++) upvalues[i] = "upval_" + i; String target = upvalues[N - 1]; // worst case: last upvalue long ops = 0; for (int ref = 0; ref < M; ref++) { for (int i = 0; i < N; i++) { ops++; if (upvalues[i].equals(target)) break; } } return ops; } // Simulate fixed searchupvalue with HashMap O(1) lookup static long fastSearchUpvalue(int N, int M) { Map upvalMap = new HashMap<>(N * 2); for (int i = 0; i < N; i++) upvalMap.put("upval_" + i, i); String target = "upval_" + (N - 1); long ops = 0; for (int ref = 0; ref < M; ref++) { ops++; // O(1) map lookup upvalMap.get(target); } return ops; } public static void main(String[] args) { System.out.println("LuaTest -- lua-0001: searchupvalue() linear scan -> HashMap index"); System.out.println(); System.out.println(" [lparser.c searchupvalue() -- O(N) per variable reference at compile time]"); int[][] cases = {{50, 500, 100000}, {100, 500, 50000}, {200, 500, 20000}}; for (int[] c : cases) { int N = c[0], M = c[1], R = c[2]; bench( String.format("N=%d upvalues, M=%d refs/fn, %,d fns compiled", N, M, R), () -> { for (int i = 0; i < R; i++) slowSearchUpvalue(N, M); }, () -> { for (int i = 0; i < R; i++) fastSearchUpvalue(N, M); }, (long) N * M * R, (long) M * R ); } System.out.println(); System.out.println("Defect : lparser.c ~360 -- searchupvalue() O(N) linear scan per var reference"); System.out.println("Fix : fixed-size hash table in FuncState -- O(1) upvalue index lookup"); System.out.println("Ticket : lua-0001-searchupvalue-linear-scan-per-reference.md"); System.out.println(); int pass = 0; long s0 = slowSearchUpvalue(200, 500), f0 = fastSearchUpvalue(200, 500); assert s0 > f0 * 50 : "lua-0001 expected >50x; slow=" + s0 + " fast=" + f0; pass++; System.out.printf("%d/1 PASS -- lua-0001: CWE-407 in Lua 5.4 searchupvalue() compilation%n", pass); System.out.printf("Hotpath: every variable reference in closures with many upvalues%n"); } }