From aba5bdac620ee7e6b0bf7465582ea67228671f59 Mon Sep 17 00:00:00 2001 From: Stefanos Kornilios Mitsis Poiitidis Date: Sun, 23 Mar 2025 06:28:18 +0200 Subject: [PATCH] fix memleaks and clang --- src/miami/animation/CutsceneMgr.cpp | 3 +- src/miami/core/FileLoader.cpp | 18 ++++ src/miami/modelinfo/BaseModelInfo.cpp | 8 ++ src/miami/modelinfo/BaseModelInfo.h | 3 +- vendor/emu/emu/window.cpp | 2 + vendor/librw/src/dc/rwdc.cpp | 134 +++++++++++++++++++++----- 6 files changed, 140 insertions(+), 28 deletions(-) diff --git a/src/miami/animation/CutsceneMgr.cpp b/src/miami/animation/CutsceneMgr.cpp index b40a8906..434c0dd9 100644 --- a/src/miami/animation/CutsceneMgr.cpp +++ b/src/miami/animation/CutsceneMgr.cpp @@ -419,7 +419,8 @@ CCutsceneMgr::DeleteCutsceneData(void) CBaseModelInfo *minfo = CModelInfo::GetModelInfo(i); CColModel *colModel = minfo->GetColModel(); if (colModel != &CTempColModels::ms_colModelPed1) { - delete colModel; + // no need to delete anymore, SetColModel will do it (~skmp) + //delete colModel; minfo->SetColModel(&CTempColModels::ms_colModelPed1); } } diff --git a/src/miami/core/FileLoader.cpp b/src/miami/core/FileLoader.cpp index 4e7eb964..7e12914d 100644 --- a/src/miami/core/FileLoader.cpp +++ b/src/miami/core/FileLoader.cpp @@ -305,6 +305,24 @@ CFileLoader::LoadCollisionModel(uint8 *buf, CColModel &model, char *modelname) model.boundingBox.max.z = *(float*)(buf+36); model.numSpheres = *(int16*)(buf+40); buf += 44; + if (model.spheres) { + RwFree(model.spheres); + } + if (model.lines) { + RwFree(model.lines); + } + if (model.boxes) { + RwFree(model.boxes); + } + if (model.vertices) { + RwFree(model.vertices); + } + if (model.triangles) { + RwFree(model.triangles); + } + if (model.trianglePlanes) { + RwFree(model.trianglePlanes); + } if(model.numSpheres > 0){ model.spheres = (CColSphere*)RwMalloc(model.numSpheres*sizeof(CColSphere)); REGISTER_MEMPTR(&model.spheres); diff --git a/src/miami/modelinfo/BaseModelInfo.cpp b/src/miami/modelinfo/BaseModelInfo.cpp index 709420fd..ef950bc2 100644 --- a/src/miami/modelinfo/BaseModelInfo.cpp +++ b/src/miami/modelinfo/BaseModelInfo.cpp @@ -40,6 +40,14 @@ CBaseModelInfo::DeleteCollisionModel(void) } } +void CBaseModelInfo::SetColModel(CColModel *col, bool owns) { + if (m_bOwnsColModel) { + delete m_colModel; + } + m_colModel = col; + m_bOwnsColModel = owns; +} + void CBaseModelInfo::AddRef(void) { diff --git a/src/miami/modelinfo/BaseModelInfo.h b/src/miami/modelinfo/BaseModelInfo.h index 2d1dc8ac..2007d3fa 100644 --- a/src/miami/modelinfo/BaseModelInfo.h +++ b/src/miami/modelinfo/BaseModelInfo.h @@ -52,8 +52,7 @@ public: bool IsClump(void) { return m_type == MITYPE_CLUMP || m_type == MITYPE_PED || m_type == MITYPE_VEHICLE; } char *GetModelName(void) { return m_name; } void SetModelName(const char *name) { strncpy(m_name, name, MAX_MODEL_NAME); } - void SetColModel(CColModel *col, bool owns = false){ - m_colModel = col; m_bOwnsColModel = owns; } + void SetColModel(CColModel *col, bool owns = false); CColModel *GetColModel(void) { return m_colModel; } bool DoesOwnColModel(void) { return m_bOwnsColModel; } void DeleteCollisionModel(void); diff --git a/vendor/emu/emu/window.cpp b/vendor/emu/emu/window.cpp index 3893f553..f708c90c 100644 --- a/vendor/emu/emu/window.cpp +++ b/vendor/emu/emu/window.cpp @@ -125,6 +125,8 @@ void x11_window_create() x11_win = (void*)x11Window; x11_vis = (void*)x11Visual->visual; + delete x11Visual; + x11_window_set_text("GTA3dc"); } diff --git a/vendor/librw/src/dc/rwdc.cpp b/vendor/librw/src/dc/rwdc.cpp index 3f2ed63c..0aefba1e 100644 --- a/vendor/librw/src/dc/rwdc.cpp +++ b/vendor/librw/src/dc/rwdc.cpp @@ -820,7 +820,8 @@ template struct chunked_vector { static constexpr size_t chunk_size = 8192; - struct chunk; + struct chunk; + struct chunk_header { chunk* prev; chunk* next; @@ -840,15 +841,19 @@ struct chunked_vector { }; // In-object first chunk storage. - chunk first_chunk; chunk* first; chunk* last; // Constructor: initialize first_chunk’s header and set pointers. chunked_vector() - : first_chunk{ { nullptr, nullptr, 0, chunk::item_count } }, - first(&first_chunk), last(&first_chunk) { + first = last = static_cast(malloc(sizeof(chunk))); + + first->header.prev = nullptr; + first->header.next = nullptr; + first->header.used = 0; + first->header.free = chunk::item_count; + static_assert(sizeof(chunk) == chunk_size, "chunk size mismatch"); } @@ -856,7 +861,7 @@ struct chunked_vector { ~chunked_vector() { clear(); // Free all dynamically allocated chunks (except first_chunk). - chunk* curr = first_chunk.header.next; + chunk* curr = first; while (curr) { chunk* next = curr->header.next; free(curr); @@ -935,13 +940,13 @@ struct chunked_vector { curr->header.free = chunk::item_count; } // Free all chunks except first_chunk. - chunk* curr = first_chunk.header.next; + chunk* curr = first->header.next; while (curr) { chunk* next = curr->header.next; free(curr); curr = next; } - first_chunk.header.next = nullptr; + first->header.next = nullptr; // Optionally, reset last pointer to first for reuse. last = first; } @@ -998,14 +1003,93 @@ struct chunked_vector { } }; +template +struct free_pointer_t { + T* ptr; + free_pointer_t(T* p) : ptr(p) { } + free_pointer_t(free_pointer_t&& other) : ptr(other.ptr) { other.ptr = nullptr; } + free_pointer_t(const free_pointer_t&) = delete; + ~free_pointer_t() { + if (ptr) { + free(ptr); + } + } +}; + chunked_vector atomicContexts; chunked_vector meshContexts; chunked_vector skinContexts; static_assert(chunked_vector::chunk::item_count >= 64); chunked_vector matfxContexts; -chunked_vector> opCallbacks; -chunked_vector> blendCallbacks; -chunked_vector> ptCallbacks; + +// A basic move-only function wrapper for callables with signature R(Args...) +template +class move_only_function; // primary template not defined + +template +class move_only_function { +public: + // Default constructor creates an empty callable. + move_only_function() noexcept : callable_(nullptr) {} + + // Templated constructor to accept any callable object. + template + move_only_function(F f) + : callable_(new model(std::move(f))) {} + + // Move constructor. + move_only_function(move_only_function&& other) noexcept + : callable_(other.callable_) { + other.callable_ = nullptr; + } + + // Move assignment operator. + move_only_function& operator=(move_only_function&& other) noexcept { + if (this != &other) { + delete callable_; + callable_ = other.callable_; + other.callable_ = nullptr; + } + return *this; + } + + // Delete copy constructor and copy assignment operator. + move_only_function(const move_only_function&) = delete; + move_only_function& operator=(const move_only_function&) = delete; + + // Destructor. + ~move_only_function() { + delete callable_; + } + + // Invoke the stored callable. + R operator()(Args... args) { + return callable_->invoke(std::forward(args)...); + } + +private: + // Base class for type erasure. + struct concept_t { + virtual ~concept_t() = default; + virtual R invoke(Args&&... args) = 0; + }; + + // Derived template class that stores the actual callable. + template + struct model : concept_t { + F f; + explicit model(F f) : f(std::move(f)) {} + R invoke(Args&&... args) override { + return f(std::forward(args)...); + } + }; + + concept_t* callable_; +}; + +chunked_vector> opCallbacks; +chunked_vector> blendCallbacks; +chunked_vector> ptCallbacks; void dcMotionBlur_v1(uint8_t a, uint8_t r, uint8_t g, uint8_t b) { @@ -1776,9 +1860,8 @@ void im2DRenderPrimitive(PrimitiveType primType, void *vertices, int32_t numVert Im2DVertex* vertData = (Im2DVertex*)malloc(numVertices * sizeof(Im2DVertex)); assert(vertData); memcpy(vertData, verts, numVertices * sizeof(Im2DVertex)); - blendCallbacks.emplace_back([renderCB, vertData]() { - renderCB(vertData); - free(vertData); + blendCallbacks.emplace_back([renderCB, vertData=free_pointer_t{vertData}]() { + renderCB(vertData.ptr); }); } @@ -1884,10 +1967,8 @@ void im2DRenderIndexedPrimitive(PrimitiveType primType, void *vertices, int32 nu uint16_t* idxData = (uint16_t*)malloc(numIndices * sizeof(uint16_t)); assert(idxData); memcpy(idxData, idx, numIndices * sizeof(uint16_t)); - blendCallbacks.emplace_back([renderCB, vertData, idxData]() { - renderCB(vertData, idxData); - free(vertData); - free(idxData); + blendCallbacks.emplace_back([renderCB, vertData=free_pointer_t(vertData), idxData=free_pointer_t(idxData)]() { + renderCB(vertData.ptr, idxData.ptr); }); // std::vector vertData(numIndices); @@ -2131,16 +2212,12 @@ void im3DRenderIndexedPrimitive(PrimitiveType primType, memcpy(idxData, indices, numIndices * sizeof(uint16_t)); if (blendEnabled) { - blendCallbacks.emplace_back([renderCB, idxData = idxData, vtxData = vtxData](){ - renderCB(idxData, vtxData); - free(idxData); - free(vtxData); + blendCallbacks.emplace_back([renderCB, idxData = free_pointer_t(idxData), vtxData = free_pointer_t(vtxData)](){ + renderCB(idxData.ptr, vtxData.ptr); }); } else { - opCallbacks.emplace_back([renderCB, idxData = idxData, vtxData = vtxData](){ - renderCB(idxData, vtxData); - free(idxData); - free(vtxData); + opCallbacks.emplace_back([renderCB, idxData = free_pointer_t(idxData), vtxData = free_pointer_t(vtxData)](){ + renderCB(idxData.ptr, vtxData.ptr); }); } @@ -5097,6 +5174,8 @@ driverClose(void *o, int32, int32) pvr_shutdown(); + engine->driver[PLATFORM_DC]->defaultPipeline->destroy(); + engine->driver[PLATFORM_DC]->defaultPipeline = nil; return o; } @@ -5152,6 +5231,11 @@ readNativeTexture(Stream *stream) auto cached = cachedRasters.find(pvr_id); + assert(natras->raster != nil); + assert(natras->raster->texaddr == nil); + assert(natras->raster->refs == 1); + free(natras->raster); + if (pvr_id != 0 && cached != cachedRasters.end()) { cached->second->refs++; natras->raster = cached->second;