Advertisement

Return a string causes mem-leak?

Started by October 18, 2005 04:33 PM
3 comments, last by mandrav 19 years, 1 month ago
Here's the problem. I have this function:

std::string StringConverters::FromFloat(float v); // StringConverters is a namespace
and I bind it with:

engine->RegisterGlobalFunction("string StringFromFloat(float)", asFUNCTION(StringConverters::FromFloat), asCALL_CDECL);
It binds and runs fine, *but* it's causing memory leaks. Each time it's called from script, the returned string is allocated but never freed (I have my own leak-tracker). If I change the above to use references, i.e.

std::string& StringConverters::FromFloat(float v);
engine->RegisterGlobalFunction("string& StringFromFloat(float)", asFUNCTION(StringConverters::FromFloat), asCALL_CDECL);
I have no memory leaks... Is something I 'm doing wrong? Yiannis.
There shouldn't be any problem with returning the string by value nor by reference.

If there truly is a memory leak it is likely because you've registered the string type incorrectly. Can you show me how you register the string type?

It could also be your leak tester that doesn't detect the allocation/deallocation correctly. The thing is that when AngelScript calls a system function that returns an object by value, it first allocates memory for the returned object with malloc() (unless you've changed that with either SetCommonObjectMemoryFunctions() or asBEHAVE_ALLOC). Your function then initializes this memory with the object constructor. And finally the memory is deleted with either free() or a call to the object's Release() (in case it supports object handles).

This shouldn't be a problem for a basic leak tester though, so my guess is that the string type is registered incorrectly.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement
Here's the relevant part of my init function:
    LOG_INFO << "Initialising scripting...\n";    m_pEngine = asCreateScriptEngine(ANGELSCRIPT_VERSION);    if (!m_pEngine)        THROW("Can't create scripting engine!");    m_pEngine->SetCommonMessageStream(&asOut);    m_pEngine->SetCommonObjectMemoryFunctions(localAllocMem, localFreeMem);    // register string type    LOG_DEBUG << " + Registering 'string' type\n";    RegisterScriptString(m_pEngine);

You 'll see two things here:
1) I 'm using scriptstring.cpp/.h from AngelScript distribution. If there's something wrong with its registration, it's not my fault ;)
2) I use custom allocator functions "localAllocMem" and "localFreeMem" which just allocate memory using my memory manager so that it can track mem leaks. Here's their implementation, for the sake of completeness:
void* localAllocMem(asUINT size){    return MemAlloc(size);}void localFreeMem(void* mem){    MemFree(mem);}

All the mem leaks I 'm talking about, come from localAllocMem. localFreeMem is never called to free the respective memory allocated before by localAllocMem. This only happens in the case I 'm posting about, the string as a return type. For all other cases, it works fine i.e. deallocations match allocations.
Finally, here's the bound function that returns the string type:

std::string StringConverters::FromFloat(float v){    std::ostringstream ss;    ss << std::setprecision(4) << v;    return ss.str();}


If you still believe that something's wrong with my code, I will try to create a minimal test-case for you to try out.
But, unless there's something wrong with the string type registration, I don't believe there's something wrong with my code because it works fine in all other cases. AngelScript is the only scripting language I could pick up and embed so quickly and painlessly :)
Trying to put the bug on my side, are you? [wink]

The problem is that you're returning a std::string, whereas you've told AngelScript that you're returning an asCScriptString (with RegisterScriptString()). Everything works ok, because of the layout of asCScriptString, except that the reference counter is never initialized. This is why it is never freed.

I suggest you change your FromFloat() function to return a handle to a script string, and change the implementation accordingly:

asCScriptString *StringConverters::FromFloat(float v){    std::ostringstream ss;    ss << std::setprecision(4) << v;    return new asCScriptString(ss.str());}


Maybe it would be possible to return the asCScriptString by value. However, since the type uses reference counting to do memory management, I do not recommend. It would likely not work in all situations, also it might not be completely portable.

Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Quote: Original post by WitchLord
Trying to put the bug on my side, are you? [wink]


I 'd never do that!
I 'm just confident for my part of the code ;)

Quote: Original post by WitchLord
The problem is that you're returning a std::string, whereas you've told AngelScript that you're returning an asCScriptString (with RegisterScriptString()). Everything works ok, because of the layout of asCScriptString, except that the reference counter is never initialized. This is why it is never freed.


See? I didn't know I had to wrap these functions for AngelScript, because usually I return a const reference to std::string. This is the only place that I return a std::string by value. No wonder it didn't appear up till now (I just created the file in question) :)

Thanks a bunch for the quick help :D

Yiannis.

This topic is closed to new replies.

Advertisement