From f109be3010cc3bda51c14ce3db6c7fcacc63d1d7 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Tue, 17 Mar 2015 18:23:04 -0700 Subject: [PATCH] libobs: Fix potential bug destroying filters When OBS is shutting down, if for some reason the filter is destroyed before the parent source is destroyed, it would try to remove itself from the source, but it would decrement the reference and try to destroy itself again while already in the process of destroying itself. So, the solution was simply to make sure that if it's removing itself from the source that it doesn't decrement its own reference. --- libobs/obs-source.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/libobs/obs-source.c b/libobs/obs-source.c index ba8daa946..c24c56f3b 100644 --- a/libobs/obs-source.c +++ b/libobs/obs-source.c @@ -244,6 +244,9 @@ static inline void obs_source_frame_decref(struct obs_source_frame *frame) obs_source_frame_destroy(frame); } +static bool obs_source_filter_remove_refless(obs_source_t *source, + obs_source_t *filter); + void obs_source_destroy(struct obs_source *source) { size_t i; @@ -254,6 +257,12 @@ void obs_source_destroy(struct obs_source *source) if (source->info.type == OBS_SOURCE_TYPE_TRANSITION) os_atomic_dec_long(&obs->data.active_transitions); + if (source->filter_parent) + obs_source_filter_remove_refless(source->filter_parent, source); + + while (source->filters.num) + obs_source_filter_remove(source, source->filters.array[0]); + obs_context_data_remove(&source->context); blog(LOG_INFO, "source '%s' destroyed", source->context.name); @@ -265,12 +274,6 @@ void obs_source_destroy(struct obs_source *source) source->context.data = NULL; } - if (source->filter_parent) - obs_source_filter_remove(source->filter_parent, source); - - while (source->filters.num) - obs_source_filter_remove(source, source->filters.array[0]); - for (i = 0; i < source->async_cache.num; i++) obs_source_frame_decref(source->async_cache.array[i].frame); @@ -1327,19 +1330,20 @@ void obs_source_filter_add(obs_source_t *source, obs_source_t *filter) calldata_free(&cd); } -void obs_source_filter_remove(obs_source_t *source, obs_source_t *filter) +static bool obs_source_filter_remove_refless(obs_source_t *source, + obs_source_t *filter) { struct calldata cd = {0}; size_t idx; if (!source || !filter) - return; + return false; pthread_mutex_lock(&source->filter_mutex); idx = da_find(source->filters, &filter, 0); if (idx == DARRAY_INVALID) - return; + return false; if (idx > 0) { obs_source_t *prev = source->filters.array[idx-1]; @@ -1363,8 +1367,13 @@ void obs_source_filter_remove(obs_source_t *source, obs_source_t *filter) filter->filter_parent = NULL; filter->filter_target = NULL; + return true; +} - obs_source_release(filter); +void obs_source_filter_remove(obs_source_t *source, obs_source_t *filter) +{ + if (obs_source_filter_remove_refless(source, filter)) + obs_source_release(filter); } static bool move_filter_dir(obs_source_t *source,