obs/source-tracker: Don't leak pointers to sources

This commit is contained in:
Michael Fabian 'Xaymar' Dirks 2020-07-26 18:38:49 +02:00 committed by Michael Fabian Dirks
parent aad7f64800
commit d410b4296f
2 changed files with 44 additions and 37 deletions

View file

@ -19,6 +19,7 @@
#include "obs-source-tracker.hpp" #include "obs-source-tracker.hpp"
#include <stdexcept> #include <stdexcept>
#include "obs/obs-tools.hpp"
#include "plugin.hpp" #include "plugin.hpp"
static std::shared_ptr<obs::source_tracker> source_tracker_instance; static std::shared_ptr<obs::source_tracker> source_tracker_instance;
@ -35,17 +36,19 @@ try {
} }
const char* name = obs_source_get_name(target); const char* name = obs_source_get_name(target);
if (!name) { if (!name) { // Do not track unnamed sources.
// Do not track unnamed sources.
return; return;
} }
obs_weak_source_t* weak = obs_source_get_weak_source(target); obs_weak_source_t* weak = obs_source_get_weak_source(target);
if (!weak) { if (!weak) { // This source has already been deleted, do not track.
return; return;
} }
self->_source_map.insert({std::string(name), weak}); {
std::unique_lock<std::mutex> ul(self->_lock);
self->_sources.insert({std::string(name), {weak, obs::obs_weak_source_deleter}});
}
} catch (...) { } catch (...) {
LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
} }
@ -62,18 +65,18 @@ try {
} }
const char* name = obs_source_get_name(target); const char* name = obs_source_get_name(target);
if (!name) { if (!name) { // Not tracking unnamed sources.
// Not tracking unnamed sources.
return; return;
} }
auto found = self->_source_map.find(std::string(name)); {
if (found == self->_source_map.end()) { std::unique_lock<std::mutex> ul(self->_lock);
return; auto found = self->_sources.find(std::string(name));
if (found == self->_sources.end()) {
return;
}
self->_sources.erase(found);
} }
obs_weak_source_release(found->second);
self->_source_map.erase(found);
} catch (...) { } catch (...) {
LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
} }
@ -94,20 +97,23 @@ try {
return; return;
} }
auto found = self->_source_map.find(std::string(prev_name)); {
if (found == self->_source_map.end()) { std::unique_lock<std::mutex> ul(self->_lock);
// Untracked source, insert. auto found = self->_sources.find(std::string(prev_name));
obs_weak_source_t* weak = obs_source_get_weak_source(target); if (found == self->_sources.end()) {
if (!weak) { // Untracked source, insert.
obs_weak_source_t* weak = obs_source_get_weak_source(target);
if (!weak) {
return;
}
self->_sources.insert({new_name, {weak, obs::obs_weak_source_deleter}});
return; return;
} }
self->_source_map.insert({new_name, weak});
return;
}
// Insert at new key, remove old pair. // Insert at new key, remove old pair.
self->_source_map.insert({new_name, found->second}); self->_sources.insert({new_name, found->second});
self->_source_map.erase(found); self->_sources.erase(found);
}
} catch (...) { } catch (...) {
LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__); LOG_ERROR("Unexpected exception in function '%s'.", __FUNCTION_NAME__);
} }
@ -144,37 +150,36 @@ obs::source_tracker::~source_tracker()
signal_handler_disconnect(osi, "source_rename", &source_rename_handler, this); signal_handler_disconnect(osi, "source_rename", &source_rename_handler, this);
} }
for (auto kv : this->_source_map) { this->_sources.clear();
obs_weak_source_release(kv.second);
}
this->_source_map.clear();
} }
void obs::source_tracker::enumerate(enumerate_cb_t ecb, filter_cb_t fcb) void obs::source_tracker::enumerate(enumerate_cb_t ecb, filter_cb_t fcb)
{ {
// Need func-local copy, otherwise we risk corruption if a new source is created or destroyed. // Need func-local copy, otherwise we risk corruption if a new source is created or destroyed.
auto source_map_copy = this->_source_map; decltype(_sources) _clone;
for (auto kv : this->_source_map) { {
obs_source_t* source = obs_weak_source_get_source(kv.second); std::unique_lock<std::mutex> ul(_lock);
_clone = _sources;
}
for (auto kv : _clone) {
auto source =
std::shared_ptr<obs_source_t>(obs_weak_source_get_source(kv.second.get()), obs::obs_source_deleter);
if (!source) { if (!source) {
continue; continue;
} }
if (fcb) { if (fcb) {
if (fcb(kv.first, source)) { if (fcb(kv.first, source.get())) {
obs_source_release(source);
continue; continue;
} }
} }
if (ecb) { if (ecb) {
if (ecb(kv.first, source)) { if (ecb(kv.first, source.get())) {
obs_source_release(source);
break; break;
} }
} }
obs_source_release(source);
} }
} }

View file

@ -21,10 +21,12 @@
#include "common.hpp" #include "common.hpp"
#include <functional> #include <functional>
#include <map> #include <map>
#include <mutex>
namespace obs { namespace obs {
class source_tracker { class source_tracker {
std::map<std::string, obs_weak_source_t*> _source_map; std::map<std::string, std::shared_ptr<obs_weak_source_t>> _sources;
std::mutex _lock;
static void source_create_handler(void* ptr, calldata_t* data) noexcept; static void source_create_handler(void* ptr, calldata_t* data) noexcept;
static void source_destroy_handler(void* ptr, calldata_t* data) noexcept; static void source_destroy_handler(void* ptr, calldata_t* data) noexcept;