Skip to content

Commit ff0706c

Browse files
committed
avcodec/mpegvideo: Fix memleak upon allocation error
When slice-threading is used, ff_mpv_common_init() duplicates the first MpegEncContext and allocates some buffers for each MpegEncContext (the first as well as the copies). But the count of allocated MpegEncContexts is not updated until after everything has been allocated and if an error happens after the first one has been allocated, only the first one is freed; the others leak. This commit fixes this: The count is now set before the copies are allocated. Furthermore, the copies are now created and initialized before the first MpegEncContext, so that the buffers exclusively owned by each MpegEncContext are still NULL in the src MpegEncContext so that no double-free happens upon allocation failure. Given that this effectively touches every line of the init code, it has also been factored out in a function of its own in order to remove code duplication with the same code in ff_mpv_common_frame_size_change() (which was never called when using more than one slice (and if it were, there would be potential double-frees)). Reviewed-by: Michael Niedermayer <michael@niedermayer.cc> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
1 parent d4b9e11 commit ff0706c

File tree

1 file changed

+36
-53
lines changed

1 file changed

+36
-53
lines changed

libavcodec/mpegvideo.c

Lines changed: 36 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -366,13 +366,6 @@ static int init_duplicate_context(MpegEncContext *s)
366366
if (s->mb_height & 1)
367367
yc_size += 2*s->b8_stride + 2*s->mb_stride;
368368

369-
s->sc.edge_emu_buffer =
370-
s->me.scratchpad =
371-
s->me.temp =
372-
s->sc.rd_scratchpad =
373-
s->sc.b_scratchpad =
374-
s->sc.obmc_scratchpad = NULL;
375-
376369
if (s->encoding) {
377370
if (!FF_ALLOCZ_TYPED_ARRAY(s->me.map, ME_MAP_SIZE) ||
378371
!FF_ALLOCZ_TYPED_ARRAY(s->me.score_map, ME_MAP_SIZE))
@@ -413,6 +406,35 @@ static int init_duplicate_context(MpegEncContext *s)
413406
return 0;
414407
}
415408

409+
/**
410+
* Initialize an MpegEncContext's thread contexts. Presumes that
411+
* slice_context_count is already set and that all the fields
412+
* that are freed/reset in free_duplicate_context() are NULL.
413+
*/
414+
static int init_duplicate_contexts(MpegEncContext *s)
415+
{
416+
int nb_slices = s->slice_context_count, ret;
417+
418+
/* We initialize the copies before the original so that
419+
* fields allocated in init_duplicate_context are NULL after
420+
* copying. This prevents double-frees upon allocation error. */
421+
for (int i = 1; i < nb_slices; i++) {
422+
s->thread_context[i] = av_memdup(s, sizeof(MpegEncContext));
423+
if (!s->thread_context[i])
424+
return AVERROR(ENOMEM);
425+
if ((ret = init_duplicate_context(s->thread_context[i])) < 0)
426+
return ret;
427+
s->thread_context[i]->start_mb_y =
428+
(s->mb_height * (i ) + nb_slices / 2) / nb_slices;
429+
s->thread_context[i]->end_mb_y =
430+
(s->mb_height * (i + 1) + nb_slices / 2) / nb_slices;
431+
}
432+
s->start_mb_y = 0;
433+
s->end_mb_y = nb_slices > 1 ? (s->mb_height + nb_slices / 2) / nb_slices
434+
: s->mb_height;
435+
return init_duplicate_context(s);
436+
}
437+
416438
static void free_duplicate_context(MpegEncContext *s)
417439
{
418440
if (!s)
@@ -949,29 +971,12 @@ av_cold int ff_mpv_common_init(MpegEncContext *s)
949971
s->context_initialized = 1;
950972
memset(s->thread_context, 0, sizeof(s->thread_context));
951973
s->thread_context[0] = s;
974+
s->slice_context_count = nb_slices;
952975

953976
// if (s->width && s->height) {
954-
if (nb_slices > 1) {
955-
for (i = 0; i < nb_slices; i++) {
956-
if (i) {
957-
s->thread_context[i] = av_memdup(s, sizeof(MpegEncContext));
958-
if (!s->thread_context[i])
959-
goto fail_nomem;
960-
}
961-
if ((ret = init_duplicate_context(s->thread_context[i])) < 0)
962-
goto fail;
963-
s->thread_context[i]->start_mb_y =
964-
(s->mb_height * (i) + nb_slices / 2) / nb_slices;
965-
s->thread_context[i]->end_mb_y =
966-
(s->mb_height * (i + 1) + nb_slices / 2) / nb_slices;
967-
}
968-
} else {
969-
if ((ret = init_duplicate_context(s)) < 0)
970-
goto fail;
971-
s->start_mb_y = 0;
972-
s->end_mb_y = s->mb_height;
973-
}
974-
s->slice_context_count = nb_slices;
977+
ret = init_duplicate_contexts(s);
978+
if (ret < 0)
979+
goto fail;
975980
// }
976981

977982
return 0;
@@ -1088,31 +1093,9 @@ int ff_mpv_common_frame_size_change(MpegEncContext *s)
10881093
s->thread_context[0] = s;
10891094

10901095
if (s->width && s->height) {
1091-
int nb_slices = s->slice_context_count;
1092-
if (nb_slices > 1) {
1093-
for (i = 0; i < nb_slices; i++) {
1094-
if (i) {
1095-
s->thread_context[i] = av_memdup(s, sizeof(MpegEncContext));
1096-
if (!s->thread_context[i]) {
1097-
err = AVERROR(ENOMEM);
1098-
goto fail;
1099-
}
1100-
}
1101-
if ((err = init_duplicate_context(s->thread_context[i])) < 0)
1102-
goto fail;
1103-
s->thread_context[i]->start_mb_y =
1104-
(s->mb_height * (i) + nb_slices / 2) / nb_slices;
1105-
s->thread_context[i]->end_mb_y =
1106-
(s->mb_height * (i + 1) + nb_slices / 2) / nb_slices;
1107-
}
1108-
} else {
1109-
err = init_duplicate_context(s);
1110-
if (err < 0)
1111-
goto fail;
1112-
s->start_mb_y = 0;
1113-
s->end_mb_y = s->mb_height;
1114-
}
1115-
s->slice_context_count = nb_slices;
1096+
err = init_duplicate_contexts(s);
1097+
if (err < 0)
1098+
goto fail;
11161099
}
11171100

11181101
return 0;

0 commit comments

Comments
 (0)