diff mbox series

[FFmpeg-devel,17/23] avcodec/wmaprodec: Make decoders init-threadsafe

Message ID VI1PR0301MB21597A614992FC884D470B828F589@VI1PR0301MB2159.eurprd03.prod.outlook.com
State Accepted
Commit 3c3712ee2bd9e2ec2d6bd576c5f05e169c36ad5a
Headers show
Series [FFmpeg-devel,01/23] avcodec/ljpegenc: Mark encoder as init-threadsafe
Related show

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished
andriy/PPC64_make success Make finished
andriy/PPC64_make_fate success Make fate finished

Commit Message

Andreas Rheinhardt May 6, 2021, 5:11 a.m. UTC
In this case this actually fixes a potential data race: The static VLC
tables were reinitialized every time an AVCodecContext has been
initialized; while the mutex in avcodec_open2() ensured that the VLCs
could not be initialized concurrently by multiple threads, nothing
guaranteed that these VLCs are not read concurrently (when decoding a
packet with an already initialized AVCodecContext) while another thread
initializes them. This is undefined behaviour despite the values being
written coinciding with the earlier values.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/wmaprodec.c | 75 ++++++++++++++++++++++--------------------
 1 file changed, 39 insertions(+), 36 deletions(-)
diff mbox series

Patch

diff --git a/libavcodec/wmaprodec.c b/libavcodec/wmaprodec.c
index 4b2dceb5bc..e0d00d2d37 100644
--- a/libavcodec/wmaprodec.c
+++ b/libavcodec/wmaprodec.c
@@ -93,6 +93,7 @@ 
 #include "libavutil/intfloat.h"
 #include "libavutil/intreadwrite.h"
 #include "libavutil/mem_internal.h"
+#include "libavutil/thread.h"
 
 #include "avcodec.h"
 #include "internal.h"
@@ -309,6 +310,38 @@  static av_cold int get_rate(AVCodecContext *avctx)
     return avctx->sample_rate;
 }
 
+static av_cold void decode_init_static(void)
+{
+    INIT_VLC_STATIC(&sf_vlc, SCALEVLCBITS, HUFF_SCALE_SIZE,
+                    scale_huffbits, 1, 1,
+                    scale_huffcodes, 2, 2, 616);
+    INIT_VLC_STATIC(&sf_rl_vlc, VLCBITS, HUFF_SCALE_RL_SIZE,
+                    scale_rl_huffbits, 1, 1,
+                    scale_rl_huffcodes, 4, 4, 1406);
+    INIT_VLC_STATIC(&coef_vlc[0], VLCBITS, HUFF_COEF0_SIZE,
+                    coef0_huffbits, 1, 1,
+                    coef0_huffcodes, 4, 4, 2108);
+    INIT_VLC_STATIC(&coef_vlc[1], VLCBITS, HUFF_COEF1_SIZE,
+                    coef1_huffbits, 1, 1,
+                    coef1_huffcodes, 4, 4, 3912);
+    INIT_VLC_STATIC(&vec4_vlc, VLCBITS, HUFF_VEC4_SIZE,
+                    vec4_huffbits, 1, 1,
+                    vec4_huffcodes, 2, 2, 604);
+    INIT_VLC_STATIC(&vec2_vlc, VLCBITS, HUFF_VEC2_SIZE,
+                    vec2_huffbits, 1, 1,
+                    vec2_huffcodes, 2, 2, 562);
+    INIT_VLC_STATIC(&vec1_vlc, VLCBITS, HUFF_VEC1_SIZE,
+                    vec1_huffbits, 1, 1,
+                    vec1_huffcodes, 2, 2, 562);
+
+    /** calculate sine values for the decorrelation matrix */
+    for (int i = 0; i < 33; i++)
+        sin64[i] = sin(i * M_PI / 64.0);
+
+    for (int i = WMAPRO_BLOCK_MIN_BITS; i <= WMAPRO_BLOCK_MAX_BITS; i++)
+        ff_init_ff_sine_windows(i);
+}
+
 /**
  *@brief Initialize the decoder.
  *@param avctx codec context
@@ -316,6 +349,7 @@  static av_cold int get_rate(AVCodecContext *avctx)
  */
 static av_cold int decode_init(WMAProDecodeCtx *s, AVCodecContext *avctx, int num_stream)
 {
+    static AVOnce init_static_once = AV_ONCE_INIT;
     uint8_t *edata_ptr = avctx->extradata;
     unsigned int channel_mask;
     int i, bits, ret;
@@ -460,34 +494,6 @@  static av_cold int decode_init(WMAProDecodeCtx *s, AVCodecContext *avctx, int nu
         }
     }
 
