Hi!
This will be a longish post :-)
I've found 2 very puzzling memory leaks. The first one seems to have something to do with strings and temporary objects. Here's my code:
// class code
struct GridFont {
GridFont()
: strName("")
, dSize(0.0)
, bIsBold(false)
, bIsItalic(false)
{
}
GridFont(const string& name, double size, bool isBold, bool isItalic)
: strName(name)
, dSize(size)
, bIsBold(isBold)
, bIsItalic(isItalic)
{
}
void Constructor() {
new(this) GridFont;
}
void Constructor(const string& name, double size, bool isBold, bool isItalic) {
new(this) GridFont(name, size, isBold, isItalic);
}
GridFont& operator=(const GridFont& other) {
strName = other.strName;
dSize = other.dSize;
bIsBold = other.bIsBold;
bIsItalic = other.bIsItalic;
return *this;
}
string strName;
double dSize;
bool bIsBold;
bool bIsItalic;
};
// registration code
r = pEngine->RegisterObjectType("GridFont", sizeof(GridFont), asOBJ_CLASS_CA); assert(r >=0);
r = pEngine->RegisterObjectBehaviour("GridFont", asBEHAVE_CONSTRUCT, "void Constructor()", asMETHODPR(GridFont, Constructor, (), void), asCALL_THISCALL); assert(r >= 0);
r = pEngine->RegisterObjectBehaviour("GridFont", asBEHAVE_CONSTRUCT, "void Constructor(const string∈, double, bool, bool)", asMETHODPR(GridFont, Constructor, (const string&, double, bool, bool), void), asCALL_THISCALL); assert(r >= 0);
r = pEngine->RegisterObjectBehaviour("GridFont", asBEHAVE_ASSIGNMENT, "GridFont& f(const GridFont∈)", asMETHOD(GridFont, operator=), asCALL_THISCALL); assert(r >= 0);
r = pEngine->RegisterObjectProperty("GridFont", "string strName", offsetof(GridFont, strName)); assert(r >=0);
r = pEngine->RegisterObjectProperty("GridFont", "double dSize", offsetof(GridFont, dSize)); assert(r >=0);
r = pEngine->RegisterObjectProperty("GridFont", "bool bIsBold", offsetof(GridFont, bIsBold)); assert(r >=0);
r = pEngine->RegisterObjectProperty("GridFont", "bool bIsItalic", offsetof(GridFont, bIsItalic)); assert(r >=0);
// script code
void main() {
for (int i = 0;; ++i) {
GridFont gridFont2("4", 10.0, true, false);
}
I'm using stdstring wrapper (from AS 2.0)
If I don't use the for loop, VC6 will report a memory leak for "4". If I use the infinite for loop, task manager will confirm the leak.
Interestingly, VS.NET 2003 will report a leak for identical code only if the string is 16 characters or longer. For shorter strings, no leak is detected (and Task Manager confirms it)
I found the other memory leak when I switched to using the new scriptstring wrapper. My main project is linked with MT DLL CRT, and I use AS DLL. While I was using stdstring wrapper, I could link AS DLL with MT CRT (static), since no memory buffer allocated in AS DLL was ever deleted in my code. But, since scriptstring deletes buffers allocated by AS DLL, I had to link AS DLL with MT DLL CRT library (as it should have been in the first place, but I forgot to check :-)
Now, when I run a script (can be an emtpy 'void foo()' function), VS6 reports 2 memory leaks, and VS.NET 2003 reports 3. Here's a sample:
// VS6
{4953} normal block at 0x00CDBEA0, 4 bytes long.
Data: <8 7 > 38 8A 37 00
{4952} normal block at 0x00CDBE48, 24 bytes long.
Data: < > A0 BE CD 00 00 00 00 00 01 00 00 00 00 00 00 00
// VS.NET 2003
{5175} normal block at 0x0131BBE8, 4 bytes long.
Data: < 1 > 18 BD 31 01
{5174} normal block at 0x0131BB90, 24 bytes long.
Data: < > 00 00 00 00 00 00 00 00 00 00 00 00 00 CD CD CD
{5173} normal block at 0x0132AB10, 24 bytes long.
Data: < 1 > E8 BB 31 01 00 00 00 00 01 00 00 00 00 00 00 00
These are one-time leaks. I can repeatedly discard modules from the engine, build and execute scripts, there will only be these 2/3 leaks reported. I release the context and engine pointers on exit. It seems that the leak originates in Build function (I commented out calls in reverse order until memory leak disappeared: execute, setargument, prepare, build :)
If I use strings as in the previous sample, those are reported, too.
I'll try to make a minimal example tomorrow to see if I can repeat it.