Skip to content

Commit 404a79c

Browse files
author
Kjell Ahlstedt
committed
signal_impl: Use std::weak_ptr<signal_impl> in connected slots
A signal_impl object shall not store std::shared_ptr to itself via connected slots. It results in memory leaks. Use std::weak_ptr in the self_and_iter struct. Bug 775871
1 parent abf29c4 commit 404a79c

File tree

1 file changed

+18
-6
lines changed

1 file changed

+18
-6
lines changed

sigc++/signal_base.cc

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ namespace internal
2828
// when the slot is disconnected. Bug 167714.
2929
struct self_and_iter : public notifiable
3030
{
31-
const std::shared_ptr<signal_impl> self_;
31+
const std::weak_ptr<signal_impl> self_;
3232
const signal_impl::iterator_type iter_;
3333

34-
self_and_iter(const std::shared_ptr<signal_impl>& self, const signal_impl::iterator_type& iter) : self_(self), iter_(iter) {}
34+
self_and_iter(const std::weak_ptr<signal_impl>& self, const signal_impl::iterator_type& iter)
35+
: self_(self), iter_(iter) {}
3536
};
3637

3738
signal_impl::signal_impl() : exec_count_(0), deferred_(false)
@@ -64,6 +65,9 @@ signal_impl::clear()
6465
{
6566
// Don't let signal_impl::notify() erase the slots. It would invalidate the
6667
// iterator in the following loop.
68+
// Don't call shared_from_this() here. clear() is called from the destructor.
69+
// When the destructor is executing, shared_ptr's use_count has reached 0,
70+
// and it's no longer possible to get a shared_ptr to this.
6771
const bool saved_deferred = deferred_;
6872
signal_impl_exec_holder exec(this);
6973

@@ -179,22 +183,30 @@ void
179183
signal_impl::notify_self_and_iter_of_invalidated_slot(notifiable* d)
180184
{
181185
std::unique_ptr<self_and_iter> si(static_cast<self_and_iter*>(d));
186+
auto self = si->self_.lock();
187+
if (!self)
188+
{
189+
// The signal_impl object is being deleted. The use_count has reached 0.
190+
// Nothing to do here. exec_count_ > 0 and clear() will restore deferred_.
191+
return;
192+
}
182193

183-
if (si->self_->exec_count_ == 0)
194+
if (self->exec_count_ == 0)
184195
{
185196
// The deletion of a slot may cause the deletion of a signal_base,
186197
// a decrementation of si->self_->ref_count_, and the deletion of si->self_.
187198
// In that case, the deletion of si->self_ is deferred to ~signal_impl_holder().
188-
signal_impl_holder exec(si->self_);
189-
si->self_->slots_.erase(si->iter_);
199+
// https://bugzilla.gnome.org/show_bug.cgi?id=564005#c24
200+
signal_impl_holder exec(self);
201+
self->slots_.erase(si->iter_);
190202
}
191203
else
192204
{
193205
// This is occurring during signal emission or slot erasure.
194206
// => sweep() will be called from ~signal_impl_holder() after signal emission.
195207
// This is safer because we don't have to care about our
196208
// iterators in emit(), clear(), and erase().
197-
si->self_->deferred_ = true;
209+
self->deferred_ = true;
198210
}
199211
}
200212

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy