Friday, October 16, 2009

DynamicArray causing memory leak in C++ Builder

Recently I came across a memory leak which CodeGuard reported was due to DynamicArray.set_length(...).

Well, DynamicArrays are referenced counted, exactly the same way as AnsiStrings / UnicodeStrings so really there's no way you could've missed free-ing it... ... or is there?

From experience, the first thing that came to mind was that since it's a referenced-counted container - and as with the rest, it's prone to circular-references.

Consider the following code:
#include <vcl.h>
#pragma hdrstop

#include <iostream.h>


struct
TCircularRef
{

DynamicArray<TCircularRef> refs;

~TCircularRef() { cout << "here" << endl; }
};


#pragma argsused
int main(int argc, char* argv[])
{

DynamicArray<TCircularRef> base;
base.set_length(1);

base[0].refs = base;
base.set_length(0);

return 0;
}

With the 'refs' member of DynamicArray<TCircularRef> base referring back to itself (base[0].refs = base), we ended up with a circular-ref. Yes, the cirular-ref in the above example is easy to spot and would probably never occur in the real world as well. In reality though, the circular-refs are much harder to spot and assignments change during run-time, depending on the code branch and/or timing. What's worse is that the reference could be held by an object of which you pass to another library written by someone else...

Notice that the above sample code tries to break the circular-ref such that it would get cleaned-up with the line base.set_length(0)? Alas, that was to no avail as its ref-count prior to set_length would be 2, which leaves us with a ref-count of 1 after that. Can we call set_length(0) again then? No. Why? Because 'base' no longer knows about the object it once held as the first set_length(0) would've set it to point to the new memory location allocated by set_length(0).

Is there a way out? There're a few. But none to my liking. (You could Google for 'circular-reference' if you're interested to find a solution to this but it's not the intention of this article).
As I have a garbage collector library ready to be used in any projects I create with C++ Builder, that was the solution I took. I simply replaced all DynamicArray with gc_array and allocated it with gcnew_array. With that, I no longer had to care about the hairy problem of who owns the object, who's responsible to free it and whether there's a potential circular reference problem in my code. What's more, it's thread-safe, unlike DynamicArray. But that's a topic for another day.

In short, this is my advice: Avoid DynamicArray at all costs!

Wednesday, October 14, 2009

Stepping into a Delphi package while debugging in C++ Builder

Well, you really should debug a Delphi package in Delphi. But once every so often, you'll find yourself using the Delphi package (controls / components) in C++ Builder and in need of tracing into the package while you're debugging your main application. By default, even if you compile the Delphi package in Debug mode, you won't be able to step into the Delphi source codes. These are the settings which will enable that (this guide is for CB2007 but it shouldn't be too different for other versions of C++ Builder):

Go to the project options of the Delphi package.

Select the Compiler view on the left pane.


Set the build config to Debug mode.

Code generation:
  • Optimization = off
  • Stack frames = on
Debugging:
  • Debug information = on
  • Local symbols = on
  • Assertions = on
  • Use debug DCUs = on
Now select the Linker view on the left pane.



Map file:
  • Off
EXE and DLL options:
  • Include TD32 debug info = on
  • Include remote debug symbols = on
Linker output:
  • Generate all C++Builder files (you should already have this selected)

You're done with the settings.

Rebuild your package and your main app and you should now be able to step into the Delphi source.