History

avfilter/asrc_flite: Fix races upon (un)registering voices

The voice registration system in libflite is broken: It is not thread-safe and also not based on internal counters; instead any call to unregister a voice frees said voice even if there are still many other users of said voice who have also registered said voice. While there is no way to guard against another library unregistering voices behind our back, we can at least be correct in the absence of other users of libflite. The current code already tried this by using a reference count of our own for each voice; but the implementation of this is not thread-safe at all. Fix this by using a mutex to guard all of libavfilter's libflite registration and unregistration calls, thereby being thread-safe in the absence of other libflite users.

Andreas Rheinhardt committed 5 years ago

Commit aac8fa21 parent 18ddb251 file · +21 −8Browse files

Unified · Split

libavfilter/asrc_flite.c+21−8
@@ -27,6 +27,7 @@ · 26 unmodified lines
2727 #include "libavutil/channel_layout.h"
2828 #include "libavutil/file.h"
2929 #include "libavutil/opt.h"
30+#include "libavutil/thread.h"
3031 #include "avfilter.h"
3132 #include "audio.h"
3233 #include "formats.h"
@@ -63,7 +64,9 @@ static const AVOption flite_options[] = { · 30 unmodified lines
6364
6465 AVFILTER_DEFINE_CLASS(flite);
6566
66−static volatile int flite_inited = 0;
67+static AVMutex flite_mutex = AV_MUTEX_INITIALIZER;
68+
69+static int flite_inited = 0;
6770
6871 /* declare functions for all the supported voices */
6972 #define DECLARE_REGISTER_VOICE_FN(name) \
@@ -111,14 +114,19 @@ static int select_voice(struct voice_entry **entry_ret, const char *voice_name, · 41 unmodified lines
111114 for (i = 0; i < FF_ARRAY_ELEMS(voice_entries); i++) {
112115 struct voice_entry *entry = &voice_entries[i];
113116 if (!strcmp(entry->name, voice_name)) {
117+ cst_voice *voice;
118+ pthread_mutex_lock(&flite_mutex);
114119 if (!entry->voice)
115120 entry->voice = entry->register_fn(NULL);
116− if (!entry->voice) {
121+ voice = entry->voice;
122+ if (voice)
123+ entry->usage_count++;
124+ pthread_mutex_unlock(&flite_mutex);
125+ if (!voice) {
117126 av_log(log_ctx, AV_LOG_ERROR,
118127 "Could not register voice '%s'\n", voice_name);
119128 return AVERROR_UNKNOWN;
120129 }
121− entry->usage_count++;
122130 *entry_ret = entry;
123131 return 0;
124132 }
@@ -141,12 +149,15 @@ static av_cold int init(AVFilterContext *ctx) · 16 unmodified lines
141149 return AVERROR_EXIT;
142150 }
143151
152+ pthread_mutex_lock(&flite_mutex);
144153 if (!flite_inited) {
145− if (flite_init() < 0) {
146− av_log(ctx, AV_LOG_ERROR, "flite initialization failed\n");
147− return AVERROR_UNKNOWN;
148− }
149− flite_inited++;
154+ if ((ret = flite_init()) >= 0)
155+ flite_inited = 1;
156+ }
157+ pthread_mutex_unlock(&flite_mutex);
158+ if (ret < 0) {
159+ av_log(ctx, AV_LOG_ERROR, "flite initialization failed\n");
160+ return AVERROR_EXTERNAL;
150161 }
151162
152163 if ((ret = select_voice(&flite->voice_entry, flite->voice_str, ctx)) < 0)
@@ -197,10 +208,12 @@ static av_cold void uninit(AVFilterContext *ctx) · 44 unmodified lines
197208 FliteContext *flite = ctx->priv;
198209
199210 if (flite->voice_entry) {
211+ pthread_mutex_lock(&flite_mutex);
200212 if (!--flite->voice_entry->usage_count) {
201213 flite->voice_entry->unregister_fn(flite->voice);
202214 flite->voice_entry->voice = NULL;
203215 }
216+ pthread_mutex_unlock(&flite_mutex);
204217 }
205218 delete_wave(flite->wave);
206219 flite->wave = NULL;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t