Explorar el Código

Added code to detect memory overwrites on Windows

Define WIN32_DETECT_OVERWRITE while building to enable this functionality.
Sam Lantinga hace 2 semanas
padre
commit
ab50f30bb1
Se han modificado 1 ficheros con 119 adiciones y 1 borrados
  1. 119 1
      src/stdlib/SDL_malloc.c

+ 119 - 1
src/stdlib/SDL_malloc.c

@@ -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); }