Prechádzať zdrojové kódy

libobs, UI: Fix cpp auto-release assignment from OBSRefs

The *AutoRelease helpers should not take references from OBSRef objects.
Instead, make an OBSRefAutoRelease base class, and OBSRef a subclass of
that to allow moves, and then perform moves from those objects.

This fixes an issue where *AutoRelease OBSRef objects would cause an
unintended double release of objects after having been assigned values
from non-*AutoRelease OBSRef objects.
jp9000 4 rokov pred
rodič
commit
52cc1d533e

+ 4 - 5
UI/window-basic-main-transitions.cpp

@@ -403,9 +403,9 @@ void OBSBasic::TransitionToScene(OBSSource source, bool force,
 		OBSSource trOverride = GetOverrideTransition(source);
 
 		if (trOverride && !overridingTransition && !quickTransition) {
-			transition = trOverride;
+			transition = std::move(trOverride);
 			duration = GetOverrideTransitionDuration(source);
-			OverrideTransition(trOverride);
+			OverrideTransition(transition.Get());
 			overridingTransition = true;
 		}
 
@@ -974,7 +974,7 @@ void OBSBasic::TBarChanged(int value)
 			OverrideTransition(tBarTr);
 			overridingTransition = true;
 
-			transition = tBarTr;
+			transition = std::move(tBarTr);
 		}
 
 		obs_transition_set_manual_torque(transition, 8.0f, 0.05f);
@@ -1603,8 +1603,7 @@ void OBSBasic::SetPreviewProgramMode(bool enabled)
 					? OBS_SCENE_DUP_PRIVATE_COPY
 					: OBS_SCENE_DUP_PRIVATE_REFS);
 		} else {
-			dup = curScene;
-			obs_scene_addref(dup);
+			dup = std::move(OBSScene(curScene));
 		}
 
 		OBSSourceAutoRelease transition = obs_get_output_source(0);

+ 6 - 11
UI/window-basic-main.cpp

@@ -1012,9 +1012,7 @@ void OBSBasic::LoadData(obs_data_t *data, const char *file)
 	LoadAudioDevice(AUX_AUDIO_4, 6, data);
 
 	if (!sources) {
-		sources = groups;
-		obs_data_array_addref(groups);
-		groups = nullptr;
+		sources = std::move(groups);
 	} else {
 		obs_data_array_push_back_array(sources, groups);
 	}
@@ -1059,12 +1057,10 @@ retryScene:
 		goto retryScene;
 	}
 
-	if (!curProgramScene) {
-		curProgramScene = curScene;
-		obs_source_addref(curScene);
-	}
-
 	SetCurrentScene(curScene.Get(), true);
+
+	if (!curProgramScene)
+		curProgramScene = std::move(curScene);
 	if (IsPreviewProgramMode())
 		TransitionToScene(curProgramScene.Get(), true);
 
@@ -5128,9 +5124,8 @@ void OBSBasic::on_actionAddScene_triggered()
 				  undo_fn, redo_fn, name, name);
 
 		OBSSceneAutoRelease scene = obs_scene_create(name.c_str());
-		source = obs_scene_get_source(scene);
-		obs_source_addref(source);
-		SetCurrentScene(source.Get());
+		obs_source_t *scene_source = obs_scene_get_source(scene);
+		SetCurrentScene(scene_source);
 	}
 }
 

+ 59 - 57
libobs/obs.hpp

@@ -23,6 +23,7 @@
 
 /* RAII wrappers */
 
+template<typename T, void release(T)> class OBSRefAutoRelease;
 template<typename T, void addref(T), void release(T)> class OBSRef;
 
 using OBSSource = OBSRef<obs_source_t *, obs_source_addref, obs_source_release>;
@@ -48,79 +49,52 @@ using OBSWeakService = OBSRef<obs_weak_service_t *, obs_weak_service_addref,
 			      obs_weak_service_release>;
 
 #define OBS_AUTORELEASE
-inline void ___source_dummy_addref(obs_source_t *){};
-inline void ___scene_dummy_addref(obs_scene_t *){};
-inline void ___sceneitem_dummy_addref(obs_sceneitem_t *){};
-inline void ___data_dummy_addref(obs_data_t *){};
-inline void ___data_array_dummy_addref(obs_data_array_t *){};
-inline void ___output_dummy_addref(obs_output_t *){};
-inline void ___encoder_dummy_addref(obs_encoder_t *){};
-inline void ___service_dummy_addref(obs_service_t *){};
-
-inline void ___weak_source_dummy_addref(obs_weak_source_t *){};
-inline void ___weak_output_dummy_addref(obs_weak_output_t *){};
-inline void ___weak_encoder_dummy_addref(obs_weak_encoder_t *){};
-inline void ___weak_service_dummy_addref(obs_weak_service_t *){};
-
 using OBSSourceAutoRelease =
-	OBSRef<obs_source_t *, ___source_dummy_addref, obs_source_release>;
-using OBSSceneAutoRelease =
-	OBSRef<obs_scene_t *, ___scene_dummy_addref, obs_scene_release>;
+	OBSRefAutoRelease<obs_source_t *, obs_source_release>;
+using OBSSceneAutoRelease = OBSRefAutoRelease<obs_scene_t *, obs_scene_release>;
 using OBSSceneItemAutoRelease =
-	OBSRef<obs_sceneitem_t *, ___sceneitem_dummy_addref,
-	       obs_sceneitem_release>;
-using OBSDataAutoRelease =
-	OBSRef<obs_data_t *, ___data_dummy_addref, obs_data_release>;
+	OBSRefAutoRelease<obs_sceneitem_t *, obs_sceneitem_release>;
+using OBSDataAutoRelease = OBSRefAutoRelease<obs_data_t *, obs_data_release>;
 using OBSDataArrayAutoRelease =
