Fix: SetCurrentSHP memory leak & mix file cache potential resource leak . (#140)

This commit is contained in:
Zero Fanker 2025-07-31 22:37:13 -04:00 committed by GitHub
parent ec81f89070
commit e97c36f548
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 116 additions and 69 deletions

View file

@ -189,7 +189,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;WIN32;_LIB;$(XCC_MINIMAL_BUILD);$(NO_FT_SUPPORT);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;_LIB;NOMINMAX;$(XCC_MINIMAL_BUILD);$(NO_FT_SUPPORT);_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader>Use</PrecompiledHeader>
@ -219,7 +219,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugMinimal|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;WIN32;_LIB;$(XCC_MINIMAL_BUILD);$(NO_FT_SUPPORT);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;_LIB;NOMINMAX;$(XCC_MINIMAL_BUILD);$(NO_FT_SUPPORT);_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader>Use</PrecompiledHeader>
@ -248,7 +248,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PreprocessorDefinitions>NDEBUG;WIN32;_LIB;$(XCC_MINIMAL_BUILD);$(NO_FT_SUPPORT);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;_LIB;NOMINMAX;$(XCC_MINIMAL_BUILD);$(NO_FT_SUPPORT);NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
@ -278,7 +278,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseMinimal|x64'">
<ClCompile>
<PreprocessorDefinitions>NDEBUG;WIN32;_LIB;$(XCC_MINIMAL_BUILD);$(NO_FT_SUPPORT);%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>WIN32;_LIB;NOMINMAX;$(XCC_MINIMAL_BUILD);$(NO_FT_SUPPORT);NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>

View file

@ -17,6 +17,7 @@
*/
#include <stdafx.h>
#include <array>
#include "mix_file.h"
#ifndef NO_FT_SUPPORT

View file

@ -18,6 +18,8 @@
#pragma once
#include <map>
#include <vector>
#include "cc_file.h"
#include "cc_structures.h"

View file

@ -30,8 +30,9 @@ Cvirtual_binary_source::Cvirtual_binary_source(const void* d, size_t cb_d, const
} else {
m_data = new byte[cb_d];
m_size = cb_d;
if (d)
if (d) {
memcpy(m_data, d, cb_d);
}
}
mc_references = 1;
}

View file

