memory fun

Region.cpp/h: fix tile cache memory leaks by replacing raw malloc/free with RAII-compliant std::unique_ptr

Tesselator.cpp/h: fix thread-exit leaks by swapping unmanaged TlsAlloc for auto-cleaning C++17 thread_local std::unique_ptr (constructor now public)

LevelRenderer.cpp: fix heap corruption and array element leaks by changing 'delete' to 'delete[]' for chunk buffers
This commit is contained in:
Racc 2026-03-11 19:48:09 +00:00
parent 354c1d1738
commit 9aad2c8515
5 changed files with 26 additions and 38 deletions

View file

@ -367,19 +367,17 @@ void LevelRenderer::setLevel(int playerIndex, MultiPlayerLevel *level)
else else
{ {
// printf("NULLing player %d, chunks @ 0x%x\n",playerIndex,chunks[playerIndex]); // printf("NULLing player %d, chunks @ 0x%x\n",playerIndex,chunks[playerIndex]);
if( chunks[playerIndex].data != nullptr ) if (chunks[playerIndex].data != nullptr)
{ {
for (unsigned int i = 0; i < chunks[playerIndex].length; i++) for (unsigned int i = 0; i < chunks[playerIndex].length; i++)
{ {
chunks[playerIndex][i].chunk->_delete(); chunks[playerIndex][i].chunk->_delete();
delete chunks[playerIndex][i].chunk; delete chunks[playerIndex][i].chunk;
} }
delete chunks[playerIndex].data; delete[] chunks[playerIndex].data;
chunks[playerIndex].data = nullptr; chunks[playerIndex].data = nullptr;
chunks[playerIndex].length = 0; chunks[playerIndex].length = 0;
// delete sortedChunks[playerIndex]; // 4J - removed - not sorting our chunks anymore }
// sortedChunks[playerIndex] = nullptr; // 4J - removed - not sorting our chunks anymore
}
// 4J Stu - If we do this for splitscreen players leaving, then all the tile entities in the world dissappear // 4J Stu - If we do this for splitscreen players leaving, then all the tile entities in the world dissappear
// We should only do this when actually exiting the game, so only when the primary player sets there level to nullptr // We should only do this when actually exiting the game, so only when the primary player sets there level to nullptr
@ -451,7 +449,7 @@ void LevelRenderer::allChanged(int playerIndex)
chunks[playerIndex][i].chunk->_delete(); chunks[playerIndex][i].chunk->_delete();
delete chunks[playerIndex][i].chunk; delete chunks[playerIndex][i].chunk;
} }
delete chunks[playerIndex].data; delete[] chunks[playerIndex].data;
// delete sortedChunks[playerIndex]; // 4J - removed - not sorting our chunks anymore // delete sortedChunks[playerIndex]; // 4J - removed - not sorting our chunks anymore
} }

View file

@ -24,17 +24,16 @@ int normal;
*/ */
DWORD Tesselator::tlsIdx = TlsAlloc(); static thread_local std::unique_ptr<Tesselator> tlsInstance;
Tesselator *Tesselator::getInstance() Tesselator *Tesselator::getInstance()
{ {
return static_cast<Tesselator *>(TlsGetValue(tlsIdx)); return tlsInstance.get();
} }
void Tesselator::CreateNewThreadStorage(int bytes) void Tesselator::CreateNewThreadStorage(int bytes)
{ {
Tesselator *instance = new Tesselator(bytes/4); tlsInstance = std::make_unique<Tesselator>(bytes / 4);
TlsSetValue(tlsIdx, instance);
} }
Tesselator::Tesselator(int size) Tesselator::Tesselator(int size)

View file

@ -34,13 +34,9 @@ private:
float xoo, yoo, zoo; float xoo, yoo, zoo;
int _normal; int _normal;
// 4J - added for thread local storage public:
public: static void CreateNewThreadStorage(int bytes);
static void CreateNewThreadStorage(int bytes); static Tesselator *getInstance();
private:
static DWORD tlsIdx;
public:
static Tesselator *getInstance();
private: private:
bool tesselating; bool tesselating;
@ -52,6 +48,7 @@ private:
int vboCounts; int vboCounts;
int size; int size;
public:
Tesselator(int size); Tesselator(int size);
public: public:
Tesselator *getUniqueInstance(int size); Tesselator *getUniqueInstance(int size);

View file

@ -13,12 +13,6 @@
Region::~Region() Region::~Region()
{ {
// flatChunksHeap automatically freed by unique_ptr // flatChunksHeap automatically freed by unique_ptr
// AP - added a caching system for Chunk::rebuild to take advantage of
if( CachedTiles )
{
free(CachedTiles);
}
} }
Region::Region(Level *level, int x1, int y1, int z1, int x2, int y2, int z2, int r) Region::Region(Level *level, int x1, int y1, int z1, int x2, int y2, int z2, int r)
@ -127,11 +121,11 @@ void Region::setCachedTiles(unsigned char *tiles, int xc, int zc)
xcCached = xc; xcCached = xc;
zcCached = zc; zcCached = zc;
int size = 16 * 16 * Level::maxBuildHeight; int size = 16 * 16 * Level::maxBuildHeight;
if( CachedTiles == nullptr ) if (!CachedTiles)
{ {
CachedTiles = static_cast<unsigned char *>(malloc(size)); CachedTiles = std::make_unique<unsigned char[]>(size);
} }
memcpy(CachedTiles, tiles, size); std::copy(tiles, tiles + size, CachedTiles.get());
} }
LevelChunk* Region::getLevelChunk(int x, int y, int z) LevelChunk* Region::getLevelChunk(int x, int y, int z)

View file

@ -19,8 +19,8 @@ private:
bool allEmpty; bool allEmpty;
// AP - added a caching system for Chunk::rebuild to take advantage of // AP - added a caching system for Chunk::rebuild to take advantage of
int xcCached, zcCached; int xcCached, zcCached;
unsigned char *CachedTiles; std::unique_ptr<unsigned char[]> CachedTiles;
public: public:
Region(Level *level, int x1, int y1, int z1, int x2, int y2, int z2, int r); Region(Level *level, int x1, int y1, int z1, int x2, int y2, int z2, int r);