-    INIT_VLC_STATIC(&sf_vlc, SCALEVLCBITS, HUFF_SCALE_SIZE,
-                    scale_huffbits, 1, 1,
-                    scale_huffcodes, 2, 2, 616);
-
-    INIT_VLC_STATIC(&sf_rl_vlc, VLCBITS, HUFF_SCALE_RL_SIZE,
-                    scale_rl_huffbits, 1, 1,
-                    scale_rl_huffcodes, 4, 4, 1406);
-
-    INIT_VLC_STATIC(&coef_vlc[0], VLCBITS, HUFF_COEF0_SIZE,
-                    coef0_huffbits, 1, 1,
-                    coef0_huffcodes, 4, 4, 2108);
-
-    INIT_VLC_STATIC(&coef_vlc[1], VLCBITS, HUFF_COEF1_SIZE,
-                    coef1_huffbits, 1, 1,
-                    coef1_huffcodes, 4, 4, 3912);
-
-    INIT_VLC_STATIC(&vec4_vlc, VLCBITS, HUFF_VEC4_SIZE,
-                    vec4_huffbits, 1, 1,
-                    vec4_huffcodes, 2, 2, 604);
-
-    INIT_VLC_STATIC(&vec2_vlc, VLCBITS, HUFF_VEC2_SIZE,
-                    vec2_huffbits, 1, 1,
-                    vec2_huffcodes, 2, 2, 562);
-
-    INIT_VLC_STATIC(&vec1_vlc, VLCBITS, HUFF_VEC1_SIZE,
-                    vec1_huffbits, 1, 1,
-                    vec1_huffcodes, 2, 2, 562);
-
     /** calculate number of scale factor bands and their offsets
         for every possible block size */
     for (i = 0; i < num_possible_block_sizes; i++) {
@@ -554,7 +560,6 @@  static av_cold int decode_init(WMAProDecodeCtx *s, AVCodecContext *avctx, int nu
     /** init MDCT windows: simple sine window */
     for (i = 0; i < WMAPRO_BLOCK_SIZES; i++) {
         const int win_idx = WMAPRO_BLOCK_MAX_BITS - i;
-        ff_init_ff_sine_windows(win_idx);
         s->windows[WMAPRO_BLOCK_SIZES - i - 1] = ff_sine_windows[win_idx];
     }
 
@@ -566,15 +571,13 @@  static av_cold int decode_init(WMAProDecodeCtx *s, AVCodecContext *avctx, int nu
         s->subwoofer_cutoffs[i] = av_clip(cutoff, 4, block_size);
     }
 
-    /** calculate sine values for the decorrelation matrix */
-    for (i = 0; i < 33; i++)
-        sin64[i] = sin(i*M_PI / 64.0);
-
     if (avctx->debug & FF_DEBUG_BITSTREAM)
         dump_context(s);
 
     avctx->channel_layout = channel_mask;
 
+    ff_thread_once(&init_static_once, decode_init_static);
+
     return 0;
 }
 
@@ -2018,10 +2021,10 @@  const AVCodec ff_wmapro_decoder = {
     .close          = wmapro_decode_end,
     .decode         = wmapro_decode_packet,
     .capabilities   = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1,
-    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
     .flush          = wmapro_flush,
     .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
                                                       AV_SAMPLE_FMT_NONE },
+    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
 };
 
 const AVCodec ff_xma1_decoder = {
@@ -2034,9 +2037,9 @@  const AVCodec ff_xma1_decoder = {
     .close          = xma_decode_end,
     .decode         = xma_decode_packet,
     .capabilities   = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY,
-    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
     .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
                                                       AV_SAMPLE_FMT_NONE },
+    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
 };
 
 const AVCodec ff_xma2_decoder = {
@@ -2050,7 +2053,7 @@  const AVCodec ff_xma2_decoder = {
     .decode         = xma_decode_packet,
     .flush          = xma_flush,
     .capabilities   = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY,
-    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
     .sample_fmts    = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
                                                       AV_SAMPLE_FMT_NONE },
+    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
 };