java-topology/defects/wireshark/patch/wireshark-0001-quic-streams-list-find-hashmap.md

2.5 KiB
Raw Blame History

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:

/* 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,00010,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:

/* 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).