Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2012-03

FreeNotification and opRemove

10 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Martin

I found a behaviour, of which I am not sure, if it is intended. Maybe someone can comment

My understanding is that FreeNotification are *always* set up bi-directional ?
At least

   C1.FreeNotification(C2);

will set up for C1 to inform C2, and for C2 to inform C1 whichever is destroyed first to call the other

And

   C1.RemoveFreeNotification(C2);

will remove both.

   C2.Notification(C1, opRemove);

breaks that.
It will lead to C2 removing C1 from it's list of FreeNotifies, but C1 will keep C2 on the list.
If then C2 is destroyed, it does not inform C1 about that, and C1 ends up with a dangling pointer to the no longer existing C2. Destroying C2 will then crash.

In the example below (compile with -gt) opRemove is caused by Owner.RemoveComponent.
It crashes on the last line.

I was briefly wondering, if in case C1 did call
"C1.FreeNotification(c2);", then C1 should overwrite Notification and check for the opRemove and call "RemoveFreeNotification" itself? But if that was the case, then why does TComponent interfer with the FreeNotify list at all?

program Project1;
{$mode objfpc}{$H+}
uses  Classes;
var
   Owner, C1, C2: TComponent;
begin
   Owner := TComponent.Create(nil);
   C1 := TComponent.Create(Owner);
   C2 := TComponent.Create(Owner);
   C1.FreeNotification(c2);
   Owner.RemoveComponent(C1); // C2 Gets on opRemove
   C2.Free;
   C1.Free; // crash
   ReadLn;
end.

Reply by email

Martin
to Martin

Further more:

the program below, does not crash in delphi (turbo delphi)

Martin wrote 58 lines
I found a behaviour, of which I am not sure, if it is intended. Maybe someone can comment My understanding is that FreeNotification are *always* set up bi-directional ? At least C1.FreeNotification(C2); will set up for C1 to inform C2, and for C2 to inform C1 whichever is destroyed first to call the other And C1.RemoveFreeNotification(C2); will remove both. C2.Notification(C1, opRemove); breaks that. It will lead to C2 removing C1 from it's list of FreeNotifies, but C1 will keep C2 on the list. If then C2 is destroyed, it does not inform C1 about that, and C1 ends up with a dangling pointer to the no longer existing C2. Destroying C2 will then crash. In the example below (compile with -gt) opRemove is caused by Owner.RemoveComponent. It crashes on the last line. I was briefly wondering, if in case C1 did call "C1.FreeNotification(c2);", then C1 should overwrite Notification and check for the opRemove and call "RemoveFreeNotification" itself? But if that was the case, then why does TComponent interfer with the FreeNotify list at all? program Project1; {$mode objfpc}{$H+} uses Classes; var Owner, C1, C2: TComponent; begin Owner := TComponent.Create(nil); C1 := TComponent.Create(Owner); C2 := TComponent.Create(Owner); C1.FreeNotification(c2); Owner.RemoveComponent(C1); // C2 Gets on opRemove C2.Free; C1.Free; // crash ReadLn; end. _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply by email

Unknown author
to Martin
Martin wrote
Further more: the program below, does not crash in delphi (turbo delphi)
I also noticed. I suspect the problem is the owner;
If it gets a free notification, it should pass it to all the children.

Michael.

Show quoted text 65 lines
On 08/03/2012 09:56, Martin wrote: > I found a behaviour, of which I am not sure, if it is intended. Maybe > someone can comment > > My understanding is that FreeNotification are *always* set up > bi-directional ? > At least > C1.FreeNotification(C2); > will set up for C1 to inform C2, and for C2 to inform C1 whichever is > destroyed first to call the other > > And > C1.RemoveFreeNotification(C2); > will remove both. > > > C2.Notification(C1, opRemove); > breaks that. > It will lead to C2 removing C1 from it's list of FreeNotifies, but C1 will > keep C2 on the list. > If then C2 is destroyed, it does not inform C1 about that, and C1 ends up > with a dangling pointer to the no longer existing C2. > Destroying C2 will then crash. > > In the example below (compile with -gt) opRemove is caused by > Owner.RemoveComponent. > It crashes on the last line. > > I was briefly wondering, if in case C1 did call "C1.FreeNotification(c2);", > then C1 should overwrite Notification and check for the opRemove and call > "RemoveFreeNotification" itself? > But if that was the case, then why does TComponent interfer with the > FreeNotify list at all? > > > > > program Project1; > {$mode objfpc}{$H+} > uses Classes; > var > Owner, C1, C2: TComponent; > begin > Owner := TComponent.Create(nil); > C1 := TComponent.Create(Owner); > C2 := TComponent.Create(Owner); > > C1.FreeNotification(c2); > > Owner.RemoveComponent(C1); // C2 Gets on opRemove > C2.Free; > C1.Free; // crash > > ReadLn; > end. > > _______________________________________________ > fpc-devel maillist - > http://lists.freepascal.org/mailman/listinfo/fpc-devel _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply by email

Martin
to Unknown author
Show quoted text 10 lines
On Thu, 8 Mar 2012, Martin wrote: > Further more: > > the program below, does not crash in delphi (turbo delphi) I also noticed. I suspect the problem is the owner; If it gets a free notification, it should pass it to all the children.

I don't think that is it.

In the example below C1 is no longer owned, when C2 is destroyed, so the problem would persist.

The problem is that opRemove breaks the bi-directional bounding of FreeNotifications.

When C2 gets the opREmove, it must mot just remove it's own entry, but also remove the entry C1 has

