From 5a261cfa32d2833d20d87414bef267f3765abc4d Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt Date: Fri, 1 Oct 2021 18:17:42 +0200 Subject: [PATCH] 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 --- libavformat/allformats.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 99d8c91e00..889cfcc2c9 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -19,7 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/thread.h" +#include #include "libavformat/internal.h" #include "avformat.h" @@ -535,18 +535,20 @@ extern const AVInputFormat ff_vapoursynth_demuxer; #include "libavformat/muxer_list.c" #include "libavformat/demuxer_list.c" -static const AVInputFormat * const *indev_list = NULL; -static const AVOutputFormat * const *outdev_list = NULL; +static atomic_uintptr_t indev_list_intptr = ATOMIC_VAR_INIT(0); +static atomic_uintptr_t outdev_list_intptr = ATOMIC_VAR_INIT(0); const AVOutputFormat *av_muxer_iterate(void **opaque) { static const uintptr_t size = sizeof(muxer_list)/sizeof(muxer_list[0]) - 1; uintptr_t i = (uintptr_t)*opaque; const AVOutputFormat *f = NULL; + uintptr_t tmp; if (i < size) { 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]; } @@ -560,10 +562,12 @@ const AVInputFormat *av_demuxer_iterate(void **opaque) static const uintptr_t size = sizeof(demuxer_list)/sizeof(demuxer_list[0]) - 1; uintptr_t i = (uintptr_t)*opaque; const AVInputFormat *f = NULL; + uintptr_t tmp; if (i < size) { 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]; } @@ -572,12 +576,8 @@ const AVInputFormat *av_demuxer_iterate(void **opaque) return f; } -static AVMutex avpriv_register_devices_mutex = AV_MUTEX_INITIALIZER; - void avpriv_register_devices(const AVOutputFormat * const o[], const AVInputFormat * const i[]) { - ff_mutex_lock(&avpriv_register_devices_mutex); - outdev_list = o; - indev_list = i; - ff_mutex_unlock(&avpriv_register_devices_mutex); + atomic_store_explicit(&outdev_list_intptr, (uintptr_t)o, memory_order_relaxed); + atomic_store_explicit(&indev_list_intptr, (uintptr_t)i, memory_order_relaxed); }