Browse Source

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.
jp9000 10 năm trước cách đây
mục cha
commit
f109be3010
1 tập tin đã thay đổi với 19 bổ sung10 xóa
  1. 19 10
      libobs/obs-source.c

+ 19 - 10
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);
 		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)
 void obs_source_destroy(struct obs_source *source)
 {
 {
 	size_t i;
 	size_t i;
@@ -254,6 +257,12 @@ void obs_source_destroy(struct obs_source *source)
 	if (source->info.type == OBS_SOURCE_TYPE_TRANSITION)
 	if (source->info.type == OBS_SOURCE_TYPE_TRANSITION)
 		os_atomic_dec_long(&obs->data.active_transitions);
 		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);
 	obs_context_data_remove(&source->context);
 
 
 	blog(LOG_INFO, "source '%s' destroyed", source->context.name);
 	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;
 		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++)
 	for (i = 0; i < source->async_cache.num; i++)
 		obs_source_frame_decref(source->async_cache.array[i].frame);
 		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);
 	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};
 	struct calldata cd = {0};
 	size_t idx;
 	size_t idx;
 
 
 	if (!source || !filter)
 	if (!source || !filter)
-		return;
+		return false;
 
 
 	pthread_mutex_lock(&source->filter_mutex);
 	pthread_mutex_lock(&source->filter_mutex);
 
 
 	idx = da_find(source->filters, &filter, 0);
 	idx = da_find(source->filters, &filter, 0);
 	if (idx == DARRAY_INVALID)
 	if (idx == DARRAY_INVALID)
-		return;
+		return false;
 
 
 	if (idx > 0) {
 	if (idx > 0) {
 		obs_source_t *prev = source->filters.array[idx-1];
 		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_parent = NULL;
 	filter->filter_target = 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,
 static bool move_filter_dir(obs_source_t *source,