mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-03-01 14:48:19 +00:00
Added code to detect memory overwrites on Windows
Define WIN32_DETECT_OVERWRITE while building to enable this functionality.
This commit is contained in:
@@ -6330,7 +6330,125 @@ History:
|
||||
|
||||
#endif /* !HAVE_MALLOC */
|
||||
|
||||
#ifdef HAVE_MALLOC
|
||||
|
||||
// Define WIN32_DETECT_OVERWRITE if you'd like guard pages around memory allocations on Windows
|
||||
#if 0
|
||||
#define WIN32_DETECT_OVERWRITE
|
||||
#endif
|
||||
#ifdef WIN32_DETECT_OVERWRITE
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PBYTE pAddr;
|
||||
ULONG ulSize;
|
||||
} SAFE_HEAP_POINTER;
|
||||
|
||||
static DWORD GetPageSize()
|
||||
{
|
||||
static DWORD page_size;
|
||||
|
||||
if (!page_size) {
|
||||
SYSTEM_INFO si = { 0 };
|
||||
GetSystemInfo(&si);
|
||||
page_size = si.dwPageSize;
|
||||
}
|
||||
return page_size;
|
||||
}
|
||||
|
||||
static ULONG SDLCALL real_msize(IN void *pPtr)
|
||||
{
|
||||
PBYTE pVirtualAddr = (PBYTE)pPtr;
|
||||
SAFE_HEAP_POINTER *pSafePtr = (SAFE_HEAP_POINTER *)(pVirtualAddr - sizeof(SAFE_HEAP_POINTER));
|
||||
ULONG_PTR rvaOld = (ULONG_PTR)(pSafePtr + 1) - (ULONG_PTR)pSafePtr->pAddr;
|
||||
return (ULONG)(pSafePtr->ulSize - GetPageSize() - rvaOld);
|
||||
}
|
||||
|
||||
static void SDLCALL real_free(IN void *pPtr)
|
||||
{
|
||||
if (!pPtr) {
|
||||
return;
|
||||
}
|
||||
|
||||
PBYTE pVirtualAddr = (PBYTE)pPtr;
|
||||
SAFE_HEAP_POINTER *pSafePtr = (SAFE_HEAP_POINTER *)(pVirtualAddr - sizeof(SAFE_HEAP_POINTER));
|
||||
ULONG ulOldProtect;
|
||||
VirtualProtect(pSafePtr->pAddr + pSafePtr->ulSize - GetPageSize(), GetPageSize(), PAGE_READWRITE, &ulOldProtect);
|
||||
_aligned_free(pSafePtr->pAddr);
|
||||
}
|
||||
|
||||
static void *SDLCALL real_malloc(IN size_t dwBytes)
|
||||
{
|
||||
DWORD dwTotalBytes = (DWORD)dwBytes + sizeof(SAFE_HEAP_POINTER);
|
||||
DWORD dwPages = (dwTotalBytes / GetPageSize()) + 1;
|
||||
DWORD dwAlignedBytesCount = (dwPages + 1) * GetPageSize();
|
||||
PBYTE pPtr = (PBYTE)_aligned_malloc(dwAlignedBytesCount, GetPageSize());
|
||||
if (!pPtr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ZeroMemory(pPtr, dwAlignedBytesCount);
|
||||
PBYTE pLastPageStart = pPtr + dwPages * GetPageSize();
|
||||
ULONG ulOldProtect;
|
||||
PBYTE pBlock = (PBYTE)(pLastPageStart - dwBytes);
|
||||
if (!VirtualProtect(pLastPageStart, GetPageSize(), PAGE_READWRITE | PAGE_GUARD, &ulOldProtect)) {
|
||||
_aligned_free(pPtr);
|
||||
return NULL;
|
||||
}
|
||||
SAFE_HEAP_POINTER *pSafePtr = (SAFE_HEAP_POINTER *)(pBlock - sizeof(SAFE_HEAP_POINTER));
|
||||
pSafePtr->pAddr = pPtr;
|
||||
pSafePtr->ulSize = dwAlignedBytesCount;
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
static void *SDLCALL real_calloc(IN size_t dwElements, IN size_t dwElementSize)
|
||||
{
|
||||
PVOID pPtr = real_malloc(dwElements * dwElementSize);
|
||||
if (pPtr) {
|
||||
ZeroMemory(pPtr, dwElements * dwElementSize);
|
||||
}
|
||||
return pPtr;
|
||||
}
|
||||
|
||||
static void *SDLCALL real_realloc(IN void *pPtr, IN size_t dwBytes)
|
||||
{
|
||||
if (!pPtr) {
|
||||
return real_malloc(dwBytes);
|
||||
}
|
||||
|
||||
PBYTE pVirtualAddr = (PBYTE)pPtr;
|
||||
SAFE_HEAP_POINTER *pSafePtr = (SAFE_HEAP_POINTER *)(pVirtualAddr - sizeof(SAFE_HEAP_POINTER));
|
||||
SAFE_HEAP_POINTER oldPtr = *pSafePtr;
|
||||
ULONG ulPrevSize = real_msize(pPtr);
|
||||
if (ulPrevSize == dwBytes) {
|
||||
return pPtr;
|
||||
}
|
||||
|
||||
// Start working on the addresses
|
||||
DWORD dwTotalBytes = (DWORD)dwBytes + sizeof(SAFE_HEAP_POINTER);
|
||||
DWORD dwNewPages = (dwTotalBytes / GetPageSize()) + 1;
|
||||
DWORD dwAlignedBytesCount = (dwNewPages + 1) * GetPageSize();
|
||||
PBYTE pBlock = 0;
|
||||
PBYTE pLastPageStart = 0;
|
||||
if ((dwAlignedBytesCount <= oldPtr.ulSize) && (dwAlignedBytesCount + GetPageSize() >= oldPtr.ulSize)) {
|
||||
// No need to reallocate memory, the allocated pages R enough
|
||||
pLastPageStart = pSafePtr->pAddr + dwNewPages * GetPageSize();
|
||||
pBlock = (pLastPageStart - dwBytes);
|
||||
MoveMemory(pBlock, pPtr, min(ulPrevSize, dwBytes));
|
||||
pSafePtr = (SAFE_HEAP_POINTER *)(pBlock - sizeof(SAFE_HEAP_POINTER));
|
||||
*pSafePtr = oldPtr;
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
// Buffer was enlarged or reduced by more than PAGE_SIZE
|
||||
PBYTE pNew = (PBYTE)real_malloc(dwBytes);
|
||||
CopyMemory(pNew, pPtr, min(ulPrevSize, dwBytes));
|
||||
real_free(pPtr);
|
||||
return pNew;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_MALLOC)
|
||||
static void * SDLCALL real_malloc(size_t s) { return malloc(s); }
|
||||
static void * SDLCALL real_calloc(size_t n, size_t s) { return calloc(n, s); }
|
||||
static void * SDLCALL real_realloc(void *p, size_t s) { return realloc(p,s); }
|
||||
|
||||
Reference in New Issue
Block a user