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.
This commit is contained in:
jp9000 2021-12-30 21:10:50 -08:00
parent 7f2dfd53a9
commit 52cc1d533e
3 changed files with 71 additions and 75 deletions

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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,55 +49,73 @@ 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;
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<typename T, void addref(T), void release(T)>
class OBSRef : public OBSRefAutoRelease<T, release> {
inline OBSRef &Replace(T valIn)
{
addref(valIn);
@ -107,35 +126,18 @@ template<typename T, void addref(T), void release(T)> 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);