Board index » cppbuilder » TBaseVariantT destructor leaking BSTR

TBaseVariantT destructor leaking BSTR

This isn't so much asking for help as requesting confirmation that I've
done the right thing ...

---

For some time, I've been trying to determine why an application has been
getting a slow memory leak (according to Task Manager and PView) not
associated with normal memory allocation. he application makes use of a
BCB OCX which in turn wraps a VC++ OCX.
It turns out that the leak is associated with when I'm getting strings
from the wrapped OCX into my OCX - the VC++ OCX SysAllocString()s the
data, and my OCX ::SysFreeString()s the BSTR when it's finished with it.

This is going through the IDispatch interface, so the data is going
across the boundary in Variants.

---

I then determined that the BSTR being emitted by the VC++ OCX wasn't the
same one that my client code was doing its SysFreeString on, and on
tracing into the code in utilcls.h, I discovered that it was going
through the following function:

  // NOTE: Caller must free SysString
  /*TBaseVariantT::*/operator wchar_t*() const
  {
    TBaseVariantT v(*this);
    v.ChangeType(VT_BSTR);
    return ::SysAllocString(V_BSTR(&v));
  }

All well and good - I was freeing up that returned string, but who was
responsible for the original?

Ah, obviously ~TBaseVariantT().

Ah, but there _isn't_ a destructor.

So I added:

  ~TBaseVariantT()
  {
    ::VariantClear(this);
  }

and hey presto, my leak went away.

---

so my question is: did I do something that will break code elsewhere, or
is this safe?

Alan Bellingham
--
al...@episys.com  
For book reviews and much more, see the Association of C and C++ Users
website at http://www.accu.org

 

Re:TBaseVariantT destructor leaking BSTR


I'm not using BCB5, but one case where this solution might be a problem
comes to mind.
When you are writing server code, and your method has an [in] BSTR
parameter. The server code shouldn't free that BSTR, the caller should.
If the code generated by the type library editor substitutes a
TBaseVariant<T> derived class for the BSTR, then the server code will
free the string, and the caller will as well. This situation was a
problem in BCB4.

Paul

Quote
Alan Bellingham wrote:

> This isn't so much asking for help as requesting confirmation that I've
> done the right thing ...

> ---

> For some time, I've been trying to determine why an application has been
> getting a slow memory leak (according to Task Manager and PView) not
> associated with normal memory allocation. he application makes use of a
> BCB OCX which in turn wraps a VC++ OCX.

> It turns out that the leak is associated with when I'm getting strings
> from the wrapped OCX into my OCX - the VC++ OCX SysAllocString()s the
> data, and my OCX ::SysFreeString()s the BSTR when it's finished with it.

> This is going through the IDispatch interface, so the data is going
> across the boundary in Variants.

> ---

> I then determined that the BSTR being emitted by the VC++ OCX wasn't the
> same one that my client code was doing its SysFreeString on, and on
> tracing into the code in utilcls.h, I discovered that it was going
> through the following function:

>   // NOTE: Caller must free SysString
>   /*TBaseVariantT::*/operator wchar_t*() const
>   {
>     TBaseVariantT v(*this);
>     v.ChangeType(VT_BSTR);
>     return ::SysAllocString(V_BSTR(&v));
>   }

> All well and good - I was freeing up that returned string, but who was
> responsible for the original?

> Ah, obviously ~TBaseVariantT().

> Ah, but there _isn't_ a destructor.

> So I added:

>   ~TBaseVariantT()
>   {
>     ::VariantClear(this);
>   }

> and hey presto, my leak went away.

> ---

> so my question is: did I do something that will break code elsewhere, or
> is this safe?

> Alan Bellingham
> --
> al...@episys.com
> For book reviews and much more, see the Association of C and C++ Users
> website at http://www.accu.org

Re:TBaseVariantT destructor leaking BSTR


Quote
Paul Dryden <paul.dry...@m.cc.utah.edu> wrote:
>I'm not using BCB5, but one case where this solution might be a problem
>comes to mind.
>When you are writing server code, and your method has an [in] BSTR
>parameter. The server code shouldn't free that BSTR, the caller should.
>If the code generated by the type library editor substitutes a
>TBaseVariant<T> derived class for the BSTR, then the server code will
>free the string, and the caller will as well. This situation was a
>problem in BCB4.

So ... I either suffer double freeing at one end of my OCX, or a memory
leak at the other?

It looks to me (on a cursory check) that such input variants get copied
as well.

Excuse me while I convert that darned VC++ OCX to have a dual interface
so I don't have to use this stupid IDispatch junk at all.

Alan Bellingham
--
al...@episys.com  
For book reviews and much more, see the Association of C and C++ Users
website at http://www.accu.org

Re:TBaseVariantT destructor leaking BSTR


I think your solution is the correct one. Please, file a bug report with
your findings. As for the Mr. Dryden's question - BCB does suffer in
this area, at least when a server gets an interface as a parameter - a
smart interface pointer is used in the server's methods and this may be
catastrophic. If the same idea ( Variant wrappers ) is used for the
Varaint parameters, then the same problem exists.

.a

Quote
Alan Bellingham wrote:

[snip]

Re:TBaseVariantT destructor leaking BSTR


Quote
Alex Bakaev <al...@jetsuite.com> wrote:
>I think your solution is the correct one. Please, file a bug report with
>your findings.

Done.

It's likely that the guys responsible for the Borland ATL code are most
likely to be able to work out exactly what should be happening here.

Alan Bellingham
--
al...@episys.com  
For book reviews and much more, see the Association of C and C++ Users
website at http://www.accu.org

Re:TBaseVariantT destructor leaking BSTR


Data members will change the layout of the object.

Imagine someone has passed in a VARIANT and the code represents that as a
TVariantInParam --attempts to access the added data members will AV in the
best case.

Chris

Quote
"Alan Bellingham" <al...@episys.com> wrote in message

news:j8hvosgclerlll3a71idr49o5plu4aathj@4ax.com...
Quote
> This isn't so much asking for help as requesting confirmation that I've
> done the right thing ...

> ---

> For some time, I've been trying to determine why an application has been
> getting a slow memory leak (according to Task Manager and PView) not
> associated with normal memory allocation. he application makes use of a
> BCB OCX which in turn wraps a VC++ OCX.

> It turns out that the leak is associated with when I'm getting strings
> from the wrapped OCX into my OCX - the VC++ OCX SysAllocString()s the
> data, and my OCX ::SysFreeString()s the BSTR when it's finished with it.

> This is going through the IDispatch interface, so the data is going
> across the boundary in Variants.

> ---

> I then determined that the BSTR being emitted by the VC++ OCX wasn't the
> same one that my client code was doing its SysFreeString on, and on
> tracing into the code in utilcls.h, I discovered that it was going
> through the following function:

>   // NOTE: Caller must free SysString
>   /*TBaseVariantT::*/operator wchar_t*() const
>   {
>     TBaseVariantT v(*this);
>     v.ChangeType(VT_BSTR);
>     return ::SysAllocString(V_BSTR(&v));
>   }

> All well and good - I was freeing up that returned string, but who was
> responsible for the original?

> Ah, obviously ~TBaseVariantT().

> Ah, but there _isn't_ a destructor.

> So I added:

>   ~TBaseVariantT()
>   {
>     ::VariantClear(this);
>   }

> and hey presto, my leak went away.

> ---

> so my question is: did I do something that will break code elsewhere, or
> is this safe?

> Alan Bellingham
> --
> al...@episys.com
> For book reviews and much more, see the Association of C and C++ Users
> website at http://www.accu.org

Other Threads