From 52cc1d533ef1882bb0f6677d509259aef296675d Mon Sep 17 00:00:00 2001 From: jp9000 Date: Thu, 30 Dec 2021 21:10:50 -0800 Subject: [PATCH] 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. --- UI/window-basic-main-transitions.cpp | 9 +- UI/window-basic-main.cpp | 17 ++-- libobs/obs.hpp | 120 ++++++++++++++------------- 3 files changed, 71 insertions(+), 75 deletions(-) diff --git a/UI/window-basic-main-transitions.cpp b/UI/window-basic-main-transitions.cpp index 19d0bb955..5daa09252 100644 --- a/UI/window-basic-main-transitions.cpp +++ b/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); diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index 2a9c531ae..f63f14baa 100644 --- a/UI/window-basic-main.cpp +++ b/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); } } diff --git a/libobs/obs.hpp b/libobs/obs.hpp index 749994e3d..3c7d2b5a6 100644 --- a/libobs/obs.hpp +++ b/libobs/obs.hpp @@ -23,6 +23,7 @@ /* RAII wrappers */ +template class OBSRefAutoRelease; template class OBSRef; using OBSSource = OBSRef; @@ -48,55 +49,73 @@ using OBSWeakService = OBSRef; #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; -using OBSSceneAutoRelease = - OBSRef; + OBSRefAutoRelease; +using OBSSceneAutoRelease = OBSRefAutoRelease; using OBSSceneItemAutoRelease = - OBSRef; -using OBSDataAutoRelease = - OBSRef; + OBSRefAutoRelease; +using OBSDataAutoRelease = OBSRefAutoRelease; using OBSDataArrayAutoRelease = - OBSRef; + OBSRefAutoRelease; using OBSOutputAutoRelease = - OBSRef; + OBSRefAutoRelease; using OBSEncoderAutoRelease = - OBSRef; + OBSRefAutoRelease; using OBSServiceAutoRelease = - OBSRef; + OBSRefAutoRelease; using OBSWeakSourceAutoRelease = - OBSRef; + OBSRefAutoRelease; using OBSWeakOutputAutoRelease = - OBSRef; + OBSRefAutoRelease; using OBSWeakEncoderAutoRelease = - OBSRef; + OBSRefAutoRelease; using OBSWeakServiceAutoRelease = - OBSRef; + OBSRefAutoRelease; -template class OBSRef { +template class OBSRefAutoRelease { +protected: T val; +public: + inline OBSRefAutoRelease() : val(nullptr) {} + inline OBSRefAutoRelease(T val_) : val(val_) {} + OBSRefAutoRelease(const OBSRefAutoRelease &ref) = delete; + inline OBSRefAutoRelease(OBSRefAutoRelease &&ref) : val(ref.val) + { + ref.val = nullptr; + } + + inline ~OBSRefAutoRelease() { release(val); } + + inline operator T() const { return val; } + inline T Get() const { return val; } + + inline bool operator==(T p) const { return val == p; } + inline bool operator!=(T p) const { return val != p; } + + inline OBSRefAutoRelease &operator=(OBSRefAutoRelease &&ref) + { + if (this != &ref) { + release(val); + val = ref.val; + ref.val = nullptr; + } + + return *this; + } + + inline OBSRefAutoRelease &operator=(T new_val) + { + release(val); + val = new_val; + return *this; + } +}; + +template +class OBSRef : public OBSRefAutoRelease { + inline OBSRef &Replace(T valIn) { addref(valIn); @@ -107,35 +126,18 @@ template class OBSRef { struct TakeOwnership { }; - inline OBSRef(T val, TakeOwnership) : val(val) {} + inline OBSRef(T val, TakeOwnership) : OBSRefAutoRelease(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 ~OBSRef() { release(val); } - - inline OBSRef &operator=(T valIn) { return Replace(valIn); } - inline OBSRef &operator=(const OBSRef &ref) { return Replace(ref.val); } - - inline OBSRef &operator=(OBSRef &&ref) + inline OBSRef() : OBSRefAutoRelease(nullptr) {} + inline OBSRef(const OBSRef &ref) : OBSRefAutoRelease(ref.val) { - if (this != &ref) { - release(val); - val = ref.val; - ref.val = nullptr; - } - - return *this; + addref(val); } + inline OBSRef(T val_) : OBSRefAutoRelease(val_) { addref(val); } - inline operator T() const { return val; } - inline T Get() const { return val; } - - inline bool operator==(T p) const { return val == p; } - inline bool operator!=(T p) const { return val != p; } + 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);