-	OBSRef<obs_data_array_t *, ___data_array_dummy_addref,
-	       obs_data_array_release>;
+	OBSRefAutoRelease<obs_data_array_t *, obs_data_array_release>;
 using OBSOutputAutoRelease =
-	OBSRef<obs_output_t *, ___output_dummy_addref, obs_output_release>;
+	OBSRefAutoRelease<obs_output_t *, obs_output_release>;
 using OBSEncoderAutoRelease =
-	OBSRef<obs_encoder_t *, ___encoder_dummy_addref, obs_encoder_release>;
+	OBSRefAutoRelease<obs_encoder_t *, obs_encoder_release>;
 using OBSServiceAutoRelease =
-	OBSRef<obs_service_t *, ___service_dummy_addref, obs_service_release>;
+	OBSRefAutoRelease<obs_service_t *, obs_service_release>;
 
 using OBSWeakSourceAutoRelease =
-	OBSRef<obs_weak_source_t *, ___weak_source_dummy_addref,
-	       obs_weak_source_release>;
+	OBSRefAutoRelease<obs_weak_source_t *, obs_weak_source_release>;
 using OBSWeakOutputAutoRelease =
-	OBSRef<obs_weak_output_t *, ___weak_output_dummy_addref,
-	       obs_weak_output_release>;
+	OBSRefAutoRelease<obs_weak_output_t *, obs_weak_output_release>;
 using OBSWeakEncoderAutoRelease =
-	OBSRef<obs_weak_encoder_t *, ___weak_encoder_dummy_addref,
-	       obs_weak_encoder_release>;
+	OBSRefAutoRelease<obs_weak_encoder_t *, obs_weak_encoder_release>;
 using OBSWeakServiceAutoRelease =
-	OBSRef<obs_weak_service_t *, ___weak_service_dummy_addref,
-	       obs_weak_service_release>;
+	OBSRefAutoRelease<obs_weak_service_t *, obs_weak_service_release>;
 
-template<typename T, void addref(T), void release(T)> class OBSRef {
+template<typename T, void release(T)> class OBSRefAutoRelease {
+protected:
 	T val;
 
-	inline OBSRef &Replace(T valIn)
+public:
+	inline OBSRefAutoRelease() : val(nullptr) {}
+	inline OBSRefAutoRelease(T val_) : val(val_) {}
+	OBSRefAutoRelease(const OBSRefAutoRelease &ref) = delete;
+	inline OBSRefAutoRelease(OBSRefAutoRelease &&ref) : val(ref.val)
 	{
-		addref(valIn);
-		release(val);
-		val = valIn;
-		return *this;
+		ref.val = nullptr;
 	}
 
-	struct TakeOwnership {
-	};
-	inline OBSRef(T val, TakeOwnership) : val(val) {}
-
-public:
-	inline OBSRef() : val(nullptr) {}
-	inline OBSRef(T val_) : val(val_) { addref(val); }
-	inline OBSRef(const OBSRef &ref) : val(ref.val) { addref(val); }
-	inline OBSRef(OBSRef &&ref) : val(ref.val) { ref.val = nullptr; }
+	inline ~OBSRefAutoRelease() { release(val); }
 
-	inline ~OBSRef() { release(val); }
+	inline operator T() const { return val; }
+	inline T Get() const { return val; }
 
-	inline OBSRef &operator=(T valIn) { return Replace(valIn); }
-	inline OBSRef &operator=(const OBSRef &ref) { return Replace(ref.val); }
+	inline bool operator==(T p) const { return val == p; }
+	inline bool operator!=(T p) const { return val != p; }
 
-	inline OBSRef &operator=(OBSRef &&ref)
+	inline OBSRefAutoRelease &operator=(OBSRefAutoRelease &&ref)
 	{
 		if (this != &ref) {
 			release(val);
@@ -131,11 +105,39 @@ public:
 		return *this;
 	}
 
-	inline operator T() const { return val; }
-	inline T Get() const { return val; }
+	inline OBSRefAutoRelease &operator=(T new_val)
+	{
+		release(val);
+		val = new_val;
+		return *this;
+	}
+};
 
-	inline bool operator==(T p) const { return val == p; }
-	inline bool operator!=(T p) const { return val != p; }
+template<typename T, void addref(T), void release(T)>
+class OBSRef : public OBSRefAutoRelease<T, release> {
+
+	inline OBSRef &Replace(T valIn)
+	{
+		addref(valIn);
+		release(val);
+		val = valIn;
+		return *this;
+	}
+
+	struct TakeOwnership {
+	};
+	inline OBSRef(T val, TakeOwnership) : OBSRefAutoRelease(val) {}
+
+public:
+	inline OBSRef() : OBSRefAutoRelease(nullptr) {}
+	inline OBSRef(const OBSRef &ref) : OBSRefAutoRelease(ref.val)
+	{
+		addref(val);
+	}
+	inline OBSRef(T val_) : OBSRefAutoRelease(val_) { addref(val); }
+
+	inline OBSRef &operator=(const OBSRef &ref) { return Replace(ref.val); }
+	inline OBSRef &operator=(T valIn) { return Replace(valIn); }
 
 	friend OBSSource OBSGetStrongRef(obs_weak_source_t *weak);
 	friend OBSWeakSource OBSGetWeakRef(obs_source_t *source);