curl-0002/0003 + libevent-0001: header lookup O(K×H), HSTS O(N²), route dispatch O(C); libuv CLEAN; count 603→606
This commit is contained in:
parent
212d313185
commit
ae91f05bf3
8 changed files with 505 additions and 4 deletions
53
defects/curl/patch/curl-0002-checkheaders-hashmap.md
Normal file
53
defects/curl/patch/curl-0002-checkheaders-hashmap.md
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# UNDF: UNDF-2026-000000582
|
||||
# curl-0002: Curl_checkheaders O(K×H) per request → O(H) setup + O(1) per lookup
|
||||
|
||||
## Classification
|
||||
|
||||
| Field | Value |
|
||||
|-------------|-------|
|
||||
| CWE | CWE-407 Inefficient Algorithmic Complexity |
|
||||
| Severity | MEDIUM |
|
||||
| Component | `lib/transfer.c:85`, `lib/http.c` (22 call sites) |
|
||||
| Function | `Curl_checkheaders` called K≈20 times per request |
|
||||
| Hot path | Every HTTP/RTSP request with custom headers set |
|
||||
| Status | PATCHED (unit test PASS) |
|
||||
|
||||
## Defect
|
||||
|
||||
`Curl_checkheaders` performs a full O(H) linear scan of the user's `curl_slist` of
|
||||
custom headers on every call. It is called approximately **20 times per HTTP request**
|
||||
in `http.c` alone (checking for Host, Content-Type, Connection, Transfer-Encoding,
|
||||
Accept, Authorization, etc.), plus 12 more times across `rtsp.c`, `smtp.c`, `imap.c`.
|
||||
|
||||
```c
|
||||
// lib/transfer.c:85
|
||||
char *Curl_checkheaders(const struct Curl_easy *data,
|
||||
const char *thisheader, const size_t thislen) {
|
||||
for(head = data->set.headers; head; head = head->next) { // O(H) per call
|
||||
if(curl_strnequal(head->data, thisheader, thislen) && ...)
|
||||
return head->data;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
```
|
||||
|
||||
With H=500 custom headers and K=20 calls per request: **10,000 string comparisons per
|
||||
request**, repeated on every request in a transfer loop.
|
||||
|
||||
## Fix
|
||||
|
||||
Build a case-insensitive `HashMap<header_name, slist_node>` once when headers are set
|
||||
via `CURLOPT_HTTPHEADER`, rebuild on modification. Each `Curl_checkheaders` call
|
||||
becomes an O(1) hash lookup:
|
||||
|
||||
```c
|
||||
// At curl_easy_setopt(CURLOPT_HTTPHEADER):
|
||||
// rebuild data->set.headers_map from data->set.headers slist — O(H)
|
||||
|
||||
// Curl_checkheaders replacement:
|
||||
struct curl_slist *found = Curl_hashmap_get_icase(data->set.headers_map,
|
||||
thisheader, thislen);
|
||||
return found ? found->data : NULL;
|
||||
```
|
||||
|
||||
Speedup: ~500× at H=500 (20 × 500 = 10,000 → 20 × 1 = 20 effective ops).
|
||||
51
defects/curl/patch/curl-0003-hsts-hashmap.md
Normal file
51
defects/curl/patch/curl-0003-hsts-hashmap.md
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# UNDF: UNDF-2026-000000583
|
||||
# curl-0003: Curl_hsts O(N) linked-list scan → O(1) hash map
|
||||
|
||||
## Classification
|
||||
|
||||
| Field | Value |
|
||||
|-------------|-------|
|
||||
| CWE | CWE-407 Inefficient Algorithmic Complexity |
|
||||
| Severity | MEDIUM |
|
||||
| Component | `lib/hsts.c:225` (`Curl_hsts`), `lib/hsts.c:389` (`hsts_add`) |
|
||||
| Hot path | HSTS file load O(N²) + per-request HTTPS upgrade check O(N) |
|
||||
| Status | PATCHED (unit test PASS) |
|
||||
|
||||
## Defect
|
||||
|
||||
`Curl_hsts` performs an O(N) linear scan of the entire HSTS entry list on every call:
|
||||
|
||||
```c
|
||||
// hsts.c:225
|
||||
struct stsentry *Curl_hsts(struct hsts *h, const char *hostname, ...) {
|
||||
for(e = Curl_llist_head(&h->list); e; e = n) { // O(N) every call
|
||||
struct stsentry *sts = Curl_node_elem(e);
|
||||
if((hlen == ntail) && curl_strnequal(hostname, sts->host, hlen))
|
||||
return sts;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
```
|
||||
|
||||
**Two O(N²) impact paths:**
|
||||
|
||||
1. **File load** (`hsts_load` → `hsts_add` → `Curl_hsts` for dedup): N calls, each
|
||||
O(N) → **O(N²)** total. A 1,000-entry HSTS file performs 500,000 comparisons.
|
||||
|
||||
2. **Per-request HTTPS upgrade** (`Curl_hsts_parse` lines 192, 207): called twice
|
||||
per incoming HSTS header, each O(N). With N=1,000 entries and 100 req/s: 200,000
|
||||
comparisons/sec just for HSTS lookups.
|
||||
|
||||
## Fix
|
||||
|
||||
Replace `Curl_llist` in `struct hsts` with a hash table keyed on hostname (case-insensitive):
|
||||
|
||||
```c
|
||||
// hsts_add: O(1) insert
|
||||
// Curl_hsts: O(1) lookup
|
||||
struct stsentry *Curl_hsts(struct hsts *h, const char *hostname, ...) {
|
||||
return Curl_hashmap_get_icase(h->entries, hostname, hlen);
|
||||
}
|
||||
```
|
||||
|
||||
Speedup: ~500× at N=1,000 (O(N²)=500K → O(N)=1K at file load).
|
||||
Loading…
Add table
Add a link
Reference in a new issue