Show quoted text 22 lines
> > On 08/03/2012 09:56, Martin wrote: >> >> program Project1; >> {$mode objfpc}{$H+} >> uses Classes; >> var >> Owner, C1, C2: TComponent; >> begin >> Owner := TComponent.Create(nil); >> C1 := TComponent.Create(Owner); >> C2 := TComponent.Create(Owner); >> >> C1.FreeNotification(c2); >> >> Owner.RemoveComponent(C1); // C2 Gets on opRemove >> C2.Free; >> C1.Free; // crash >> >> ReadLn; >> end. >>

Reply by email

Martin
to Martin
Martin wrote 23 lines
On 08/03/2012 13:08, wrote: > > > On Thu, 8 Mar 2012, Martin wrote: > >> Further more: >> >> the program below, does not crash in delphi (turbo delphi) > > I also noticed. I suspect the problem is the owner; If it gets a free > notification, it should pass it to all the children. I don't think that is it. In the example below C1 is no longer owned, when C2 is destroyed, so the problem would persist. The problem is that opRemove breaks the bi-directional bounding of FreeNotifications. When C2 gets the opREmove, it must mot just remove it's own entry, but also remove the entry C1 has

In the following code, I thing is the problem:

Procedure TComponent.Notification(AComponent: TComponent;
   Operation: TOperation);
Var Runner : Longint;
begin
   If (Operation=opRemove) and Assigned(FFreeNotifies) then
     begin
     FFreeNotifies.Remove(AComponent);
...

It removes only one of the 2 notify entries.

If opRemove is to remove FreeNotifications, then it mus remove them bi-directional, same as RemoveFreeNotification does

Show quoted text 27 lines
>> >> On 08/03/2012 09:56, Martin wrote: >>> >>> program Project1; >>> {$mode objfpc}{$H+} >>> uses Classes; >>> var >>> Owner, C1, C2: TComponent; >>> begin >>> Owner := TComponent.Create(nil); >>> C1 := TComponent.Create(Owner); >>> C2 := TComponent.Create(Owner); >>> >>> C1.FreeNotification(c2); >>> >>> Owner.RemoveComponent(C1); // C2 Gets on opRemove >>> C2.Free; >>> C1.Free; // crash >>> >>> ReadLn; >>> end. >>> _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply by email

Martin
to Martin
Martin wrote 18 lines
In the following code, I thing is the problem: Procedure TComponent.Notification(AComponent: TComponent; Operation: TOperation); Var Runner : Longint; begin If (Operation=opRemove) and Assigned(FFreeNotifies) then begin FFreeNotifies.Remove(AComponent); ... It removes only one of the 2 notify entries. If opRemove is to remove FreeNotifications, then it mus remove them bi-directional, same as RemoveFreeNotification does

That is: I have not checked if Delphi removes the I assume, if it does, it does both...

Reply by email

Torsten Bonde Christiansen
to Martin
Martin wrote 22 lines
On 08/03/2012 13:44, Martin wrote: > > > In the following code, I thing is the problem: > > Procedure TComponent.Notification(AComponent: TComponent; > Operation: TOperation); > Var Runner : Longint; > begin > If (Operation=opRemove) and Assigned(FFreeNotifies) then > begin > FFreeNotifies.Remove(AComponent); > ... > > It removes only one of the 2 notify entries. > > If opRemove is to remove FreeNotifications, then it mus remove them > bi-directional, same as RemoveFreeNotification does > That is: I have not checked if Delphi removes the FreeNotify at all. But I assume, if it does, it does both...

I can confirm the D7 does remove both - it calls:

*AComponent.RemoveNotification(Self);*

Regards,
Torsten Bonde Christiansen.

Reply by email

Hans-Peter Diettrich
to Martin: I don't think that is it. In the example below C1 is no longer owned, when C2 is…
When C2 gets the opREmove, it must mot just remove it's own entry, but also remove the entry C1 has

The meaning of opRemove is unclear. IMO it doesn't make sense in the example code, because the owner of a component can change many times, without meaning that the component is being destroyed. In such a scenario the receiver can not know whether (when) the notification should be removed, the notification itself is quite useless.

>>> Owner.RemoveComponent(C1); // C2 Gets on opRemove

DoDi

Reply by email

Martin
to Martin: I don't think that is it. In the example below C1 is no longer owned, when C2 is…
Martin wrote 11 lines
On 08/03/2012 13:08, wrote: > > > On Thu, 8 Mar 2012, Martin wrote: > >> Further more: >> >> the program below, does not crash in delphi (turbo delphi) > > I also noticed. I suspect the problem is the owner; If it gets a free > notification, it should pass it to all the children.

I initially posted this to see if the behaviour would be considered a bug (rather than wrong user code)

Seeing that Delphi does not crash, I assume I can consider it a bug, and report?

Show quoted text 12 lines
I don't think that is it. In the example below C1 is no longer owned, when C2 is destroyed, so the problem would persist. The problem is that opRemove breaks the bi-directional bounding of FreeNotifications. When C2 gets the opREmove, it must mot just remove it's own entry, but also remove the entry C1 has

Reply by email

Michael Van Canneyt
to Martin
Martin wrote 17 lines
On 08/03/2012 13:34, Martin wrote: > On 08/03/2012 13:08, wrote: >> >> >> On Thu, 8 Mar 2012, Martin wrote: >> >>> Further more: >>> >>> the program below, does not crash in delphi (turbo delphi) >> >> I also noticed. I suspect the problem is the owner; If it gets a free >> notification, it should pass it to all the children. I initially posted this to see if the behaviour would be considered a bug (rather than wrong user code) Seeing that Delphi does not crash, I assume I can consider it a bug, and report?

Yes, please.

Michael.

Reply by email