/* =========================================================================== Copyright (C) 2023 the OpenMoHAA team This file is part of OpenMoHAA source code. OpenMoHAA source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. OpenMoHAA source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenMoHAA source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ // win_bounds.cpp : Bounds checks all new's and delete's extern "C" { void* b_malloc(unsigned int size); void b_free(void*); }; ////////////////////////// // Bounds checking // // #define DISABLE_BOUNDS to disable checking a compiler // warning will happen if checking is enabled // // #define BOUNDS_ENDOFPAGE to check for overflowed, don't // define it to check for underflows // // functions: // void *b_malloc ( unsigned ); // Does a bounds-malloc, or just a normal one if checking's // disabled // void b_free ( void * ); // Frees a bounds pointer, or just a normal free if no // checking // // void *operator new ( size_t ), operator new[] ( size ) // For C++ new's and new []'s, bounds checked // void operator delete ( void * ), operator delete[] ( void * ) // For C++ delete's and delete []'s, bounds checked ////////////////////////// #define DISABLE_BOUNDS #if defined(GAME_DLL) || defined(CGAME_DLL) #define DISABLE_BOUNDS #endif //#define BOUNDS_ENDOFPAGE ///////////////////////// // If bounds are disabled ///////////////////////// #ifdef DISABLE_BOUNDS #include void* b_malloc(unsigned int size) { return malloc(size); } void b_free(void* what) { free(what); } /////////////////////////// // If bounds are enabled /////////////////////////// #else #pragma message ("win_bounds.cpp: Warning - Bounds checking is enabled\n" ) #include #include typedef struct { unsigned int header; int size; void* returned; } bounds_type_t; #define PAGE_SIZE ( 4096 ) #define NORMAL_HEADER 0xdeadbeef #define ARRAY_HEADER 0xdeadbabe static unsigned int bounds_numpages(unsigned int size) { unsigned int ret; ret = size / PAGE_SIZE + 3; if (size % PAGE_SIZE) ret++; return ret; } void* bounds_malloc(unsigned int size, unsigned head = NORMAL_HEADER) { bounds_type_t* where; unsigned int num_pages; void* mainaddress; num_pages = bounds_numpages(size); mainaddress = VirtualAlloc(NULL, num_pages * PAGE_SIZE, MEM_RESERVE, PAGE_NOACCESS); VirtualAlloc(mainaddress, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE); VirtualAlloc((char*)mainaddress + PAGE_SIZE * 2, (num_pages - 3) * PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE); where = (bounds_type_t*)mainaddress; where->header = head; where->size = size; #ifdef BOUNDS_ENDOFPAGE where->returned = (char*)mainaddress + (num_pages - 1) * PAGE_SIZE - size; #else where->returned = (char*)mainaddress + PAGE_SIZE * 2; #endif memset(where->returned, 0xdc, size); return where->returned; } void bounds_free(void* address, unsigned head = NORMAL_HEADER) { bounds_type_t* where; unsigned int num_pages; void* mainaddress; mainaddress = (char*)address - PAGE_SIZE * 2; #ifdef BOUNDS_ENDOFPAGE mainaddress = (char*)mainaddress - ((unsigned int)mainaddress % 4096); #endif where = (bounds_type_t*)mainaddress; if (where->header != head || where->returned != address) { __asm int 3 // Breakpoint } num_pages = bounds_numpages(where->size); // All pages must be in the same state to be MEM_RELEASED VirtualFree(mainaddress, PAGE_SIZE, MEM_DECOMMIT); VirtualFree((char*)mainaddress + PAGE_SIZE * 2, (num_pages - 3) * PAGE_SIZE, MEM_DECOMMIT); VirtualFree(mainaddress, 0, MEM_RELEASE); } void* b_malloc(unsigned int size) { return bounds_malloc(size); } void b_free(void* what) { bounds_free(what); } void* operator new[](size_t size) { return bounds_malloc(size, ARRAY_HEADER); } void* operator new (size_t size) { return bounds_malloc(size); } void operator delete [](void* what) { if (what) bounds_free(what, ARRAY_HEADER); } void operator delete (void* what) { if (what) bounds_free(what); } #endif /* !DISABLE_BOUNDS */