java-topology/defects/nginx/unit/NginxTest.java
russell@unturf.com ff6292d067 wave17: postgres-0001/asterisk-0001/haproxy-0001/nginx-0001; postfix+bevy CLEAN
postgres-0001: pg_inherits.c typeInheritsFrom() BFS visited List → HTAB O(1)
asterisk-0001: app_queue.c interface_exists() ao2_iterator walk → ao2_find O(1)
haproxy-0001: http_ana.c cookie-server scan linked-list → eb-tree index O(log S)
nginx-0001: ngx_http_link_multi_headers() O(H²) double-scan → O(H) hash pass
postfix: CLEAN (htable throughout; two marginal LOW admin-bounded candidates)
bevy: CLEAN (FixedBitSet/HashSet throughout; only hardware-bounded marginals)
2026-03-30 07:57:30 -04:00

87 lines
3.5 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import java.util.*;
/**
* CWE-407 unit test for nginx ngx_http_core_module.c defect.
*
* nginx-0001: src/http/ngx_http_core_module.c ngx_http_link_multi_headers()
* Nested double-traversal of r->headers_in.headers to chain duplicate
* header names: outer loop at position i, inner loop scans 0..i-1.
* O(H²) where H = number of incoming request headers.
* Fix: single O(H) pass using a hash map of name → first header pointer;
* append to chain on first match, no backward scan needed.
*/
public class NginxTest {
// Simulate defect: O(H²) double-traversal
static Map<String, List<Integer>> linkMultiHeaders_quadratic(String[] headers) {
// Returns map of name -> list of positions (the "chain")
Map<String, List<Integer>> chains = new LinkedHashMap<>();
for (int i = 0; i < headers.length; i++) {
boolean linked = false;
for (int j = 0; j < i; j++) { // O(H²) total — defect
if (headers[j].equalsIgnoreCase(headers[i])) {
chains.get(headers[j].toLowerCase()).add(i);
linked = true;
break;
}
}
if (!linked) {
List<Integer> chain = new ArrayList<>();
chain.add(i);
chains.put(headers[i].toLowerCase(), chain);
}
}
return chains;
}
// Simulate fix: O(H) single pass with hash map
static Map<String, List<Integer>> linkMultiHeaders_hash(String[] headers) {
Map<String, List<Integer>> chains = new LinkedHashMap<>();
for (int i = 0; i < headers.length; i++) {
String lower = headers[i].toLowerCase();
chains.computeIfAbsent(lower, k -> new ArrayList<>()).add(i); // O(1)
}
return chains;
}
static void testNginx0001() throws Exception {
// Simulate H headers with many duplicates (worst case for O(H²))
// nginx default: ~50 unique header names, many repeated → H=300 total
int H = 300;
int UNIQUE = 20;
String[] headers = new String[H];
String[] names = new String[UNIQUE];
for (int i = 0; i < UNIQUE; i++) names[i] = "X-Header-" + i;
for (int i = 0; i < H; i++) headers[i] = names[i % UNIQUE];
// correctness
Map<String, List<Integer>> r1 = linkMultiHeaders_quadratic(headers);
Map<String, List<Integer>> r2 = linkMultiHeaders_hash(headers);
assert r1.keySet().equals(r2.keySet()) : "must produce same key set";
for (String k : r1.keySet()) {
assert r1.get(k).equals(r2.get(k)) :
"chain mismatch for " + k + ": " + r1.get(k) + " vs " + r2.get(k);
}
// performance
int REPS = 10_000;
long t0 = System.nanoTime();
for (int r = 0; r < REPS; r++) linkMultiHeaders_quadratic(headers);
long tQuad = System.nanoTime() - t0;
t0 = System.nanoTime();
for (int r = 0; r < REPS; r++) linkMultiHeaders_hash(headers);
long tHash = System.nanoTime() - t0;
double ratio = (double) tQuad / tHash;
System.out.printf("nginx-0001: quadratic=%.3fs hash=%.3fs ratio=%.1f×%n",
tQuad / 1e9, tHash / 1e9, ratio);
assert ratio > 3 : "Expected >3× speedup, got " + ratio;
System.out.println("PASS nginx-0001");
}
public static void main(String[] args) throws Exception {
testNginx0001();
System.out.println("ALL PASS");
}
}