avcodec/wmaprodec: Make decoders init-threadsafe

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>
pull/362/head
Andreas Rheinhardt 4 years ago
parent a1b0148366
commit 3c3712ee2b
  1. 75
      libavcodec/wmaprodec.c

@ -93,6 +93,7 @@
#include "libavutil/intfloat.h" #include "libavutil/intfloat.h"
#include "libavutil/intreadwrite.h" #include "libavutil/intreadwrite.h"
#include "libavutil/mem_internal.h" #include "libavutil/mem_internal.h"
#include "libavutil/thread.h"
#include "avcodec.h" #include "avcodec.h"
#include "internal.h" #include "internal.h"
@ -309,6 +310,38 @@ static av_cold int get_rate(AVCodecContext *avctx)
return avctx->sample_rate; 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. *@brief Initialize the decoder.
*@param avctx codec context *@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 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; uint8_t *edata_ptr = avctx->extradata;
unsigned int channel_mask; unsigned int channel_mask;
int i, bits, ret; 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 /** calculate number of scale factor bands and their offsets
for every possible block size */ for every possible block size */
for (i = 0; i < num_possible_block_sizes; i++) { 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 */ /** init MDCT windows: simple sine window */
for (i = 0; i < WMAPRO_BLOCK_SIZES; i++) { for (i = 0; i < WMAPRO_BLOCK_SIZES; i++) {
const int win_idx = WMAPRO_BLOCK_MAX_BITS - 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]; 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); 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) if (avctx->debug & FF_DEBUG_BITSTREAM)
dump_context(s); dump_context(s);
avctx->channel_layout = channel_mask; avctx->channel_layout = channel_mask;
ff_thread_once(&init_static_once, decode_init_static);
return 0; return 0;
} }
@ -2018,10 +2021,10 @@ const AVCodec ff_wmapro_decoder = {
.close = wmapro_decode_end, .close = wmapro_decode_end,
.decode = wmapro_decode_packet, .decode = wmapro_decode_packet,
.capabilities = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1, .capabilities = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1,
.caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
.flush = wmapro_flush, .flush = wmapro_flush,
.sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_NONE }, AV_SAMPLE_FMT_NONE },
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
}; };
const AVCodec ff_xma1_decoder = { const AVCodec ff_xma1_decoder = {
@ -2034,9 +2037,9 @@ const AVCodec ff_xma1_decoder = {
.close = xma_decode_end, .close = xma_decode_end,
.decode = xma_decode_packet, .decode = xma_decode_packet,
.capabilities = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .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, .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_NONE }, AV_SAMPLE_FMT_NONE },
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
}; };
const AVCodec ff_xma2_decoder = { const AVCodec ff_xma2_decoder = {
@ -2050,7 +2053,7 @@ const AVCodec ff_xma2_decoder = {
.decode = xma_decode_packet, .decode = xma_decode_packet,
.flush = xma_flush, .flush = xma_flush,
.capabilities = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .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, .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP,
AV_SAMPLE_FMT_NONE }, AV_SAMPLE_FMT_NONE },
.caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP,
}; };

Loading…
Cancel
Save