# UNDF: UNDF-2026-000000341
## Classification

| Field       | Value |
|-------------|-------|
| CWE         | CWE-407 Inefficient Algorithmic Complexity |
| Severity    | MEDIUM |
| Component   | `epan/dissectors/packet-quic.c:5419` |
| Function    | `quic_streams_add()` |
| Hot path    | Called once per new QUIC stream — per-packet during QUIC capture |
| Status      | PATCHED (unit test PASS) |

## Defect

`quic_streams_add()` checks whether a stream ID is already known using a
linear scan of a sorted linked list:

```c
/* packet-quic.c:5415 */
if (!quic_info->streams_list) {
    quic_info->streams_list = wmem_list_new(wmem_file_scope());
}
if (!wmem_list_find(quic_info->streams_list, GUINT_TO_POINTER(stream_id))) {
    wmem_list_insert_sorted(quic_info->streams_list, GUINT_TO_POINTER(stream_id),
                            wmem_compare_uint);
}
```

`wmem_list_find()` is a linear scan of a singly-linked list — O(S) per call
where S is the current number of known stream IDs.  Called once per new QUIC
stream encountered during dissection.

QUIC HTTP/3 traffic uses one stream per request.  A capture of a high-traffic
server may contain a connection with S=1,000–10,000 streams.  Total cost of
stream-dedup across all stream additions: O(S²/2).

At S=1,000: ~500,000 pointer comparisons just for dedup.

Note: `quic_info->streams_list` is maintained sorted (`wmem_list_insert_sorted`)
for the "Follow QUIC Stream" UI dropdown.  A parallel `wmem_map_t` hash set for
O(1) membership checks preserves the sorted list while eliminating the scan.

## Fix

Add `wmem_map_t *streams_id_set` alongside `streams_list` in `quic_info_data_t`:

```c
/* quic_info_data_t struct — add: */
wmem_map_t     *streams_id_set;  /**< Hash set: stream IDs already seen — O(1) dedup */

/* quic_streams_add() — replace wmem_list_find with map lookup: */
if (!quic_info->streams_id_set) {
    quic_info->streams_id_set = wmem_map_new(wmem_file_scope(),
                                             g_direct_hash, g_direct_equal);
}
if (!wmem_map_lookup(quic_info->streams_id_set, GUINT_TO_POINTER(stream_id))) {
    wmem_map_insert(quic_info->streams_id_set, GUINT_TO_POINTER(stream_id),
                    GUINT_TO_POINTER(1));
    wmem_list_insert_sorted(quic_info->streams_list, GUINT_TO_POINTER(stream_id),
                            wmem_compare_uint);
}
```

The sorted `streams_list` is preserved for UI display.  Only the O(S) membership
check is replaced with an O(1) hash lookup.

Speedup: ~500× at S=1,000 (500,000 → 1,000 effective operations).
