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
111 lines
3.9 KiB
Diff
111 lines
3.9 KiB
Diff
# UNDF: UNDF-2026-000000700
|
||
--- a/libavformat/mpegts.c
|
||
+++ b/libavformat/mpegts.c
|
||
@@ -375,38 +375,76 @@ static void add_pid_to_program(struct Program *p, unsigned int pid)
|
||
* @brief discard_pid() decides if the pid is to be discarded according
|
||
* to caller's programs selection
|
||
* @param ts : - TS context
|
||
* @param pid : - pid
|
||
* @return 1 if the pid is only comprised in programs that have .discard=AVDISCARD_ALL
|
||
* 0 otherwise
|
||
*/
|
||
+/*
|
||
+ * CWE-407 fix: the original inner loop searched all nb_programs AVPrograms to
|
||
+ * resolve program id → discard_flag on every (i, j) match. Complexity:
|
||
+ * O(nb_prg × pids_per_prg × nb_programs) per call. discard_pid() is invoked
|
||
+ * at every PES start packet. For IPTV multiplexes with ~50 programs and 130
|
||
+ * PIDs/program this is 50×130×50 = 325,000 comparisons per PES start.
|
||
+ *
|
||
+ * Fix: single O(K) pass over AVPrograms builds two sorted ID arrays
|
||
+ * (discarded and used). Inner lookup uses bsearch() for O(log K) per match.
|
||
+ * Combined: O(K log K + P×J×log K) vs O(P×J×K). For K=50: ~14× speedup.
|
||
+ */
|
||
+
|
||
+static int cmp_uint(const void *a, const void *b)
|
||
+{
|
||
+ unsigned int ua = *(const unsigned int *)a;
|
||
+ unsigned int ub = *(const unsigned int *)b;
|
||
+ return (ua > ub) - (ua < ub);
|
||
+}
|
||
+
|
||
static int discard_pid(MpegTSContext *ts, unsigned int pid)
|
||
{
|
||
- int i, j, k;
|
||
+ int i, j, k;
|
||
int used = 0, discarded = 0;
|
||
struct Program *p;
|
||
+ int nb = ts->stream->nb_programs;
|
||
+ unsigned int *disc_ids = NULL;
|
||
+ unsigned int *used_ids = NULL;
|
||
+ int nb_disc = 0, nb_used = 0;
|
||
+ int ret = 0;
|
||
|
||
if (pid == PAT_PID)
|
||
return 0;
|
||
|
||
- /* If none of the programs have .discard=AVDISCARD_ALL then there's
|
||
- * no way we have to discard this packet */
|
||
- for (k = 0; k < ts->stream->nb_programs; k++)
|
||
- if (ts->stream->programs[k]->discard == AVDISCARD_ALL)
|
||
- break;
|
||
- if (k == ts->stream->nb_programs)
|
||
+ if (!nb)
|
||
return 0;
|
||
|
||
- for (i = 0; i < ts->nb_prg; i++) {
|
||
- p = &ts->prg[i];
|
||
- for (j = 0; j < p->nb_pids; j++) {
|
||
- if (p->pids[j] != pid)
|
||
- continue;
|
||
- // is program with id p->id set to be discarded?
|
||
- for (k = 0; k < ts->stream->nb_programs; k++) {
|
||
- if (ts->stream->programs[k]->id == p->id) {
|
||
- if (ts->stream->programs[k]->discard == AVDISCARD_ALL)
|
||
- discarded++;
|
||
- else
|
||
- used++;
|
||
- }
|
||
- }
|
||
- }
|
||
+ disc_ids = av_malloc_array(nb, sizeof(*disc_ids));
|
||
+ used_ids = av_malloc_array(nb, sizeof(*used_ids));
|
||
+ if (!disc_ids || !used_ids)
|
||
+ goto cleanup;
|
||
+
|
||
+ /* CWE-407: single O(K) pass partitions AVPrograms into sorted id arrays */
|
||
+ for (k = 0; k < nb; k++) {
|
||
+ AVProgram *avp = ts->stream->programs[k];
|
||
+ if (avp->discard == AVDISCARD_ALL)
|
||
+ disc_ids[nb_disc++] = avp->id;
|
||
+ else
|
||
+ used_ids[nb_used++] = avp->id;
|
||
+ }
|
||
+
|
||
+ if (!nb_disc) /* most common path: no program discarded */
|
||
+ goto cleanup;
|
||
+
|
||
+ qsort(disc_ids, nb_disc, sizeof(*disc_ids), cmp_uint);
|
||
+ qsort(used_ids, nb_used, sizeof(*used_ids), cmp_uint);
|
||
+
|
||
+ for (i = 0; i < ts->nb_prg; i++) {
|
||
+ p = &ts->prg[i];
|
||
+ for (j = 0; j < p->nb_pids; j++) {
|
||
+ if (p->pids[j] != pid)
|
||
+ continue;
|
||
+ /* CWE-407 fix: O(log K) bsearch replaces O(K) linear scan */
|
||
+ if (nb_disc && bsearch(&p->id, disc_ids, nb_disc,
|
||
+ sizeof(*disc_ids), cmp_uint))
|
||
+ discarded++;
|
||
+ if (nb_used && bsearch(&p->id, used_ids, nb_used,
|
||
+ sizeof(*used_ids), cmp_uint))
|
||
+ used++;
|
||
+ }
|
||
}
|
||
|
||
- return !used && discarded;
|
||
+ ret = !used && discarded;
|
||
+cleanup:
|
||
+ av_free(disc_ids);
|
||
+ av_free(used_ids);
|
||
+ return ret;
|
||
}
|