OMEM.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  1. /*
  2. * Seven Kingdoms: Ancient Adversaries
  3. *
  4. * Copyright 1997,1998 Enlight Software Ltd.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. //Filename : OMEM.CPP
  21. //Description : Object Memory Management (Debug Version)
  22. #include <string.h>
  23. #include <stdlib.h>
  24. #ifndef NO_MEM_CLASS
  25. #include <stdio.h>
  26. #include <ALL.h>
  27. //--------- Define Constants -----------//
  28. // We will write the PRE_CHK_VAL before every allocated memory block
  29. // and POST_CHK_VAL after them, so when freeing them, we could
  30. // know whether they have been underrun/overun or not
  31. #define CHK_VAL_SIZE sizeof(long)
  32. #define PRE_CHK_VAL 0x12345678 // value to detect underrun
  33. #define POST_CHK_VAL 0x87654321 // value to detect overrun
  34. // The followings should are selected to give maximum probability that
  35. // pointers loaded with these values will cause an obvious crash.
  36. // MALLOCVAL is the value to set malloc'd data to.
  37. #define BAD_VAL 0xFF // set to this value for freed memory (memory that we no longer occupy)
  38. #define ALLOC_VAL 0xEE // set to this value for memory just allocated
  39. //---------- define constant and structure --------//
  40. #define SPOOL_MEM 50 // 50 bytes spool memory for mem_add(),
  41. struct MemInfo
  42. {
  43. void *ptr; // this pointer directly point to useable buffer
  44. unsigned size; // bypassing the PRE_CHK_VAL
  45. char *file_name;
  46. int file_line;
  47. };
  48. //-------- BEGIN OF FUNCTION Mem::Mem ------------//
  49. Mem::Mem()
  50. {
  51. info_array = (MemInfo *)malloc(sizeof(MemInfo) * 100);
  52. if ( info_array == NULL )
  53. err.mem();
  54. ptr_num = 100 ;
  55. ptr_used = 0;
  56. }
  57. //---------- END OF FUNCTION Mem::Mem ------------//
  58. //--------- BEGIN OF FUNCTION Mem::add --------------//
  59. //
  60. // <unsigned> memNum = the size of the memory to be allocated
  61. // <char*> fileName = file from which the client function calls
  62. // <int> fileLine = line number of the client function in the file
  63. //
  64. char* Mem::add(unsigned memSize, char* fileName, int fileLine)
  65. {
  66. // ###### begin Gilbert 29/8 ######//
  67. //err_when( memSize > 1000000 ); //**BUGHERE, for temporary debugging only
  68. err_when( memSize > 0x800000 );
  69. // ###### end Gilbert 29/8 ######//
  70. //----------- build up memory pointer table ---------//
  71. if ( ptr_used == ptr_num )
  72. {
  73. ptr_num += 100 ;
  74. if ( ptr_num > 10000 )
  75. err.run( " Mem::add() - Too many pointers " );
  76. info_array = (MemInfo*) realloc( info_array, sizeof(MemInfo) * ptr_num ) ;
  77. if ( info_array == NULL )
  78. err.mem();
  79. }
  80. //----------- actually allocate memory -------------//
  81. char *allocPtr;
  82. allocPtr = (char *)malloc(sizeof(char)*( memSize + CHK_VAL_SIZE*2 )); // Pre-check & Post-check
  83. if ( allocPtr == NULL )
  84. {
  85. err.mem();
  86. return NULL;
  87. }
  88. else
  89. {
  90. // set check value before and after the allocated block,
  91. // so Mem::del() can use these check value to detect
  92. // underrun && overrun
  93. *((long*)allocPtr) = PRE_CHK_VAL;
  94. *((long*)(allocPtr+CHK_VAL_SIZE+memSize)) = POST_CHK_VAL;
  95. // fill the allocated block with a value, which may
  96. // have chance to reveal some hiden bugs
  97. memset( allocPtr+CHK_VAL_SIZE, ALLOC_VAL, memSize );
  98. info_array[ptr_used].ptr = allocPtr+CHK_VAL_SIZE;
  99. info_array[ptr_used].size = memSize;
  100. info_array[ptr_used].file_name = fileName;
  101. info_array[ptr_used].file_line = fileLine;
  102. ptr_used++;
  103. return allocPtr+CHK_VAL_SIZE;
  104. }
  105. }
  106. //---------- END OF FUNCTION Mem::add ---------------//
  107. //--------- BEGIN OF FUNCTION Mem::add_clear --------------//
  108. //
  109. // Allocate the memory and set all the memory content to byte 0.
  110. //
  111. // <unsigned> memNum = the size of the memory to be allocated
  112. // <char*> fileName = file from which the client function calls
  113. // <int> fileLine = line number of the client function in the file
  114. //
  115. char* Mem::add_clear(unsigned memSize, char* fileName, int fileLine)
  116. {
  117. err_when( memSize > 1000000 ); //**BUGHERE, for temporary debugging only
  118. //----------- build up memory pointer table ---------//
  119. if ( ptr_used == ptr_num )
  120. {
  121. ptr_num += 100 ;
  122. if ( ptr_num > 10000 )
  123. err.run( " Mem::add_clear() - Too many pointers " );
  124. info_array = (MemInfo*) realloc( info_array, sizeof(MemInfo) * ptr_num ) ;
  125. if ( info_array == NULL )
  126. err.mem();
  127. }
  128. //----------- actually allocate memory -------------//
  129. char *allocPtr;
  130. allocPtr = (char*)malloc(sizeof(char)*( memSize + CHK_VAL_SIZE*2 )); // Pre-check & Post-check
  131. if ( allocPtr == NULL )
  132. {
  133. err.mem();
  134. return NULL;
  135. }
  136. else
  137. {
  138. // set check value before and after the allocated block,
  139. // so Mem::del() can use these check value to detect
  140. // underrun && overrun
  141. *((long*)allocPtr) = PRE_CHK_VAL;
  142. *((long*)(allocPtr+CHK_VAL_SIZE+memSize)) = POST_CHK_VAL;
  143. // fill the allocated block with a value, which may
  144. // have chance to reveal some hiden bugs
  145. memset( allocPtr+CHK_VAL_SIZE, 0, memSize );
  146. info_array[ptr_used].ptr = allocPtr+CHK_VAL_SIZE;
  147. info_array[ptr_used].size = memSize;
  148. info_array[ptr_used].file_name = fileName;
  149. info_array[ptr_used].file_line = fileLine;
  150. ptr_used++;
  151. return allocPtr+CHK_VAL_SIZE;
  152. }
  153. }
  154. //---------- END OF FUNCTION Mem::add_clear ---------------//
  155. //-------- BEGIN OF FUNCTION Mem::resize_keep_data ----------//
  156. //
  157. // The Mem::resize() and realloc() may not function properly in
  158. // some case when the memory block has a considerable size.
  159. //
  160. // Calling this function resize_keep_data will do additional effort
  161. // to preserve the original data.
  162. //
  163. // <void*> orgPtr = the original memory data pointer
  164. // <unsigned> orgSize = the original data size
  165. // <unsigned> newSize = new size of memory required
  166. // <char*> fileName = file from which the client function calls
  167. // <int> fileLine = line number of the client function in the file
  168. //
  169. // Returns : NULL - not enough memory
  170. // <char*> - pointer to the allocated memory
  171. //
  172. char* Mem::resize_keep_data(void *orgPtr, unsigned orgSize, unsigned newSize, char* fileName, int fileLine)
  173. {
  174. if( orgPtr == NULL )
  175. return add( newSize, fileName, fileLine);
  176. if( newSize <= orgSize )
  177. return resize(orgPtr, newSize, fileName, fileLine);
  178. //-------- save the original data first ------//
  179. char* saveBuf = (char*)malloc(sizeof(char)*(orgSize));
  180. memcpy( saveBuf, orgPtr, orgSize );
  181. //------ reallocate the memory --------//
  182. char* newPtr = resize(orgPtr, newSize, fileName, fileLine);
  183. //----- store the original data to the new buf -------//
  184. //
  185. // if the new pointer is the same as the orginal pointer
  186. // the original data should be kept without any change
  187. //
  188. //----------------------------------------------------//
  189. if( newPtr != orgPtr )
  190. memcpy( newPtr, saveBuf, orgSize );
  191. free(saveBuf);
  192. return newPtr;
  193. }
  194. //----------- END OF FUNCTION Mem::resize_keep_data ---------------//
  195. //-------- BEGIN OF FUNCTION Mem::resize ----------//
  196. //
  197. // <void*> orgPtr = the original memory data pointer
  198. // <unsigned> memSize = new size of memory required
  199. // <char*> fileName = file from which the client function calls
  200. // <int> fileLine = line number of the client function in the file
  201. //
  202. // Returns : NULL - not enough memory
  203. // <char*> - pointer to the allocated memory
  204. //
  205. // Note : resize() must actually call realloc(), it can't call mem()
  206. // and add(), because some clients want to keep the content on the
  207. // existing buffer. (e.g. DynArray)
  208. //
  209. char* Mem::resize(void *orgPtr, unsigned memSize, char* fileName, int fileLine)
  210. {
  211. err_when( memSize > 1000000 ); //**BUGHERE, for temporary debugging only
  212. if( orgPtr == NULL )
  213. return add( memSize, fileName, fileLine);
  214. //-------------------------------------------//
  215. char *newPtr;
  216. int i;
  217. for( i=ptr_used-1; i>=0; i-- )
  218. {
  219. if( info_array[i].ptr == orgPtr )
  220. {
  221. if( info_array[i].size != memSize )
  222. {
  223. // Remember : MemInfo::ptr points directly to client buffer,
  224. // bypassing the PRE_CHK_VAL
  225. newPtr = (char*) realloc( (char*)orgPtr-CHK_VAL_SIZE, memSize+CHK_VAL_SIZE*2 );
  226. if( newPtr == NULL )
  227. err.mem();
  228. // set the POST_CHK_VAL again as the size of it has changed
  229. *((long*)newPtr) = PRE_CHK_VAL;
  230. *((long*)(newPtr+CHK_VAL_SIZE+memSize)) = POST_CHK_VAL;
  231. info_array[i].ptr = newPtr + CHK_VAL_SIZE;
  232. info_array[i].size = memSize;
  233. }
  234. return (char*) info_array[i].ptr;
  235. }
  236. }
  237. err.run( "Mem::resize - Original memory pointer not found.\n"
  238. "File name : %s, line no. : %d \n", fileName, fileLine );
  239. return NULL;
  240. }
  241. //----------- END OF FUNCTION Mem::resize ---------------//
  242. //-------- BEGIN OF FUNCTION Mem::del ----------//
  243. //
  244. // <void*> freePtr = the memory data pointer to be freed
  245. // <char*> fileName = file from which the client function calls
  246. // <int> fileLine = line number of the client function in the file
  247. //
  248. void Mem::del(void *freePtr, char* fileName, int fileLine)
  249. {
  250. int i ;
  251. char* truePtr;
  252. for( i=ptr_used-1; i>=0; i-- )
  253. {
  254. if( info_array[i].ptr == freePtr )
  255. {
  256. // truePtr is the pointer actually point to the start of the allocated block, including PRE_CHK_VAL
  257. truePtr = (char*) freePtr - CHK_VAL_SIZE;
  258. //---- Check for Underwrite and Overwrite error ---//
  259. if( *((long*)truePtr) != PRE_CHK_VAL )
  260. err.run( "Mem::del - Memory Underwritten, File name:%s, line no.:%d\n", fileName, fileLine );
  261. if( *((long*)(truePtr+CHK_VAL_SIZE+info_array[i].size)) != POST_CHK_VAL )
  262. err.run( "Mem::del - Memory Overwritten, File name:%s, line no.:%d\n", fileName, fileLine );
  263. // fill the to be freed block with a value, which may
  264. // have chance to reveal some hiden bugs
  265. memset( truePtr+CHK_VAL_SIZE, BAD_VAL, info_array[i].size );
  266. //--------- free it up --------------//
  267. free(truePtr);
  268. memmove( info_array+i, info_array+i+1, sizeof(MemInfo) * (ptr_used-i-1) ) ;
  269. ptr_used-- ;
  270. return ;
  271. }
  272. }
  273. err.run( "Mem::del - Free value not found, File name:%s, line no.:%d\n", fileName, fileLine );
  274. }
  275. //----------- END OF FUNCTION Mem::del ---------------//
  276. //-------- BEGIN OF FUNCTION Mem::get_mem_size ----------//
  277. //
  278. // This function is mainly for debugging only.
  279. //
  280. // <void*> memPtr = the memory data pointer to be freed
  281. //
  282. int Mem::get_mem_size(void *memPtr)
  283. {
  284. for( int i=ptr_used-1; i>=0; i-- )
  285. {
  286. if( info_array[i].ptr == memPtr )
  287. return info_array[i].size;
  288. }
  289. err.run( "Error: Mem::get_mem_size()." );
  290. return 0;
  291. }
  292. //----------- END OF FUNCTION Mem::get_mem_size ---------------//
  293. //-------- BEGIN OF FUNCTION Mem::~Mem ------------//
  294. Mem::~Mem()
  295. {
  296. if ( ptr_used > 0 )
  297. {
  298. int i;
  299. for ( i=0; i< ptr_used ; i++ )
  300. {
  301. err.msg( "Memory not freed. File name : %s, line no. : %d \n",
  302. info_array[i].file_name, info_array[i].file_line );
  303. }
  304. }
  305. free(info_array);
  306. }
  307. //---------- END OF FUNCTION Mem::~Mem ------------//
  308. /*
  309. //-------- Begin of Overload "new" operator --------//
  310. void* operator new(size_t memSize)
  311. {
  312. void *memPtr = malloc(memSize);
  313. return memPtr;
  314. }
  315. //--------- End of Overload "new" operator ---------//
  316. //-------- Begin of Overload "delete" operator --------//
  317. void operator delete(void *memPtr)
  318. {
  319. free(memPtr);
  320. }
  321. //--------- End of Overload "delete" operator ---------//
  322. */
  323. #else
  324. //-------- BEGIN OF FUNCTION mem_resize_keep_data ----------//
  325. //
  326. // This is the non-DEBUG version of Mem::resize_keep_data()
  327. //
  328. // <void*> orgPtr = the original memory data pointer
  329. // <unsigned> orgSize = the original data size
  330. // <unsigned> newSize = new size of memory required
  331. //
  332. // Returns : NULL - not enough memory
  333. // <char*> - pointer to the allocated memory
  334. //
  335. char* mem_resize_keep_data(void *orgPtr, unsigned orgSize, unsigned newSize)
  336. {
  337. if( orgPtr == NULL )
  338. return (char*) malloc(newSize);
  339. if( newSize <= orgSize )
  340. return (char*) realloc(orgPtr, newSize);
  341. //-------- save the original data first ------//
  342. char* saveBuf = (char*)malloc(sizeof(char)*(orgSize));
  343. memcpy( saveBuf, orgPtr, orgSize );
  344. //------ reallocate the memory --------//
  345. char* newPtr = (char*) realloc(orgPtr, newSize);
  346. //----- store the original data to the new buf -------//
  347. if( newPtr != orgPtr ) // only when the pointer has been changed
  348. memcpy( newPtr, saveBuf, orgSize );
  349. free(saveBuf);
  350. return newPtr;
  351. }
  352. //----------- END OF FUNCTION mem_resize_keep_data ---------------//
  353. #endif
  354. //-----------------------------------------------------//
  355. //
  356. // An article from Walter Bright's MEM Package which is
  357. // very similar to our omem class
  358. //
  359. // WHAT MEM DOES:
  360. // --------------
  361. //
  362. // 1. ISO/ANSI verification:
  363. //
  364. // When Walter wrote MEM, compiler compliance with ANSI standards was still
  365. // quite low. MEM verifies ISO/ANSI compliance for situations such as passing
  366. // NULL or size 0 to allocation/reallocation functions.
  367. //
  368. // 2. Logging of all allocations and frees:
  369. //
  370. // All MEM's functions pass the __FILE__ and __LINE__ arguments. During alloca-
  371. // tion, MEM makes an entry into a linked list and stores the file and line
  372. // information in the list for whichever allocation or free function is called.
  373. //
  374. // This linked list is the backbone of MEM. When MEM detects a bug, it tells
  375. // you where to look in which file to begin tracking the problem.
  376. //
  377. // 3. Verification of frees:
  378. //
  379. // Since MEM knows about all allocations, when a pointer is freed, MEM can
  380. // verify that the pointer was allocated originally. Additionally, MEM will
  381. // only allow a pointer to be freed once.
  382. //
  383. // Freed data is overwritten with a non-zero known value, flushing such problems
  384. // as continuing to reference data after it's been freed. The value written
  385. // over the data is selected to maximize the probability of a segment fault or
  386. // assertion failure if your application references it after it's been freed.
  387. //
  388. // MEM obviously can't directly detect "if" instances such as...
  389. //
  390. // mem_free(p);
  391. // if (p) ...
  392. //
  393. // ...but by guaranteeing that `p' points to garbage after being freed, code
  394. // like this will hopefully never work and will thus be easier to find.
  395. //
  396. // 4. Detection of pointer over- and under-run:
  397. //
  398. // Pointer overrun occurs when a program stores data past the end of a buffer,
  399. // e.g.
  400. //
  401. // p = malloc(strlen(s)); /* No space for terminating NUL */
  402. // strcpy(p,s); /* Terminating NUL clobber memory */
  403. //
  404. // Pointer underrun occurs when a program stores data before the beginning of a
  405. // buffer. This error occurs less often than overruns, but MEM detects it
  406. // anyway. MEM does this by allocating a little extra at each end of every
  407. // buffer, which is filled with a known value, called a sentinel. MEM detects
  408. // overruns and underruns by verifying the sentinel value when the buffer is
  409. // freed.
  410. //
  411. // 5. Dependence on values in buffer obtained from malloc():
  412. //
  413. // When obtaining a buffer from malloc(), a program may develop erroneous and
  414. // creeping dependencies on whatever random (and sometimes repeatable) values
  415. // the buffer may contain. The mem_malloc() function prevents this by always
  416. // setting the data in a buffer to a known non-zero value before returning its
  417. // pointer. This also prevents another common error when running under MS-DOS
  418. // which doesn't clear unused memory when loading a program. These bugs are
  419. // particularly nasty to find since correct program operation may depend on what
  420. // was last run!
  421. //
  422. // 6. Realloc problems:
  423. //
  424. // Common problems when using realloc() are: 1) depending on realloc() *not*
  425. // shifting the location of the buffer in memory, and 2) depending on finding
  426. // certain values in the uninitialized region of the realloc'ed buffer.
  427. //
  428. // MEM flushes these out by *always* moving the buffer and stomping on values
  429. // past the initialized area.
  430. //
  431. // 7. Memory leak detection:
  432. //
  433. // Memory "leaks" are areas that are allocated but never freed. This can become
  434. // a major problem in programs that must run for long periods without interrup-
  435. // tion (e.g. BBS's). If there are leaks, eventually the program will run out
  436. // of memory and fail.
  437. //
  438. // Another form of memory leak occurs when a piece of allocated memory should
  439. // have been added to some central data structure, but wasn't.
  440. //
  441. // MEM find memory leaks by keeping track of all allocations and frees. When
  442. // mem_term() is called, a list of all unfreed allocations is printed along with
  443. // the files and line numbers where the allocations occurred.
  444. //
  445. // 8. Pointer checking:
  446. //
  447. // Sometimes it's useful to be able to verify that a pointer is actually
  448. // pointing into free store. MEM provides a function...
  449. //
  450. // mem_checkptr(void *p);
  451. //
  452. // ...to do this.
  453. //
  454. // 9. Consistency checking:
  455. //
  456. // Occasionally, even MEM's internal data structures get clobbered by a wild
  457. // pointer. When this happens, you can track it down by sprinkling your code
  458. // temporarily with calls to mem_check(), which performs a consistency check on
  459. // the free store.
  460. //
  461. // 10. Out of memory handling:
  462. //
  463. // MEM can be set using mem_setexception() (see MEM.H) to handle out-of-memory
  464. // conditions in any one of several predefined ways:
  465. //
  466. // 1. Present an "Out of memory" message and terminate the program.
  467. // 2. Abort the program with no message.
  468. // 3. Mimic ISO/ANSI and return NULL.
  469. // 4. Call a user-specified function, perhaps involving virtual memory
  470. // or some other "emergency reserve".
  471. // 5. Retry (be careful to avoid infinite loops!)
  472. //
  473. // 11. Companion techniques:
  474. //
  475. // Since MEM presets allocated and stomps on freed memory, this facilitates
  476. // adding your own code to add tags to your data structures when debugging. If
  477. // the structures are invalid, you'll know it because MEM will have clobbered
  478. // your verification tags.
  479. //
  480. //-----------------------------------------------------//