[fpc-pascal] A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)

Tony Whyman tony.whyman at mccallumwhyman.com
Thu Oct 6 00:07:17 CEST 2016


On 05/10/16 19:19, Marcos Douglas wrote:
> Hi Tony,
>
> On Wed, Oct 5, 2016 at 1:13 PM, Tony Whyman
> <tony.whyman at mccallumwhyman.com> wrote:
>> [...]
>>
>> 7. You are responsible for freeing the object that "provides" the delegated
>> interface.
> But I'm working only using Interfaces. All variables are interfaces type.
> So, I can't free the object myself.
As I understand it, it depends on the variable to which the object is 
first assigned. For example:

TMyClass = class(TInterfacedObject,IUnknown);

var Obj: TMyClass; {Note the var is of type TMyClass}
begin
   Obj := TMyClass.Create;
   try
    ...
   finally
     Obj.Free; {This is OK and necessary}
   end
end;

Alternatively:

var Obj: IUnknown;
begin
   Obj := TMyClass.Create;
   try
    ...
   finally
     Obj.Free; {Not required and will cause an exception when obj goes 
out of scope}
   end
end;

>> Where do we go from here?
>> ======================
>>
>> Provided you understand what is happening then it works - but there is no
>> real documentation and it is really easy to get this wrong.
> I disagree.
> Well, works, but with memleaks... so, I can't have a real program on
> the server with memleaks.
No, if you explicitly free the provider class there will be no memleaks. 
My point is that having to do this is counter-intuitive and  easy to get 
wrong - or to overlook cases where it is necessary.
>
>> For me the consistent approach should be that when you coerce an interface
>> from an object, the reference count of the object that "provides" the
>> delegated interface is always the one that is incremented and the interface
>> remains tied to that object  An object that "is the source of" a delegated
>> interface should always have its lifetime tied to that of the object that
>> "provides" the delegated interface. i.e. it has an implicit reference to the
>> object that is the source of the interface.
> I understood you but I can't help, because I don't know how the
> compiler works to do this 'kind of magic' — I think only Object Pascal
> has delegation in that way, right?
Here I was suggesting a compiler change (bug fix?)
>
> Delegates is a powerful feature. I can write less and compose complexy
> objects using delegation. Really cool.
>
> We need to compare with Delphi?
> I don't have it, but I guess this problem there isn't there.
I never used delegated interfaces in Delphi. In FPC I try to avoid them 
given the problems you get. On the other hand, reference counted com 
interfaces are a great feature and it's a pity delegated interfaces are 
so awkward.
>
> What do you think?
>
> Best regards,
> Marcos Douglas
>
> On Wed, Oct 5, 2016 at 1:13 PM, Tony Whyman
> <tony.whyman at mccallumwhyman.com> wrote:
>> On 05/10/16 16:26, Marcos Douglas wrote:
>>> Tony Whyman had posted on August 10 a problem with the compiler using
>>> Delegates.
>>> He used a workaround to "solve" his problem and the thread died.
>>
>> Marcos,
>>
>> I believe I concluded that this could be a bug or feature. Either way it is
>> a Bear Trap waiting for the unwary programmer and it would be nice if in
>> some way the implementation could be improved. The problem, as I see it is:
>>
>> Basics:
>>
>> 1. Whenever an interface reference is coerced from an interfaced object, the
>> object's reference count is incremented.
>>
>> 2. When the interface is copied that reference count is again incremented.
>>
>> 3. When the interface goes out of scope, the reference count is decremented
>> and when it reaches zero, the object is freed.
>>
>> So far so good, but, when you have a delegated interface:
>>
>> Terminalogy: In the example:
>>
>>      TMyValue = class(TInterfacedObject,IValue);
>>
>>      TMyObject = class (TinterfacedObject,IMyInterface)
>>      ...
>>      property Value: IValue read FValue implements IValue;
>>      end;
>>
>>      Then a TMyValue object "is the source of" the delegated interface.
>>      A TMyObject object "provides" the delegated interface.
>>
>> 4. Whenever an interface reference to a delegated interfaced is coerced from
>> an interfaced object, it is the reference count of the object that "is the
>> source of" the delegated interface that is incremented.
>>
>> 5. When the interface is copied the reference count of the object that "is
>> the source of" the delegated interface is incremented.
>>
>> 6. When the interface goes out of scope, the reference count of the object
>> that "is the source of" the delegated interface is decremented and when it
>> reaches zero, that object is freed.
>>
>> 7. You are responsible for freeing the object that "provides" the delegated
>> interface.
>>
>> To me this is counter-intuitive behaviour and this counter-intuitiveness is
>> compounded by the case where:
>>
>> a. An interfaced object provides only a delegated interface.
>>
>> b. An inherited interface (e.g. IUnknown) is coerced from the object.
>>
>> In this case, the reference count incremented is that of the object that
>> "provides" the delegated interface  and not the object that "is the source
>> of" the delegated interface.
>>
>> Where do we go from here?
>> ======================
>>
>> Provided you understand what is happening then it works - but there is no
>> real documentation and it is really easy to get this wrong.
>>
>> For me the consistent approach should be that when you coerce an interface
>> from an object, the reference count of the object that "provides" the
>> delegated interface is always the one that is incremented and the interface
>> remains tied to that object  An object that "is the source of" a delegated
>> interface should always have its lifetime tied to that of the object that
>> "provides" the delegated interface. i.e. it has an implicit reference to the
>> object that is the source of the interface.
>>
>> Tony Whyman
>> MWA
>>
> _______________________________________________
> fpc-pascal maillist  -  fpc-pascal at lists.freepascal.org
> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
>




More information about the fpc-pascal mailing list