Game Development Community

Infinite recursion while reporting a page allocation

by Robert Rose · in Torque Game Engine Advanced · 12/02/2007 (7:44 pm) · 1 replies

I'm hitting this in my TGEA-based game, it's reproable everytime:

PlatformMemory: allocating new page, total bytes allocated so far: 32162116 (total bytes in all pages=41943040)
PlatformMemory: allocating new page, total bytes allocated so far: 32162128 (total bytes in all pages=50331648)
PlatformMemory: allocating new page, total bytes allocated so far: 32162140 (total bytes in all pages=58720256)
PlatformMemory: allocating new page, total bytes allocated so far: 32162152 (total bytes in all pages=67108864)
...

This keeps going until it crashes with a stack overflow.

If I set a breakpoint in allocMemPage I can catch the problem. It's doing an infinite recursion trying to report to the console the page allocation. Since Con::_printf() does an allocation itself, it gets stuck in a loop reporting its own allocation, never _actually_ performing the allocation. Silly, silly! There's even a note to this effect at console.cpp line 555:

// This prevents infinite recursion if the console itself needs to
// re-allocate memory to accommodate the new console log entry, and
// LOG_PAGE_ALLOCS is defined. It is kind of a dirty hack, but the
// uses for LOG_PAGE_ALLOCS are limited, and it is not worth writing
// a lot of special case code to support this situation. -patw
const bool save = Con::active;
Con::active = false;
consoleLog.push_back(entry);
Con::active = save;

Yet nothing that I can find actually checks the Con::active value.

#1
12/02/2007 (7:50 pm)
The fix is simple enough:

#ifndef TORQUE_SHIPPING // this is equivalent to a memory leak, turn it off in ship build

// This prevents infinite recursion if the console itself needs to
// re-allocate memory to accommodate the new console log entry, and
// LOG_PAGE_ALLOCS is defined. It is kind of a dirty hack, but the
// uses for LOG_PAGE_ALLOCS are limited, and it is not worth writing
// a lot of special case code to support this situation. -patw
const bool save = Con::active;
Con::active = false;

entry.mString = (const char *)consoleLogChunker.alloc(dStrlen(pos) + 1);
dStrcpy(const_cast(entry.mString), pos);

consoleLog.push_back(entry);
Con::active = save;

#endif