package unit; import java.util.*; /** * Models libevent evhttp_dispatch_callback and evhttp_set_cb defects. * * libevent-0001: O(C) TAILQ scan per request → O(1) with HashMap. * O(C²) setup dedup → O(C) with HashMap. * * CWE-407: http.c:3697 (dispatch), http.c:4290 (set_cb) */ public class LibeventDispatchCallbackAlgorithmTest { // ========================================================================= // Slow — TAILQ_FOREACH analog (linked list) // ========================================================================= static class SlowEvhttp { final List callbacks = new ArrayList<>(); long cmpOps = 0; /** evhttp_set_cb: O(C) dedup scan per registration → O(C²) total for C registrations */ boolean setCb(String uri) { for (String cb : callbacks) { cmpOps++; if (cb.equals(uri)) return false; // duplicate } callbacks.add(uri); return true; } /** evhttp_dispatch_callback: O(C) per request */ String dispatch(String uri) { for (String cb : callbacks) { cmpOps++; if (cb.equals(uri)) return cb; } return null; } long registerAll(List uris) { cmpOps = 0; callbacks.clear(); for (String u : uris) setCb(u); return cmpOps; } long dispatchAll(List requests) { cmpOps = 0; for (String r : requests) dispatch(r); return cmpOps; } } // ========================================================================= // Fast — HashMap // ========================================================================= static class FastEvhttp { final Map map = new HashMap<>(); long cmpOps = 0; boolean setCb(String uri) { cmpOps++; return map.putIfAbsent(uri, uri) == null; } String dispatch(String uri) { cmpOps++; return map.get(uri); } long registerAll(List uris) { cmpOps = 0; map.clear(); for (String u : uris) setCb(u); return cmpOps; } long dispatchAll(List requests) { cmpOps = 0; for (String r : requests) dispatch(r); return cmpOps; } } static List makeRoutes(int n) { List r = new ArrayList<>(); for (int i = 0; i < n; i++) r.add("/api/v1/resource/" + i); return r; } public static void main(String[] args) { SlowEvhttp slow = new SlowEvhttp(); FastEvhttp fast = new FastEvhttp(); int passed = 0, total = 0; System.out.println("=== libevent-0001: evhttp_set_cb O(C²) setup ==="); int[] sizes = {20, 50, 100, 200}; for (int c : sizes) { List routes = makeRoutes(c); long s = slow.registerAll(routes); long f = fast.registerAll(routes); double ratio = (double) s / Math.max(f, 1); total++; boolean ok = s > f && ratio >= 5.0; System.out.printf("C=%3d setup slow=%7d fast=%4d ratio=%6.1fx %s%n", c, s, f, ratio, ok ? "PASS" : "FAIL"); if (ok) passed++; } System.out.println("=== libevent-0001: evhttp_dispatch_callback O(C) per request ==="); for (int c : sizes) { List routes = makeRoutes(c); slow.registerAll(routes); fast.registerAll(routes); // Requests target the last route (worst case — full scan) List requests = new ArrayList<>(); for (int i = 0; i < c; i++) requests.add("/api/v1/resource/" + (c - 1)); long s = slow.dispatchAll(requests); long f = fast.dispatchAll(requests); double ratio = (double) s / Math.max(f, 1); total++; boolean ok = s > f && ratio >= 5.0; System.out.printf("C=%3d R=%3d dispatch slow=%7d fast=%4d ratio=%6.1fx %s%n", c, c, s, f, ratio, ok ? "PASS" : "FAIL"); if (ok) passed++; } // Correctness: both dispatch same route List routes100 = makeRoutes(100); slow.registerAll(routes100); fast.registerAll(routes100); String sr = slow.dispatch("/api/v1/resource/42"); String fr = fast.dispatch("/api/v1/resource/42"); total++; boolean correct = Objects.equals(sr, fr); System.out.printf("dispatch correctness: %s%n", correct ? "PASS" : "FAIL"); if (correct) passed++; System.out.printf("%n%d/%d PASS%n", passed, total); if (passed < total) System.exit(1); } }