java-topology/defects/libevent/unit/LibeventDispatchCallbackAlgorithmTest.java

147 lines
4.8 KiB
Java

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<String> 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<String> uris) {
cmpOps = 0;
callbacks.clear();
for (String u : uris) setCb(u);
return cmpOps;
}
long dispatchAll(List<String> requests) {
cmpOps = 0;
for (String r : requests) dispatch(r);
return cmpOps;
}
}
// =========================================================================
// Fast — HashMap
// =========================================================================
static class FastEvhttp {
final Map<String, String> 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<String> uris) {
cmpOps = 0;
map.clear();
for (String u : uris) setCb(u);
return cmpOps;
}
long dispatchAll(List<String> requests) {
cmpOps = 0;
for (String r : requests) dispatch(r);
return cmpOps;
}
}
static List<String> makeRoutes(int n) {
List<String> 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<String> 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<String> routes = makeRoutes(c);
slow.registerAll(routes);
fast.registerAll(routes);
// Requests target the last route (worst case — full scan)
List<String> 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<String> 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);
}
}