java-topology/defects/vlc/patch/vlc-0002.patch
russell@unturf.com 25c2bafdee undf: assign 694-720; stamp patches; ruby-0003/elixir-0002/r-source-0002/victoria-metrics-0002
New UNDF assignments (693→720):
  elixir-0002 → UNDF-2026-000000698 (typespec used_type_pairs O(T²))
  r-source-0002 → UNDF-2026-000000711 (.walkClassGraph match dedup O(S²))
  ruby-0003 → UNDF-2026-000000712 (RubyGems dependent_gems O(N²×D))
  victoria-metrics-0002 → UNDF-2026-000000717 (MetricName tag-filter O(T×I))

Total: 720 UNDF assigned
2026-03-29 22:28:31 -04:00

127 lines
4.3 KiB
Diff

# UNDF: UNDF-2026-000000718
--- 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 );
+ }