Skip to content

Commit 2ccfbcc

Browse files
authored
Merge pull request #4441 from Dechcaudron/15341
Fixes issue 15341
2 parents 2955c8c + bea5e60 commit 2ccfbcc

File tree

1 file changed

+45
-7
lines changed

1 file changed

+45
-7
lines changed

std/signals.d

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -153,21 +153,31 @@ mixin template Signal(T1...)
153153
*/
154154
final void disconnect(slot_t slot)
155155
{
156-
debug (signal) writefln("Signal.disconnect(slot)");
156+
size_t disconnectedSlots = 0;
157+
size_t instancePreviousSlots = 0;
158+
157159
for (size_t i = 0; i < slots_idx; )
158160
{
159-
if (slots[i] == slot)
160-
{ slots_idx--;
161+
if (slots[i].ptr == slot.ptr &&
162+
++instancePreviousSlots &&
163+
slots[i] == slot)
164+
{
165+
slots_idx--;
166+
disconnectedSlots++;
161167
slots[i] = slots[slots_idx];
162168
slots[slots_idx] = null; // not strictly necessary
163-
164-
Object o = _d_toObject(slot.ptr);
165-
rt_detachDisposeEvent(o, &unhook);
166169
}
167170
else
168171
i++;
169172
}
170-
}
173+
174+
// detach object from dispose event if all its slots have been removed
175+
if (instancePreviousSlots == disconnectedSlots)
176+
{
177+
Object o = _d_toObject(slot.ptr);
178+
rt_detachDisposeEvent(o, &unhook);
179+
}
180+
}
171181

172182
/* **
173183
* Special function called when o is destroyed.
@@ -555,6 +565,34 @@ void linkin() { }
555565
a.value6 = 46;
556566
}
557567

568+
// Triggers bug from issue 15341
569+
unittest
570+
{
571+
class Observer
572+
{
573+
void watch() { }
574+
void watch2() { }
575+
}
576+
577+
class Bar
578+
{
579+
mixin Signal!();
580+
}
581+
582+
auto a = new Bar;
583+
auto o = new Observer;
584+
585+
//Connect both observer methods for the same instance
586+
a.connect(&o.watch);
587+
a.connect(&o.watch2); // not connecting watch2() or disconnecting it manually fixes the issue
588+
589+
//Disconnect a single method of the two
590+
a.disconnect(&o.watch); // NOT disconnecting watch() fixes the issue
591+
592+
destroy(o); // destroying o should automatically call unhook and disconnect the slot for watch2
593+
a.emit(); // should not raise segfault since &o.watch2 is no longer connected
594+
}
595+
558596
version(none) // Disabled because of dmd @@@BUG5028@@@
559597
@system unittest
560598
{

0 commit comments

Comments
 (0)