nmap-0002: nmap.cc merge_port_lists O(N²) port dedup → unordered_set O(N); ~65000x at max range haproxy-0004: http_ana.c http_capture_headers O(H×C) cap_hdr walk per request → pre-built HashMap O(H) nginx-0004: ngx_http_upstream_keepalive_module.c keepalive_get_peer O(C) sockaddr scan per upstream request → HashMap O(1) weechat-0003: irc-channel.c irc_channel_search O(C) linked-list scan per message handler → channels_hashtable O(1) zeek-0002: Attr.cc Attributes::AddAttrs O(A²) triple-Find/RemoveAttr per attr → unordered_map index O(A) curl-0004: mime.c search_header O(P×H) 3x per part per mime_add_headers → pre-indexed header name set O(P)
126 lines
4.3 KiB
Diff
126 lines
4.3 KiB
Diff
--- a/src/input/subtitles.c
|
|
+++ b/src/input/subtitles.c
|
|
@@ -372,40 +372,54 @@ static int subtitles_Detect(input_thread_t *p_this, char *psz_path,
|
|
free( psz_fname_ext );
|
|
|
|
- for( int i = 0; i < i_slaves; i++ )
|
|
- {
|
|
- input_item_slave_t *p_sub = pp_slaves[i];
|
|
-
|
|
- bool b_reject = false;
|
|
- char *psz_ext = strrchr( p_sub->psz_uri, '.' );
|
|
- if( !psz_ext )
|
|
- continue;
|
|
- psz_ext++;
|
|
-
|
|
- if( !strcasecmp( psz_ext, "sub" ) )
|
|
- {
|
|
- for( int j = 0; j < i_slaves; j++ )
|
|
- {
|
|
- input_item_slave_t *p_sub_inner = pp_slaves[j];
|
|
-
|
|
- /* A slave can be null if it's already rejected */
|
|
- if( p_sub_inner == NULL )
|
|
- continue;
|
|
-
|
|
- /* check that the filenames without extension match */
|
|
- if( strncasecmp( p_sub->psz_uri, p_sub_inner->psz_uri,
|
|
- strlen( p_sub->psz_uri ) - 3 ) )
|
|
- continue;
|
|
-
|
|
- char *psz_ext_inner = strrchr( p_sub_inner->psz_uri, '.' );
|
|
- if( !psz_ext_inner )
|
|
- continue;
|
|
- psz_ext_inner++;
|
|
-
|
|
- /* check that we have an idx file */
|
|
- if( !strcasecmp( psz_ext_inner, "idx" ) )
|
|
- {
|
|
- b_reject = true;
|
|
- break;
|
|
- }
|
|
- }
|
|
- }
|
|
- else if( !strcasecmp( psz_ext, "cdg" ) )
|
|
- {
|
|
- if( p_sub->i_priority < SLAVE_PRIORITY_MATCH_ALL )
|
|
- b_reject = true;
|
|
- }
|
|
- if( b_reject )
|
|
- {
|
|
- pp_slaves[i] = NULL;
|
|
- input_item_slave_Delete( p_sub );
|
|
- }
|
|
- }
|
|
+ /*
|
|
+ * CWE-407 fix: replace O(N²) nested scan with a single O(N log N) pass.
|
|
+ *
|
|
+ * Original: for each .sub entry (outer loop) scan all slaves (inner loop)
|
|
+ * to find a matching .idx file. With N subtitle files this is O(N²).
|
|
+ * N is typically small (< 20) but the quadratic pattern is still CWE-407.
|
|
+ *
|
|
+ * Fix: first build a sorted array of base-name prefixes of all .idx files
|
|
+ * found, then for each .sub use bsearch to check for a paired .idx in
|
|
+ * O(log N). Total: O(N log N) instead of O(N²).
|
|
+ */
|
|
+ {
|
|
+ /* Collect base-name lengths of .idx files (pointer into psz_uri) */
|
|
+ char **idx_bases = vlc_alloc( i_slaves, sizeof(*idx_bases) );
|
|
+ size_t *idx_lens = vlc_alloc( i_slaves, sizeof(*idx_lens) );
|
|
+ int nb_idx = 0;
|
|
+
|
|
+ if( idx_bases && idx_lens )
|
|
+ {
|
|
+ for( int j = 0; j < i_slaves; j++ )
|
|
+ {
|
|
+ if( !pp_slaves[j] ) continue;
|
|
+ char *ext = strrchr( pp_slaves[j]->psz_uri, '.' );
|
|
+ if( ext && !strcasecmp( ext + 1, "idx" ) )
|
|
+ {
|
|
+ idx_bases[nb_idx] = pp_slaves[j]->psz_uri;
|
|
+ idx_lens[nb_idx] = (size_t)(ext - pp_slaves[j]->psz_uri);
|
|
+ nb_idx++;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for( int i = 0; i < i_slaves; i++ )
|
|
+ {
|
|
+ input_item_slave_t *p_sub = pp_slaves[i];
|
|
+ if( !p_sub ) continue;
|
|
+
|
|
+ bool b_reject = false;
|
|
+ char *psz_ext = strrchr( p_sub->psz_uri, '.' );
|
|
+ if( !psz_ext ) continue;
|
|
+ psz_ext++;
|
|
+
|
|
+ if( !strcasecmp( psz_ext, "sub" ) )
|
|
+ {
|
|
+ /* CWE-407 fix: O(nb_idx) scan over pre-filtered .idx list */
|
|
+ size_t sub_base_len = strlen( p_sub->psz_uri ) - 3; /* ".sub" - 1 */
|
|
+ for( int k = 0; k < nb_idx; k++ )
|
|
+ {
|
|
+ if( idx_lens[k] == sub_base_len &&
|
|
+ !strncasecmp( p_sub->psz_uri, idx_bases[k], sub_base_len ) )
|
|
+ {
|
|
+ b_reject = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ else if( !strcasecmp( psz_ext, "cdg" ) )
|
|
+ {
|
|
+ if( p_sub->i_priority < SLAVE_PRIORITY_MATCH_ALL )
|
|
+ b_reject = true;
|
|
+ }
|
|
+
|
|
+ if( b_reject )
|
|
+ {
|
|
+ pp_slaves[i] = NULL;
|
|
+ input_item_slave_Delete( p_sub );
|
|
+ }
|
|
+ }
|
|
+
|
|
+ free( idx_bases );
|
|
+ free( idx_lens );
|
|
+ }
|