1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2025-01-29 22:00:58 +02:00

avformat/allformats: Fix data race when accessing devices lists

Up until now setting the input and output devices lists is guarded
by a mutex. This prevents data races emanating from multiple concurrent
calls to avpriv_register_devices() (triggered by multiple concurrent
calls to avdevice_register_all()). Yet reading the lists pointers was
done without any lock and with nonatomic variables. This means that
there are data races in case of concurrent calls to
av_(de)muxer_iterate() and avdevice_register_all() (but only if the
iteration in av_(de)muxer_iterate exhausts the non-device (de)muxers).

This commit fixes this by putting said pointers into atomic objects.
Due to the unavailability of _Atomic the object is an atomic_uintptr,
leading to ugly casts. Switching to atomics also allowed to remove
the mutex currently used in avpriv_register_devices().

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
This commit is contained in:
Andreas Rheinhardt 2021-10-01 18:17:42 +02:00
parent 98aec8c1b8
commit 5a261cfa32

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "libavutil/thread.h" #include <stdatomic.h>
#include "libavformat/internal.h" #include "libavformat/internal.h"
#include "avformat.h" #include "avformat.h"
@ -535,18 +535,20 @@ extern const AVInputFormat ff_vapoursynth_demuxer;
#include "libavformat/muxer_list.c" #include "libavformat/muxer_list.c"
#include "libavformat/demuxer_list.c" #include "libavformat/demuxer_list.c"
static const AVInputFormat * const *indev_list = NULL; static atomic_uintptr_t indev_list_intptr = ATOMIC_VAR_INIT(0);
static const AVOutputFormat * const *outdev_list = NULL; static atomic_uintptr_t outdev_list_intptr = ATOMIC_VAR_INIT(0);
const AVOutputFormat *av_muxer_iterate(void **opaque) const AVOutputFormat *av_muxer_iterate(void **opaque)
{ {
static const uintptr_t size = sizeof(muxer_list)/sizeof(muxer_list[0]) - 1; static const uintptr_t size = sizeof(muxer_list)/sizeof(muxer_list[0]) - 1;
uintptr_t i = (uintptr_t)*opaque; uintptr_t i = (uintptr_t)*opaque;
const AVOutputFormat *f = NULL; const AVOutputFormat *f = NULL;
uintptr_t tmp;
if (i < size) { if (i < size) {
f = muxer_list[i]; f = muxer_list[i];
} else if (outdev_list) { } else if (tmp = atomic_load_explicit(&outdev_list_intptr, memory_order_relaxed)) {
const AVOutputFormat *const *outdev_list = (const AVOutputFormat *const *)tmp;
f = outdev_list[i - size]; f = outdev_list[i - size];
} }
@ -560,10 +562,12 @@ const AVInputFormat *av_demuxer_iterate(void **opaque)
static const uintptr_t size = sizeof(demuxer_list)/sizeof(demuxer_list[0]) - 1; static const uintptr_t size = sizeof(demuxer_list)/sizeof(demuxer_list[0]) - 1;
uintptr_t i = (uintptr_t)*opaque; uintptr_t i = (uintptr_t)*opaque;
const AVInputFormat *f = NULL; const AVInputFormat *f = NULL;
uintptr_t tmp;
if (i < size) { if (i < size) {
f = demuxer_list[i]; f = demuxer_list[i];
} else if (indev_list) { } else if (tmp = atomic_load_explicit(&indev_list_intptr, memory_order_relaxed)) {
const AVInputFormat *const *indev_list = (const AVInputFormat *const *)tmp;
f = indev_list[i - size]; f = indev_list[i - size];
} }
@ -572,12 +576,8 @@ const AVInputFormat *av_demuxer_iterate(void **opaque)
return f; return f;
} }
static AVMutex avpriv_register_devices_mutex = AV_MUTEX_INITIALIZER;
void avpriv_register_devices(const AVOutputFormat * const o[], const AVInputFormat * const i[]) void avpriv_register_devices(const AVOutputFormat * const o[], const AVInputFormat * const i[])
{ {
ff_mutex_lock(&avpriv_register_devices_mutex); atomic_store_explicit(&outdev_list_intptr, (uintptr_t)o, memory_order_relaxed);
outdev_list = o; atomic_store_explicit(&indev_list_intptr, (uintptr_t)i, memory_order_relaxed);
indev_list = i;
ff_mutex_unlock(&avpriv_register_devices_mutex);
} }