@ -44,6 +44,9 @@ struct IUnknown;
#include <hva_file.h>
#include "mix_file_write.h"
#include <locale>
#include <utility>
#include <unordered_map>
#include <filesystem>
#include <windows.h>
#include <windowsx.h>
@ -53,9 +56,10 @@ struct IUnknown;
#include "VoxelNormals.h"
Cmix_file mixfiles[2000];
std::string mixfiles_names[2000];
size_t constexpr mixfileCachedCapacity = 2000;
Cmix_file mixfiles[mixfileCachedCapacity];
std::string mixfiles_names[mixfileCachedCapacity];
std::unordered_map<std::string_view, size_t> cacheMixFileIndexes;
Cshp_ts_file cur_shp; // for now only support one shp at once
Ctmp_ts_file cur_tmp;
@ -386,47 +390,78 @@ namespace FSunPackLib
return TRUE;
}
HMIXFILE XCC_OpenMix(LPCTSTR szMixFile, HMIXFILE hOwner)
char toLower(char in)
{
DWORD i, d = 0xFFFFFFFF;
for (i = 0; i <= dwMixFileCount && i < 2000; i++) {
if (mixfiles[i].is_open() == false) {
d = i;
break;
return std::tolower(in);
}
HMIXFILE XCC_OpenMix(LPCTSTR szMixFile, HMIXFILE hParent)
{
size_t cur = 0xFFFFFFFF;
auto const fullName = [szMixFile]() -> std::string {
std::filesystem::path fileFullPath(szMixFile);
auto fullName = fileFullPath.string();
std::transform(fullName.begin(), fullName.end(), fullName.begin(), toLower);
return fullName;
}();
auto const it = cacheMixFileIndexes.find(fullName);
if (it == cacheMixFileIndexes.end()) {
auto const cacheEnd = std::min<size_t>(dwMixFileCount + 1, mixfileCachedCapacity);
for (auto i = 0ull; i <= cacheEnd; i++) {
if (mixfiles[i].is_open() == false) {
cur = i;
break;
}
}
} else {
cur = it->second;
}
if (d == 0xFFFFFFFF)
if (cur == 0xFFFFFFFF) {
return NULL;
std::string sMixFile = szMixFile;
if (hOwner == NULL) {
if (open_read(mixfiles[d], sMixFile))
return NULL;
//mixfiles[dwMixFileCount].enable_mix_expansion();
mixfiles_names[d] = szMixFile;
if (d == dwMixFileCount)
dwMixFileCount++;
return d + 1;//dwMixFileCount;
} else if (hOwner > 0 && (hOwner - 1) < dwMixFileCount) {
if (szMixFile[0] == L'_' && szMixFile[1] == L'I' && szMixFile[2] == L'D') {
char id[256];
strcpy_s(id, &sMixFile[3]);
int iId = atoi(id);
if (mixfiles[d].open(iId, mixfiles[hOwner - 1])) return NULL;
} else {
if (mixfiles[d].open(sMixFile, mixfiles[hOwner - 1]))
return NULL;
}
// no parent, open it directly
if (hParent == NULL) {
if (mixfiles[cur].is_open()) {
return static_cast<HMIXFILE>(cur + 1);
}
mixfiles_names[d] = szMixFile;
if (d == dwMixFileCount)
if (0 != open_read(mixfiles[cur], fullName)) {
return NULL;
}
mixfiles_names[cur] = std::move(fullName);
cacheMixFileIndexes.emplace(mixfiles_names[cur], cur);
if (cur == dwMixFileCount) {
dwMixFileCount++;
return d + 1;
}
return static_cast<HMIXFILE>(cur + 1);//dwMixFileCount;
}
auto const parent = hParent - 1;
if (parent >= dwMixFileCount) {
return NULL;
}
return NULL;
// directly open with crc id
if (fullName.compare(0, 3, "_ID") == 0) {
char id[256];
strcpy_s(id, fullName.c_str() + 3);
int iId = atoi(id);
if (mixfiles[cur].open(iId, mixfiles[parent])) {
return NULL;
}
} else {
if (mixfiles[cur].open(fullName, mixfiles[parent])) {
return NULL;
}
}
mixfiles_names[cur] = std::move(fullName);
cacheMixFileIndexes.emplace(mixfiles_names[cur], cur);
if (cur == dwMixFileCount) {
dwMixFileCount++;
}
return static_cast<HMIXFILE>(cur + 1);
}
BOOL XCC_GetMixName(HMIXFILE hOwner, std::string& sMixFile)
@ -460,18 +495,25 @@ namespace FSunPackLib
BOOL XCC_CloseMix(HMIXFILE hMixFile)
{
if (hMixFile<1 || hMixFile>dwMixFileCount)
if (hMixFile < 1 || hMixFile > dwMixFileCount) {
return FALSE;
}
hMixFile--; // -1 to make it to an array index
auto const& name = mixfiles_names[hMixFile];
auto const erased = cacheMixFileIndexes.erase(name);
assert(erased == 1);
mixfiles_names[hMixFile].clear();
if (mixfiles[hMixFile].is_open()) mixfiles[hMixFile].close();
else
return FALSE;
if (mixfiles[hMixFile].is_open()) {
mixfiles[hMixFile].close();
return TRUE;
}
return FALSE;
return TRUE;
}
BOOL XCC_ExtractFile(const std::string& szFilename, const std::string& szSaveTo, HMIXFILE hOwner)
@ -505,10 +547,10 @@ namespace FSunPackLib
if (open_write(target_file, szSaveTo))
return FALSE;
const int bufferSize = static_cast<int>(min(file.get_size(), 1024 * 1024));
const int bufferSize = static_cast<int>(std::min<size_t>(file.get_size(), 1024 * 1024));
std::vector<byte> buffer(bufferSize);
for (auto p = 0; p < file.get_size();) {
const auto toRead = static_cast<int>(min(file.get_size() - p, bufferSize));
const auto toRead = static_cast<int>(std::min<size_t>(file.get_size() - p, bufferSize));
if (file.read(buffer.data(), toRead))
return FALSE;
if (target_file.write(buffer.data(), toRead))
@ -593,24 +635,25 @@ namespace FSunPackLib
if (cur_shp.is_open()) {
cur_shp.close();
}
auto const fileIdx = hOwner - 1;
if (hOwner == NULL) {
if (open_read(cur_shp, szSHP) != 0) {
return false;
}
} else {
auto const id = mixfiles[hOwner - 1].get_id(mixfiles[hOwner - 1].get_game(), szSHP);
auto const size = mixfiles[hOwner - 1].get_size(id);
if (size == 0) {
OutputDebugString("NULL size");
return false;
}
BYTE* b = new(BYTE[size]);
mixfiles[hOwner - 1].seek(mixfiles[hOwner - 1].get_offset(id));
mixfiles[hOwner - 1].read(b, size);
cur_shp.load(Cvirtual_binary(b, size));
return true;
}
auto const id = mixfiles[fileIdx].get_id(mixfiles[fileIdx].get_game(), szSHP);
auto const size = mixfiles[fileIdx].get_size(id);
if (size == 0) {
OutputDebugString("NULL size");
return false;
}
auto buffer = std::shared_ptr<BYTE>(new BYTE[size]); // this line is most important to fix memory leak
mixfiles[fileIdx].seek(mixfiles[fileIdx].get_offset(id));
mixfiles[fileIdx].read(buffer.get(), size);
cur_shp.load(Cvirtual_binary(buffer.get(), size, buffer));
return true;
};
@ -1618,7 +1661,7 @@ namespace FSunPackLib
auto normalDotLightingVec = normal.dot(inverseLightDirection);
auto lightVal = normalDotLightingVec < 0.0f ? 0.0f : normalDotLightingVec;
assert(fabs(normal.squaredLength() - 1.0f) < 0.01f);
lighting[ofs] = max(0, static_cast<BYTE>(lightVal * 255.0f));
lighting[ofs] = std::max< BYTE>(0, static_cast<BYTE>(lightVal * 255.0f));
image_z[ofs] = static_cast<char>(d_pixel.z());
} else
r += 2;;

View file

@ -135,7 +135,7 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<WarningLevel>Level3</WarningLevel>
<AdditionalIncludeDirectories>..\3rdParty\xcc\misc;.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>NDEBUG;EF;WIN32;_LIB;NO_XIF_SUPPORT;NO_FT_SUPPORT;NO_AVI_SUPPORT;XCC_MINIMAL_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>NDEBUG;EF;WIN32;_LIB;NO_XIF_SUPPORT;NO_FT_SUPPORT;NO_AVI_SUPPORT;XCC_MINIMAL_BUILD;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AssemblerListingLocation>.\Release\</AssemblerListingLocation>
<PrecompiledHeaderOutputFile>.\Release\MissionEditorPackLib.pch</PrecompiledHeaderOutputFile>
<ObjectFileName>.\Release\</ObjectFileName>
@ -204,7 +204,7 @@
<ProgramDataBaseFileName>.\Debug\</ProgramDataBaseFileName>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<LanguageStandard>stdcpp20</LanguageStandard>
<PreprocessorDefinitions>_DEBUG;WIN32;_LIB;NO_XIF_SUPPORT;NO_FT_SUPPORT;NO_AVI_SUPPORT;XCC_MINIMAL_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_DEBUG;WIN32;_LIB;NO_XIF_SUPPORT;NO_FT_SUPPORT;NO_AVI_SUPPORT;XCC_MINIMAL_BUILD;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<ResourceCompile>
<Culture>0x0407</Culture>

View file

@ -85,17 +85,17 @@ public:
inline Vec3& minimum(const Vec3& v2)
{
v[0] = min(v[0], v2[0]);
v[1] = min(v[1], v2[1]);
v[2] = min(v[2], v2[2]);
v[0] = std::min(v[0], v2[0]);
v[1] = std::min(v[1], v2[1]);
v[2] = std::min(v[2], v2[2]);
return *this;
}
inline Vec3& maximum(const Vec3& v2)
{
v[0] = max(v[0], v2[0]);
v[1] = max(v[1], v2[1]);
v[2] = max(v[2], v2[2]);
v[0] = std::max(v[0], v2[0]);
v[1] = std::max(v[1], v2[1]);
v[2] = std::max(v[2], v2[2]);
return *this;
}