diff --git a/core/HalfLife2.cpp b/core/HalfLife2.cpp index 9e2bad5b..27007a03 100644 --- a/core/HalfLife2.cpp +++ b/core/HalfLife2.cpp @@ -1212,6 +1212,45 @@ bool IsWindowsReservedDeviceName(const char *pMapname) } #endif +#if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS +// This frees memory allocated by the game using the game's CRT on Windows, +// avoiding a crash due to heap corruption (issue #910). +template< class T, class I > +class CUtlMemoryGlobalMalloc : public CUtlMemory< T, I > +{ + typedef CUtlMemory< T, I > BaseClass; + +public: + using BaseClass::BaseClass; + + void Purge() + { + if (!IsExternallyAllocated()) + { + if (m_pMemory) + { + UTLMEMORY_TRACK_FREE(); + g_pMemAlloc->Free((void*)m_pMemory); + m_pMemory = 0; + } + m_nAllocationCount = 0; + } + BaseClass::Purge(); + } +}; + +void CHalfLife2::FreeUtlVectorUtlString(CUtlVector> &vec) +{ + CUtlMemoryGlobalMalloc *pMemory; + FOR_EACH_VEC(vec, i) + { + pMemory = (CUtlMemoryGlobalMalloc *) &vec[i].m_Storage.m_Memory; + pMemory->Purge(); + vec[i].m_Storage.SetLength(0); + } +} +#endif + SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_t nMapNameMax) { /* We need to ensure user input does not contain reserved device names on windows */ @@ -1245,8 +1284,13 @@ SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_ static size_t helperCmdLen = strlen(pHelperCmd->GetName()); +#ifdef PLATFORM_WINDOWS + CUtlVector> results; + pHelperCmd->AutoCompleteSuggest(pMapName, *(CUtlVector>*)&results); +#else CUtlVector results; pHelperCmd->AutoCompleteSuggest(pMapName, results); +#endif if (results.Count() == 0) return SMFindMapResult::NotFound; @@ -1258,11 +1302,17 @@ SMFindMapResult CHalfLife2::FindMap(const char *pMapName, char *pFoundMap, size_ bool bExactMatch = Q_strcmp(pMapName, &results[0][helperCmdLen + 1]) == 0; if (bExactMatch) { +#ifdef PLATFORM_WINDOWS + FreeUtlVectorUtlString(results); +#endif return SMFindMapResult::Found; } else { ke::SafeStrcpy(pFoundMap, nMapNameMax, &results[0][helperCmdLen + 1]); +#ifdef PLATFORM_WINDOWS + FreeUtlVectorUtlString(results); +#endif return SMFindMapResult::FuzzyMatch; } diff --git a/core/HalfLife2.h b/core/HalfLife2.h index 6393a3ce..9a1662af 100644 --- a/core/HalfLife2.h +++ b/core/HalfLife2.h @@ -179,6 +179,12 @@ enum class SMFindMapResult : cell_t { PossiblyAvailable }; +#if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS +template< class T, class I = int > +class CUtlMemoryGlobalMalloc; +class CUtlString; +#endif + class CHalfLife2 : public SMGlobalClass, public IGameHelpers @@ -229,6 +235,9 @@ public: //IGameHelpers bool IsMapValid(const char *map); SMFindMapResult FindMap(char *pMapName, size_t nMapNameMax); SMFindMapResult FindMap(const char *pMapName, char *pFoundMap = NULL, size_t nMapNameMax = 0); +#if SOURCE_ENGINE >= SE_LEFT4DEAD && defined PLATFORM_WINDOWS + void FreeUtlVectorUtlString(CUtlVector> &vec); +#endif bool GetMapDisplayName(const char *pMapName, char *pDisplayname, size_t nMapNameMax); #if SOURCE_ENGINE >= SE_ORANGEBOX string_t AllocPooledString(const char *pszValue);