memwatch.c 74 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665
  1. /*
  2. ** MEMWATCH.C
  3. ** Nonintrusive ANSI C memory leak / overwrite detection
  4. ** Copyright (C) 1992-2003 Johan Lindh
  5. ** All rights reserved.
  6. ** Version 2.71
  7. This file is part of MEMWATCH.
  8. MEMWATCH is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 2 of the License, or
  11. (at your option) any later version.
  12. MEMWATCH is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with MEMWATCH; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. **
  20. ** 920810 JLI [1.00]
  21. ** 920830 JLI [1.10 double-free detection]
  22. ** 920912 JLI [1.15 mwPuts, mwGrab/Drop, mwLimit]
  23. ** 921022 JLI [1.20 ASSERT and VERIFY]
  24. ** 921105 JLI [1.30 C++ support and TRACE]
  25. ** 921116 JLI [1.40 mwSetOutFunc]
  26. ** 930215 JLI [1.50 modified ASSERT/VERIFY]
  27. ** 930327 JLI [1.51 better auto-init & PC-lint support]
  28. ** 930506 JLI [1.55 MemWatch class, improved C++ support]
  29. ** 930507 JLI [1.60 mwTest & CHECK()]
  30. ** 930809 JLI [1.65 Abort/Retry/Ignore]
  31. ** 930820 JLI [1.70 data dump when unfreed]
  32. ** 931016 JLI [1.72 modified C++ new/delete handling]
  33. ** 931108 JLI [1.77 mwSetAssertAction() & some small changes]
  34. ** 940110 JLI [1.80 no-mans-land alloc/checking]
  35. ** 940328 JLI [2.00 version 2.0 rewrite]
  36. ** Improved NML (no-mans-land) support.
  37. ** Improved performance (especially for free()ing!).
  38. ** Support for 'read-only' buffers (checksums)
  39. ** ^^ NOTE: I never did this... maybe I should?
  40. ** FBI (free'd block info) tagged before freed blocks
  41. ** Exporting of the mwCounter variable
  42. ** mwBreakOut() localizes debugger support
  43. ** Allocation statistics (global, per-module, per-line)
  44. ** Self-repair ability with relinking
  45. ** 950913 JLI [2.10 improved garbage handling]
  46. ** 951201 JLI [2.11 improved auto-free in emergencies]
  47. ** 960125 JLI [X.01 implemented auto-checking using mwAutoCheck()]
  48. ** 960514 JLI [2.12 undefining of existing macros]
  49. ** 960515 JLI [2.13 possibility to use default new() & delete()]
  50. ** 960516 JLI [2.20 suppression of file flushing on unfreed msgs]
  51. ** 960516 JLI [2.21 better support for using MEMWATCH with DLL's]
  52. ** 960710 JLI [X.02 multiple logs and mwFlushNow()]
  53. ** 960801 JLI [2.22 merged X.01 version with current]
  54. ** 960805 JLI [2.30 mwIsXXXXAddr() to avoid unneeded GP's]
  55. ** 960805 JLI [2.31 merged X.02 version with current]
  56. ** 961002 JLI [2.32 support for realloc() + fixed STDERR bug]
  57. ** 961222 JLI [2.40 added mwMark() & mwUnmark()]
  58. ** 970101 JLI [2.41 added over/underflow checking after failed ASSERT/VERIFY]
  59. ** 970113 JLI [2.42 added support for PC-Lint 7.00g]
  60. ** 970207 JLI [2.43 added support for strdup()]
  61. ** 970209 JLI [2.44 changed default filename to lowercase]
  62. ** 970405 JLI [2.45 fixed bug related with atexit() and some C++ compilers]
  63. ** 970723 JLI [2.46 added MW_ARI_NULLREAD flag]
  64. ** 970813 JLI [2.47 stabilized marker handling]
  65. ** 980317 JLI [2.48 ripped out C++ support; wasn't working good anyway]
  66. ** 980318 JLI [2.50 improved self-repair facilities & SIGSEGV support]
  67. ** 980417 JLI [2.51 more checks for invalid addresses]
  68. ** 980512 JLI [2.52 moved MW_ARI_NULLREAD to occur before aborting]
  69. ** 990112 JLI [2.53 added check for empty heap to mwIsOwned]
  70. ** 990217 JLI [2.55 improved the emergency repairs diagnostics and NML]
  71. ** 990224 JLI [2.56 changed ordering of members in structures]
  72. ** 990303 JLI [2.57 first maybe-fixit-for-hpux test]
  73. ** 990516 JLI [2.58 added 'static' to the definition of mwAutoInit]
  74. ** 990517 JLI [2.59 fixed some high-sensitivity warnings]
  75. ** 990610 JLI [2.60 fixed some more high-sensitivity warnings]
  76. ** 990715 JLI [2.61 changed TRACE/ASSERT/VERIFY macro names]
  77. ** 991001 JLI [2.62 added CHECK_BUFFER() and mwTestBuffer()]
  78. ** 991007 JLI [2.63 first shot at a 64-bit compatible version]
  79. ** 991009 JLI [2.64 undef's strdup() if defined, mwStrdup made const]
  80. ** 000704 JLI [2.65 added some more detection for 64-bits]
  81. ** 010502 JLI [2.66 incorporated some user fixes]
  82. ** [mwRelink() could print out garbage pointer (thanks mac@phobos.ca)]
  83. ** [added array destructor for C++ (thanks rdasilva@connecttel.com)]
  84. ** [added mutex support (thanks rdasilva@connecttel.com)]
  85. ** 010531 JLI [2.67 fix: mwMutexXXX() was declared even if MW_HAVE_MUTEX was not defined]
  86. ** 010619 JLI [2.68 fix: mwRealloc() could leave the mutex locked]
  87. ** 020918 JLI [2.69 changed to GPL, added C++ array allocation by Howard Cohen]
  88. ** 030212 JLI [2.70 mwMalloc() bug for very large allocations (4GB on 32bits)]
  89. ** 030520 JLI [2.71 added ULONG_LONG_MAX as a 64-bit detector (thanks Sami Salonen)]
  90. */
  91. #define __MEMWATCH_C 1
  92. #ifdef MW_NOCPP
  93. #define MEMWATCH_NOCPP
  94. #endif
  95. #ifdef MW_STDIO
  96. #define MEMWATCH_STDIO
  97. #endif
  98. /***********************************************************************
  99. ** Include files
  100. ***********************************************************************/
  101. #include <stdio.h>
  102. #include <stdlib.h>
  103. #include <stdarg.h>
  104. #include <string.h>
  105. #include <signal.h>
  106. #include <setjmp.h>
  107. #include <time.h>
  108. #include <limits.h>
  109. #include "memwatch.h"
  110. #ifndef toupper
  111. #include <ctype.h>
  112. #endif
  113. #if defined(WIN32) || defined(__WIN32__)
  114. #define MW_HAVE_MUTEX 1
  115. #include <windows.h>
  116. #endif
  117. #if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
  118. #define MW_HAVE_MUTEX 1
  119. #include <pthread.h>
  120. #endif
  121. /***********************************************************************
  122. ** Defines & other weird stuff
  123. ***********************************************************************/
  124. /*lint -save -e767 */
  125. #define VERSION "2.71" /* the current version number */
  126. #define CHKVAL(mw) (0xFE0180L^(long)mw->count^(long)mw->size^(long)mw->line)
  127. #define FLUSH() mwFlush()
  128. #define TESTS(f,l) if(mwTestAlways) (void)mwTestNow(f,l,1)
  129. #define PRECHK 0x01234567L
  130. #define POSTCHK 0x76543210L
  131. #define mwBUFFER_TO_MW(p) ( (mwData*) (void*) ( ((char*)p)-mwDataSize-mwOverflowZoneSize ) )
  132. /*lint -restore */
  133. #define MW_NML 0x0001
  134. #ifdef _MSC_VER
  135. #define COMMIT "c" /* Microsoft C requires the 'c' to perform as desired */
  136. #else
  137. #define COMMIT "" /* Normal ANSI */
  138. #endif /* _MSC_VER */
  139. #ifdef __cplusplus
  140. #define CPPTEXT "++"
  141. #else
  142. #define CPPTEXT ""
  143. #endif /* __cplusplus */
  144. #ifdef MEMWATCH_STDIO
  145. #define mwSTDERR stderr
  146. #else
  147. #define mwSTDERR mwLog
  148. #endif
  149. #ifdef MW_HAVE_MUTEX
  150. #define MW_MUTEX_INIT() mwMutexInit()
  151. #define MW_MUTEX_TERM() mwMutexTerm()
  152. #define MW_MUTEX_LOCK() mwMutexLock()
  153. #define MW_MUTEX_UNLOCK() mwMutexUnlock()
  154. #else
  155. #define MW_MUTEX_INIT()
  156. #define MW_MUTEX_TERM()
  157. #define MW_MUTEX_LOCK()
  158. #define MW_MUTEX_UNLOCK()
  159. #endif
  160. /***********************************************************************
  161. ** If you really, really know what you're doing,
  162. ** you can predefine these things yourself.
  163. ***********************************************************************/
  164. #ifndef mwBYTE_DEFINED
  165. # if CHAR_BIT != 8
  166. # error need CHAR_BIT to be 8!
  167. # else
  168. typedef unsigned char mwBYTE;
  169. # define mwBYTE_DEFINED 1
  170. # endif
  171. #endif
  172. #if defined(ULONGLONG_MAX) || defined(ULLONG_MAX) || defined(_UI64_MAX) || defined(ULONG_LONG_MAX)
  173. # define mw64BIT 1
  174. # define mwROUNDALLOC_DEFAULT 8
  175. #else
  176. # if UINT_MAX <= 0xFFFFUL
  177. # define mw16BIT 1
  178. # define mwROUNDALLOC_DEFAULT 2
  179. # else
  180. # if ULONG_MAX > 0xFFFFFFFFUL
  181. # define mw64BIT 1
  182. # define mwROUNDALLOC_DEFAULT 8
  183. # else
  184. # define mw32BIT 1
  185. # define mwROUNDALLOC_DEFAULT 4
  186. # endif
  187. # endif
  188. #endif
  189. /* mwROUNDALLOC is the number of bytes to */
  190. /* round up to, to ensure that the end of */
  191. /* the buffer is suitable for storage of */
  192. /* any kind of object */
  193. #ifndef mwROUNDALLOC
  194. # define mwROUNDALLOC mwROUNDALLOC_DEFAULT
  195. #endif
  196. #ifndef mwDWORD_DEFINED
  197. #if ULONG_MAX == 0xFFFFFFFFUL
  198. typedef unsigned long mwDWORD;
  199. #define mwDWORD_DEFINED "unsigned long"
  200. #endif
  201. #endif
  202. #ifndef mwDWORD_DEFINED
  203. #if UINT_MAX == 0xFFFFFFFFUL
  204. typedef unsigned int mwDWORD;
  205. #define mwDWORD_DEFINED "unsigned int"
  206. #endif
  207. #endif
  208. #ifndef mwDWORD_DEFINED
  209. #if USHRT_MAX == 0xFFFFFFFFUL
  210. typedef unsigned short mwDWORD;
  211. #define mwDWORD_DEFINED "unsigned short"
  212. #endif
  213. #endif
  214. #ifndef mwBYTE_DEFINED
  215. #error "can't find out the correct type for a 8 bit scalar"
  216. #endif
  217. #ifndef mwDWORD_DEFINED
  218. #error "can't find out the correct type for a 32 bit scalar"
  219. #endif
  220. /***********************************************************************
  221. ** Typedefs & structures
  222. ***********************************************************************/
  223. /* main data holding area, precedes actual allocation */
  224. typedef struct mwData_ mwData;
  225. struct mwData_ {
  226. mwData* prev; /* previous allocation in chain */
  227. mwData* next; /* next allocation in chain */
  228. const char* file; /* file name where allocated */
  229. long count; /* action count */
  230. long check; /* integrity check value */
  231. #if 0
  232. long crc; /* data crc value */
  233. #endif
  234. size_t size; /* size of allocation */
  235. int line; /* line number where allocated */
  236. unsigned flag; /* flag word */
  237. };
  238. /* statistics structure */
  239. typedef struct mwStat_ mwStat;
  240. struct mwStat_ {
  241. mwStat* next; /* next statistic buffer */
  242. const char* file;
  243. long total; /* total bytes allocated */
  244. long num; /* total number of allocations */
  245. long max; /* max allocated at one time */
  246. long curr; /* current allocations */
  247. int line;
  248. };
  249. /* grabbing structure, 1K in size */
  250. typedef struct mwGrabData_ mwGrabData;
  251. struct mwGrabData_ {
  252. mwGrabData* next;
  253. int type;
  254. char blob[ 1024 - sizeof(mwGrabData*) - sizeof(int) ];
  255. };
  256. typedef struct mwMarker_ mwMarker;
  257. struct mwMarker_ {
  258. void *host;
  259. char *text;
  260. mwMarker *next;
  261. int level;
  262. };
  263. #if defined(WIN32) || defined(__WIN32__)
  264. typedef HANDLE mwMutex;
  265. #endif
  266. #if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
  267. typedef pthread_mutex_t mwMutex;
  268. #endif
  269. /***********************************************************************
  270. ** Static variables
  271. ***********************************************************************/
  272. static int mwInited = 0;
  273. static int mwInfoWritten = 0;
  274. static int mwUseAtexit = 0;
  275. static FILE* mwLog = NULL;
  276. static int mwFlushing = 0;
  277. static int mwStatLevel = MW_STAT_DEFAULT;
  278. static int mwNML = MW_NML_DEFAULT;
  279. static int mwFBI = 0;
  280. static long mwAllocLimit = 0L;
  281. static int mwUseLimit = 0;
  282. static long mwNumCurAlloc = 0L;
  283. static mwData* mwHead = NULL;
  284. static mwData* mwTail = NULL;
  285. static int mwDataSize = 0;
  286. static unsigned char mwOverflowZoneTemplate[] = "mEmwAtch";
  287. static int mwOverflowZoneSize = mwROUNDALLOC;
  288. static void (*mwOutFunction)(int) = NULL;
  289. static int (*mwAriFunction)(const char*) = NULL;
  290. static int mwAriAction = MW_ARI_ABORT;
  291. static char mwPrintBuf[MW_TRACE_BUFFER+8];
  292. static unsigned long mwCounter = 0L;
  293. static long mwErrors = 0L;
  294. static int mwTestFlags = 0;
  295. static int mwTestAlways = 0;
  296. static FILE* mwLogB1 = NULL;
  297. static int mwFlushingB1 = 0;
  298. static mwStat* mwStatList = NULL;
  299. static long mwStatTotAlloc = 0L;
  300. static long mwStatMaxAlloc = 0L;
  301. static long mwStatNumAlloc = 0L;
  302. static long mwStatCurAlloc = 0L;
  303. static long mwNmlNumAlloc = 0L;
  304. static long mwNmlCurAlloc = 0L;
  305. static mwGrabData* mwGrabList = NULL;
  306. static long mwGrabSize = 0L;
  307. static void * mwLastFree[MW_FREE_LIST];
  308. static const char *mwLFfile[MW_FREE_LIST];
  309. static int mwLFline[MW_FREE_LIST];
  310. static int mwLFcur = 0;
  311. static mwMarker* mwFirstMark = NULL;
  312. static FILE* mwLogB2 = NULL;
  313. static int mwFlushingB2 = 0;
  314. #ifdef MW_HAVE_MUTEX
  315. static mwMutex mwGlobalMutex;
  316. #endif
  317. /***********************************************************************
  318. ** Static function declarations
  319. ***********************************************************************/
  320. static void mwAutoInit( void );
  321. static FILE* mwLogR( void );
  322. static void mwLogW( FILE* );
  323. static int mwFlushR( void );
  324. static void mwFlushW( int );
  325. static void mwFlush( void );
  326. static void mwIncErr( void );
  327. static void mwUnlink( mwData*, const char* file, int line );
  328. static int mwRelink( mwData*, const char* file, int line );
  329. static int mwIsHeapOK( mwData *mw );
  330. static int mwIsOwned( mwData* mw, const char* file, int line );
  331. static int mwTestBuf( mwData* mw, const char* file, int line );
  332. static void mwDefaultOutFunc( int );
  333. static void mwWrite( const char* format, ... );
  334. static void mwLogFile( const char* name );
  335. static size_t mwFreeUp( size_t, int );
  336. static const void *mwTestMem( const void *, unsigned, int );
  337. static int mwStrCmpI( const char *s1, const char *s2 );
  338. static int mwTestNow( const char *file, int line, int always_invoked );
  339. static void mwDropAll( void );
  340. static const char *mwGrabType( int type );
  341. static unsigned mwGrab_( unsigned kb, int type, int silent );
  342. static unsigned mwDrop_( unsigned kb, int type, int silent );
  343. static int mwARI( const char* text );
  344. static void mwStatReport( void );
  345. static mwStat* mwStatGet( const char*, int, int );
  346. static void mwStatAlloc( size_t, const char*, int );
  347. static void mwStatFree( size_t, const char*, int );
  348. static int mwCheckOF( const void * p );
  349. static void mwWriteOF( void * p );
  350. static char mwDummy( char c );
  351. #ifdef MW_HAVE_MUTEX
  352. static void mwMutexInit( void );
  353. static void mwMutexTerm( void );
  354. static void mwMutexLock( void );
  355. static void mwMutexUnlock( void );
  356. #endif
  357. /***********************************************************************
  358. ** System functions
  359. ***********************************************************************/
  360. void mwInit( void ) {
  361. time_t tid;
  362. if( mwInited++ > 0 ) return;
  363. MW_MUTEX_INIT();
  364. /* start a log if none is running */
  365. if( mwLogR() == NULL ) mwLogFile( "memwatch.log" );
  366. if( mwLogR() == NULL ) {
  367. int i;
  368. char buf[32];
  369. /* oops, could not open it! */
  370. /* probably because it's already open */
  371. /* so we try some other names */
  372. for( i=1; i<100; i++ ) {
  373. sprintf( buf, "memwat%02d.log", i );
  374. mwLogFile( buf );
  375. if( mwLogR() != NULL ) break;
  376. }
  377. }
  378. /* initialize the statistics */
  379. mwStatList = NULL;
  380. mwStatTotAlloc = 0L;
  381. mwStatCurAlloc = 0L;
  382. mwStatMaxAlloc = 0L;
  383. mwStatNumAlloc = 0L;
  384. mwNmlCurAlloc = 0L;
  385. mwNmlNumAlloc = 0L;
  386. /* calculate the buffer size to use for a mwData */
  387. mwDataSize = sizeof(mwData);
  388. while( mwDataSize % mwROUNDALLOC ) mwDataSize ++;
  389. /* write informational header if needed */
  390. if( !mwInfoWritten ) {
  391. mwInfoWritten = 1;
  392. (void) time( &tid );
  393. mwWrite(
  394. "\n============="
  395. " MEMWATCH " VERSION " Copyright (C) 1992-1999 Johan Lindh "
  396. "=============\n");
  397. mwWrite( "\nStarted at %s\n", ctime( &tid ) );
  398. /**************************************************************** Generic */
  399. mwWrite( "Modes: " );
  400. #ifdef mwNew
  401. mwWrite( "C++ " );
  402. #endif /* mwNew */
  403. #ifdef __STDC__
  404. mwWrite( "__STDC__ " );
  405. #endif /* __STDC__ */
  406. #ifdef mw16BIT
  407. mwWrite( "16-bit " );
  408. #endif
  409. #ifdef mw32BIT
  410. mwWrite( "32-bit " );
  411. #endif
  412. #ifdef mw64BIT
  413. mwWrite( "64-bit " );
  414. #endif
  415. mwWrite( "mwDWORD==(" mwDWORD_DEFINED ")\n" );
  416. mwWrite( "mwROUNDALLOC==%d sizeof(mwData)==%d mwDataSize==%d\n",
  417. mwROUNDALLOC, sizeof(mwData), mwDataSize );
  418. /**************************************************************** Generic */
  419. /************************************************************ Microsoft C */
  420. #ifdef _MSC_VER
  421. mwWrite( "Compiled using Microsoft C" CPPTEXT
  422. " %d.%02d\n", _MSC_VER / 100, _MSC_VER % 100 );
  423. #endif /* _MSC_VER */
  424. /************************************************************ Microsoft C */
  425. /************************************************************** Borland C */
  426. #ifdef __BORLANDC__
  427. mwWrite( "Compiled using Borland C"
  428. #ifdef __cplusplus
  429. "++ %d.%01d\n", __BCPLUSPLUS__/0x100, (__BCPLUSPLUS__%0x100)/0x10 );
  430. #else
  431. " %d.%01d\n", __BORLANDC__/0x100, (__BORLANDC__%0x100)/0x10 );
  432. #endif /* __cplusplus */
  433. #endif /* __BORLANDC__ */
  434. /************************************************************** Borland C */
  435. /************************************************************** Watcom C */
  436. #ifdef __WATCOMC__
  437. mwWrite( "Compiled using Watcom C %d.%02d ",
  438. __WATCOMC__/100, __WATCOMC__%100 );
  439. #ifdef __FLAT__
  440. mwWrite( "(32-bit flat model)" );
  441. #endif /* __FLAT__ */
  442. mwWrite( "\n" );
  443. #endif /* __WATCOMC__ */
  444. /************************************************************** Watcom C */
  445. mwWrite( "\n" );
  446. FLUSH();
  447. }
  448. if( mwUseAtexit ) (void) atexit( mwAbort );
  449. return;
  450. }
  451. void mwAbort( void ) {
  452. mwData *mw;
  453. mwMarker *mrk;
  454. char *data;
  455. time_t tid;
  456. int c, i, j;
  457. int errors;
  458. tid = time( NULL );
  459. mwWrite( "\nStopped at %s\n", ctime( &tid) );
  460. if( !mwInited )
  461. mwWrite( "internal: mwAbort(): MEMWATCH not initialized!\n" );
  462. /* release the grab list */
  463. mwDropAll();
  464. /* report mwMarked items */
  465. while( mwFirstMark ) {
  466. mrk = mwFirstMark->next;
  467. mwWrite( "mark: %p: %s\n", mwFirstMark->host, mwFirstMark->text );
  468. free( mwFirstMark->text );
  469. free( mwFirstMark );
  470. mwFirstMark = mrk;
  471. mwErrors ++;
  472. }
  473. /* release all still allocated memory */
  474. errors = 0;
  475. while( mwHead != NULL && errors < 3 ) {
  476. if( !mwIsOwned(mwHead, __FILE__, __LINE__ ) ) {
  477. if( errors < 3 )
  478. {
  479. errors ++;
  480. mwWrite( "internal: NML/unfreed scan restarting\n" );
  481. FLUSH();
  482. mwHead = mwHead;
  483. continue;
  484. }
  485. mwWrite( "internal: NML/unfreed scan aborted, heap too damaged\n" );
  486. FLUSH();
  487. break;
  488. }
  489. mwFlushW(0);
  490. if( !(mwHead->flag & MW_NML) ) {
  491. mwErrors++;
  492. data = ((char*)mwHead)+mwDataSize;
  493. mwWrite( "unfreed: <%ld> %s(%d), %ld bytes at %p ",
  494. mwHead->count, mwHead->file, mwHead->line, (long)mwHead->size, data+mwOverflowZoneSize );
  495. if( mwCheckOF( data ) ) {
  496. mwWrite( "[underflowed] ");
  497. FLUSH();
  498. }
  499. if( mwCheckOF( (data+mwOverflowZoneSize+mwHead->size) ) ) {
  500. mwWrite( "[overflowed] ");
  501. FLUSH();
  502. }
  503. mwWrite( " \t{" );
  504. j = 16; if( mwHead->size < 16 ) j = (int) mwHead->size;
  505. for( i=0;i<16;i++ ) {
  506. if( i<j ) mwWrite( "%02X ",
  507. (unsigned char) *(data+mwOverflowZoneSize+i) );
  508. else mwWrite( ".. " );
  509. }
  510. for( i=0;i<j;i++ ) {
  511. c = *(data+mwOverflowZoneSize+i);
  512. if( c < 32 || c > 126 ) c = '.';
  513. mwWrite( "%c", c );
  514. }
  515. mwWrite( "}\n" );
  516. mw = mwHead;
  517. mwUnlink( mw, __FILE__, __LINE__ );
  518. free( mw );
  519. }
  520. else {
  521. data = ((char*)mwHead) + mwDataSize + mwOverflowZoneSize;
  522. if( mwTestMem( data, mwHead->size, MW_VAL_NML ) ) {
  523. mwErrors++;
  524. mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
  525. mwHead->count, data + mwOverflowZoneSize, mwHead->file, mwHead->line );
  526. FLUSH();
  527. }
  528. mwNmlNumAlloc --;
  529. mwNmlCurAlloc -= mwHead->size;
  530. mw = mwHead;
  531. mwUnlink( mw, __FILE__, __LINE__ );
  532. free( mw );
  533. }
  534. }
  535. if( mwNmlNumAlloc ) mwWrite("internal: NoMansLand block counter %ld, not zero\n", mwNmlNumAlloc );
  536. if( mwNmlCurAlloc ) mwWrite("internal: NoMansLand byte counter %ld, not zero\n", mwNmlCurAlloc );
  537. /* report statistics */
  538. mwStatReport();
  539. FLUSH();
  540. mwInited = 0;
  541. mwHead = mwTail = NULL;
  542. if( mwErrors )
  543. fprintf(mwSTDERR,"MEMWATCH detected %ld anomalies\n",mwErrors);
  544. mwLogFile( NULL );
  545. mwErrors = 0;
  546. MW_MUTEX_TERM();
  547. }
  548. void mwTerm( void ) {
  549. if( mwInited == 1 )
  550. {
  551. mwAbort();
  552. return;
  553. }
  554. if( !mwInited )
  555. mwWrite("internal: mwTerm(): MEMWATCH has not been started!\n");
  556. else
  557. mwInited --;
  558. }
  559. void mwStatistics( int level )
  560. {
  561. mwAutoInit();
  562. if( level<0 ) level=0;
  563. if( mwStatLevel != level )
  564. {
  565. mwWrite( "statistics: now collecting on a %s basis\n",
  566. level<1?"global":(level<2?"module":"line") );
  567. mwStatLevel = level;
  568. }
  569. }
  570. void mwAutoCheck( int onoff ) {
  571. mwAutoInit();
  572. mwTestAlways = onoff;
  573. if( onoff ) mwTestFlags = MW_TEST_ALL;
  574. }
  575. void mwSetOutFunc( void (*func)(int) ) {
  576. mwAutoInit();
  577. mwOutFunction = func;
  578. }
  579. static void mwWriteOF( void *p )
  580. {
  581. int i;
  582. unsigned char *ptr;
  583. ptr = (unsigned char*) p;
  584. for( i=0; i<mwOverflowZoneSize; i++ )
  585. {
  586. *(ptr+i) = mwOverflowZoneTemplate[i%8];
  587. }
  588. return;
  589. }
  590. static int mwCheckOF( const void *p )
  591. {
  592. int i;
  593. const unsigned char *ptr;
  594. ptr = (const unsigned char *) p;
  595. for( i=0; i<mwOverflowZoneSize; i++ )
  596. {
  597. if( *(ptr+i) != mwOverflowZoneTemplate[i%8] )
  598. return 1; /* errors found */
  599. }
  600. return 0; /* no errors */
  601. }
  602. int mwTest( const char *file, int line, int items ) {
  603. mwAutoInit();
  604. mwTestFlags = items;
  605. return mwTestNow( file, line, 0 );
  606. }
  607. /*
  608. ** Returns zero if there are no errors.
  609. ** Returns nonzero if there are errors.
  610. */
  611. int mwTestBuffer( const char *file, int line, void *p ) {
  612. mwData* mw;
  613. mwAutoInit();
  614. /* do the quick ownership test */
  615. mw = (mwData*) mwBUFFER_TO_MW( p );
  616. if( mwIsOwned( mw, file, line ) ) {
  617. return mwTestBuf( mw, file, line );
  618. }
  619. return 1;
  620. }
  621. void mwBreakOut( const char* cause ) {
  622. fprintf(mwSTDERR, "breakout: %s\n", cause);
  623. mwWrite("breakout: %s\n", cause );
  624. return;
  625. }
  626. /*
  627. ** 981217 JLI: is it possible that ->next is not always set?
  628. */
  629. void * mwMark( void *p, const char *desc, const char *file, unsigned line ) {
  630. mwMarker *mrk;
  631. unsigned n, isnew;
  632. char *buf;
  633. int tot, oflow = 0;
  634. char wherebuf[128];
  635. mwAutoInit();
  636. TESTS(NULL,0);
  637. if( desc == NULL ) desc = "unknown";
  638. if( file == NULL ) file = "unknown";
  639. tot = sprintf( wherebuf, "%.48s called from %s(%d)", desc, file, line );
  640. if( tot >= (int)sizeof(wherebuf) ) { wherebuf[sizeof(wherebuf)-1] = 0; oflow = 1; }
  641. if( p == NULL ) {
  642. mwWrite("mark: %s(%d), no mark for NULL:'%s' may be set\n", file, line, desc );
  643. return p;
  644. }
  645. if( mwFirstMark != NULL && !mwIsReadAddr( mwFirstMark, sizeof( mwMarker ) ) )
  646. {
  647. mwWrite("mark: %s(%d), mwFirstMark (%p) is trashed, can't mark for %s\n",
  648. file, line, mwFirstMark, desc );
  649. return p;
  650. }
  651. for( mrk=mwFirstMark; mrk; mrk=mrk->next )
  652. {
  653. if( mrk->next != NULL && !mwIsReadAddr( mrk->next, sizeof( mwMarker ) ) )
  654. {
  655. mwWrite("mark: %s(%d), mark(%p)->next(%p) is trashed, can't mark for %s\n",
  656. file, line, mrk, mrk->next, desc );
  657. return p;
  658. }
  659. if( mrk->host == p ) break;
  660. }
  661. if( mrk == NULL ) {
  662. isnew = 1;
  663. mrk = (mwMarker*) malloc( sizeof( mwMarker ) );
  664. if( mrk == NULL ) {
  665. mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc );
  666. return p;
  667. }
  668. mrk->next = NULL;
  669. n = 0;
  670. }
  671. else {
  672. isnew = 0;
  673. n = strlen( mrk->text );
  674. }
  675. n += strlen( wherebuf );
  676. buf = (char*) malloc( n+3 );
  677. if( buf == NULL ) {
  678. if( isnew ) free( mrk );
  679. mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc );
  680. return p;
  681. }
  682. if( isnew ) {
  683. memcpy( buf, wherebuf, n+1 );
  684. mrk->next = mwFirstMark;
  685. mrk->host = p;
  686. mrk->text = buf;
  687. mrk->level = 1;
  688. mwFirstMark = mrk;
  689. }
  690. else {
  691. strcpy( buf, mrk->text );
  692. strcat( buf, ", " );
  693. strcat( buf, wherebuf );
  694. free( mrk->text );
  695. mrk->text = buf;
  696. mrk->level ++;
  697. }
  698. if( oflow ) {
  699. mwIncErr();
  700. mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" );
  701. }
  702. return p;
  703. }
  704. void* mwUnmark( void *p, const char *file, unsigned line ) {
  705. mwMarker *mrk, *prv;
  706. mrk = mwFirstMark;
  707. prv = NULL;
  708. while( mrk ) {
  709. if( mrk->host == p ) {
  710. if( mrk->level < 2 ) {
  711. if( prv ) prv->next = mrk->next;
  712. else mwFirstMark = mrk->next;
  713. free( mrk->text );
  714. free( mrk );
  715. return p;
  716. }
  717. mrk->level --;
  718. return p;
  719. }
  720. prv = mrk;
  721. mrk = mrk->next;
  722. }
  723. mwWrite("mark: %s(%d), no mark found for %p\n", file, line, p );
  724. return p;
  725. }
  726. /***********************************************************************
  727. ** Abort/Retry/Ignore handlers
  728. ***********************************************************************/
  729. static int mwARI( const char *estr ) {
  730. char inbuf[81];
  731. int c;
  732. fprintf(mwSTDERR, "\n%s\nMEMWATCH: Abort, Retry or Ignore? ", estr);
  733. (void) fgets(inbuf,sizeof(inbuf),stdin);
  734. for( c=0; inbuf[c] && inbuf[c] <= ' '; c++ ) ;
  735. c = inbuf[c];
  736. if( c == 'R' || c == 'r' ) {
  737. mwBreakOut( estr );
  738. return MW_ARI_RETRY;
  739. }
  740. if( c == 'I' || c == 'i' ) return MW_ARI_IGNORE;
  741. return MW_ARI_ABORT;
  742. }
  743. /* standard ARI handler (exported) */
  744. int mwAriHandler( const char *estr ) {
  745. mwAutoInit();
  746. return mwARI( estr );
  747. }
  748. /* used to set the ARI function */
  749. void mwSetAriFunc( int (*func)(const char *) ) {
  750. mwAutoInit();
  751. mwAriFunction = func;
  752. }
  753. /***********************************************************************
  754. ** Allocation handlers
  755. ***********************************************************************/
  756. void* mwMalloc( size_t size, const char* file, int line) {
  757. size_t needed;
  758. mwData *mw;
  759. char *ptr;
  760. void *p;
  761. mwAutoInit();
  762. MW_MUTEX_LOCK();
  763. TESTS(file,line);
  764. mwCounter ++;
  765. needed = mwDataSize + mwOverflowZoneSize*2 + size;
  766. if( needed < size )
  767. {
  768. /* theoretical case: req size + mw overhead exceeded size_t limits */
  769. return NULL;
  770. }
  771. /* if this allocation would violate the limit, fail it */
  772. if( mwUseLimit && ((long)size + mwStatCurAlloc > mwAllocLimit) ) {
  773. mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n",
  774. mwCounter, file, line, (long)size, mwAllocLimit - mwStatCurAlloc );
  775. mwIncErr();
  776. FLUSH();
  777. MW_MUTEX_UNLOCK();
  778. return NULL;
  779. }
  780. mw = (mwData*) malloc( needed );
  781. if( mw == NULL ) {
  782. if( mwFreeUp(needed,0) >= needed ) {
  783. mw = (mwData*) malloc(needed);
  784. if( mw == NULL ) {
  785. mwWrite( "internal: mwFreeUp(%u) reported success, but malloc() fails\n", needed );
  786. mwIncErr();
  787. FLUSH();
  788. }
  789. }
  790. if( mw == NULL ) {
  791. mwWrite( "fail: <%ld> %s(%d), %ld wanted %ld allocated\n",
  792. mwCounter, file, line, (long)size, mwStatCurAlloc );
  793. mwIncErr();
  794. FLUSH();
  795. MW_MUTEX_UNLOCK();
  796. return NULL;
  797. }
  798. }
  799. mw->count = mwCounter;
  800. mw->prev = NULL;
  801. mw->next = mwHead;
  802. mw->file = file;
  803. mw->size = size;
  804. mw->line = line;
  805. mw->flag = 0;
  806. mw->check = CHKVAL(mw);
  807. if( mwHead ) mwHead->prev = mw;
  808. mwHead = mw;
  809. if( mwTail == NULL ) mwTail = mw;
  810. ptr = ((char*)mw) + mwDataSize;
  811. mwWriteOF( ptr ); /* '*(long*)ptr = PRECHK;' */
  812. ptr += mwOverflowZoneSize;
  813. p = ptr;
  814. memset( ptr, MW_VAL_NEW, size );
  815. ptr += size;
  816. mwWriteOF( ptr ); /* '*(long*)ptr = POSTCHK;' */
  817. mwNumCurAlloc ++;
  818. mwStatCurAlloc += (long) size;
  819. mwStatTotAlloc += (long) size;
  820. if( mwStatCurAlloc > mwStatMaxAlloc )
  821. mwStatMaxAlloc = mwStatCurAlloc;
  822. mwStatNumAlloc ++;
  823. if( mwStatLevel ) mwStatAlloc( size, file, line );
  824. MW_MUTEX_UNLOCK();
  825. return p;
  826. }
  827. void* mwRealloc( void *p, size_t size, const char* file, int line) {
  828. int oldUseLimit, i;
  829. mwData *mw;
  830. char *ptr;
  831. mwAutoInit();
  832. if( p == NULL ) return mwMalloc( size, file, line );
  833. if( size == 0 ) { mwFree( p, file, line ); return NULL; }
  834. MW_MUTEX_LOCK();
  835. /* do the quick ownership test */
  836. mw = (mwData*) mwBUFFER_TO_MW( p );
  837. if( mwIsOwned( mw, file, line ) ) {
  838. /* if the buffer is an NML, treat this as a double-free */
  839. if( mw->flag & MW_NML )
  840. {
  841. mwIncErr();
  842. if( *((unsigned char*)(mw)+mwDataSize+mwOverflowZoneSize) != MW_VAL_NML )
  843. {
  844. mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n",
  845. mwCounter, file, line, mw );
  846. }
  847. goto check_dbl_free;
  848. }
  849. /* if this allocation would violate the limit, fail it */
  850. if( mwUseLimit && ((long)size + mwStatCurAlloc - (long)mw->size > mwAllocLimit) ) {
  851. TESTS(file,line);
  852. mwCounter ++;
  853. mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n",
  854. mwCounter, file, line, (unsigned long)size - mw->size, mwAllocLimit - mwStatCurAlloc );
  855. mwIncErr();
  856. FLUSH();
  857. MW_MUTEX_UNLOCK();
  858. return NULL;
  859. }
  860. /* fake realloc operation */
  861. oldUseLimit = mwUseLimit;
  862. mwUseLimit = 0;
  863. ptr = (char*) mwMalloc( size, file, line );
  864. if( ptr != NULL ) {
  865. if( size < mw->size )
  866. memcpy( ptr, p, size );
  867. else
  868. memcpy( ptr, p, mw->size );
  869. mwFree( p, file, line );
  870. }
  871. mwUseLimit = oldUseLimit;
  872. MW_MUTEX_UNLOCK();
  873. return (void*) ptr;
  874. }
  875. /* Unknown pointer! */
  876. /* using free'd pointer? */
  877. check_dbl_free:
  878. for(i=0;i<MW_FREE_LIST;i++) {
  879. if( mwLastFree[i] == p ) {
  880. mwIncErr();
  881. mwWrite( "realloc: <%ld> %s(%d), %p was"
  882. " freed from %s(%d)\n",
  883. mwCounter, file, line, p,
  884. mwLFfile[i], mwLFline[i] );
  885. FLUSH();
  886. MW_MUTEX_UNLOCK();
  887. return NULL;
  888. }
  889. }
  890. /* some weird pointer */
  891. mwIncErr();
  892. mwWrite( "realloc: <%ld> %s(%d), unknown pointer %p\n",
  893. mwCounter, file, line, p );
  894. FLUSH();
  895. MW_MUTEX_UNLOCK();
  896. return NULL;
  897. }
  898. char *mwStrdup( const char* str, const char* file, int line ) {
  899. size_t len;
  900. char *newstring;
  901. MW_MUTEX_LOCK();
  902. if( str == NULL ) {
  903. mwIncErr();
  904. mwWrite( "strdup: <%ld> %s(%d), strdup(NULL) called\n",
  905. mwCounter, file, line );
  906. FLUSH();
  907. MW_MUTEX_UNLOCK();
  908. return NULL;
  909. }
  910. len = strlen( str ) + 1;
  911. newstring = (char*) mwMalloc( len, file, line );
  912. if( newstring != NULL ) memcpy( newstring, str, len );
  913. MW_MUTEX_UNLOCK();
  914. return newstring;
  915. }
  916. void mwFree( void* p, const char* file, int line ) {
  917. int i;
  918. mwData* mw;
  919. char buffer[ sizeof(mwData) + (mwROUNDALLOC*3) + 64 ];
  920. /* this code is in support of C++ delete */
  921. if( file == NULL ) {
  922. mwFree_( p );
  923. MW_MUTEX_UNLOCK();
  924. return;
  925. }
  926. mwAutoInit();
  927. MW_MUTEX_LOCK();
  928. TESTS(file,line);
  929. mwCounter ++;
  930. /* on NULL free, write a warning and return */
  931. if( p == NULL ) {
  932. mwWrite( "NULL free: <%ld> %s(%d), NULL pointer free'd\n",
  933. mwCounter, file, line );
  934. FLUSH();
  935. MW_MUTEX_UNLOCK();
  936. return;
  937. }
  938. /* do the quick ownership test */
  939. mw = (mwData*) mwBUFFER_TO_MW( p );
  940. if( mwIsOwned( mw, file, line ) ) {
  941. (void) mwTestBuf( mw, file, line );
  942. /* if the buffer is an NML, treat this as a double-free */
  943. if( mw->flag & MW_NML )
  944. {
  945. if( *(((unsigned char*)mw)+mwDataSize+mwOverflowZoneSize) != MW_VAL_NML )
  946. {
  947. mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n",
  948. mwCounter, file, line, mw );
  949. }
  950. goto check_dbl_free;
  951. }
  952. /* update the statistics */
  953. mwNumCurAlloc --;
  954. mwStatCurAlloc -= (long) mw->size;
  955. if( mwStatLevel ) mwStatFree( mw->size, mw->file, mw->line );
  956. /* we should either free the allocation or keep it as NML */
  957. if( mwNML ) {
  958. mw->flag |= MW_NML;
  959. mwNmlNumAlloc ++;
  960. mwNmlCurAlloc += (long) mw->size;
  961. memset( ((char*)mw)+mwDataSize+mwOverflowZoneSize, MW_VAL_NML, mw->size );
  962. }
  963. else {
  964. /* unlink the allocation, and enter the post-free data */
  965. mwUnlink( mw, file, line );
  966. memset( mw, MW_VAL_DEL,
  967. mw->size + mwDataSize+mwOverflowZoneSize+mwOverflowZoneSize );
  968. if( mwFBI ) {
  969. memset( mw, '.', mwDataSize + mwOverflowZoneSize );
  970. sprintf( buffer, "FBI<%ld>%s(%d)", mwCounter, file, line );
  971. strncpy( (char*)(void*)mw, buffer, mwDataSize + mwOverflowZoneSize );
  972. }
  973. free( mw );
  974. }
  975. /* add the pointer to the last-free track */
  976. mwLFfile[ mwLFcur ] = file;
  977. mwLFline[ mwLFcur ] = line;
  978. mwLastFree[ mwLFcur++ ] = p;
  979. if( mwLFcur == MW_FREE_LIST ) mwLFcur = 0;
  980. MW_MUTEX_UNLOCK();
  981. return;
  982. }
  983. /* check for double-freeing */
  984. check_dbl_free:
  985. for(i=0;i<MW_FREE_LIST;i++) {
  986. if( mwLastFree[i] == p ) {
  987. mwIncErr();
  988. mwWrite( "double-free: <%ld> %s(%d), %p was"
  989. " freed from %s(%d)\n",
  990. mwCounter, file, line, p,
  991. mwLFfile[i], mwLFline[i] );
  992. FLUSH();
  993. MW_MUTEX_UNLOCK();
  994. return;
  995. }
  996. }
  997. /* some weird pointer... block the free */
  998. mwIncErr();
  999. mwWrite( "WILD free: <%ld> %s(%d), unknown pointer %p\n",
  1000. mwCounter, file, line, p );
  1001. FLUSH();
  1002. MW_MUTEX_UNLOCK();
  1003. return;
  1004. }
  1005. void* mwCalloc( size_t a, size_t b, const char *file, int line ) {
  1006. void *p;
  1007. size_t size = a * b;
  1008. p = mwMalloc( size, file, line );
  1009. if( p == NULL ) return NULL;
  1010. memset( p, 0, size );
  1011. return p;
  1012. }
  1013. void mwFree_( void *p ) {
  1014. MW_MUTEX_LOCK();
  1015. TESTS(NULL,0);
  1016. MW_MUTEX_UNLOCK();
  1017. free(p);
  1018. }
  1019. void* mwMalloc_( size_t size ) {
  1020. MW_MUTEX_LOCK();
  1021. TESTS(NULL,0);
  1022. MW_MUTEX_UNLOCK();
  1023. return malloc( size );
  1024. }
  1025. void* mwRealloc_( void *p, size_t size ) {
  1026. MW_MUTEX_LOCK();
  1027. TESTS(NULL,0);
  1028. MW_MUTEX_UNLOCK();
  1029. return realloc( p, size );
  1030. }
  1031. void* mwCalloc_( size_t a, size_t b ) {
  1032. MW_MUTEX_LOCK();
  1033. TESTS(NULL,0);
  1034. MW_MUTEX_UNLOCK();
  1035. return calloc( a, b );
  1036. }
  1037. void mwFlushNow( void ) {
  1038. if( mwLogR() ) fflush( mwLogR() );
  1039. return;
  1040. }
  1041. void mwDoFlush( int onoff ) {
  1042. mwFlushW( onoff<1?0:onoff );
  1043. if( onoff ) if( mwLogR() ) fflush( mwLogR() );
  1044. return;
  1045. }
  1046. void mwLimit( long lim ) {
  1047. TESTS(NULL,0);
  1048. mwWrite("limit: old limit = ");
  1049. if( !mwAllocLimit ) mwWrite( "none" );
  1050. else mwWrite( "%ld bytes", mwAllocLimit );
  1051. mwWrite( ", new limit = ");
  1052. if( !lim ) {
  1053. mwWrite( "none\n" );
  1054. mwUseLimit = 0;
  1055. }
  1056. else {
  1057. mwWrite( "%ld bytes\n", lim );
  1058. mwUseLimit = 1;
  1059. }
  1060. mwAllocLimit = lim;
  1061. FLUSH();
  1062. }
  1063. void mwSetAriAction( int action ) {
  1064. MW_MUTEX_LOCK();
  1065. TESTS(NULL,0);
  1066. mwAriAction = action;
  1067. MW_MUTEX_UNLOCK();
  1068. return;
  1069. }
  1070. int mwAssert( int exp, const char *exps, const char *fn, int ln ) {
  1071. int i;
  1072. char buffer[MW_TRACE_BUFFER+8];
  1073. if( exp ) {
  1074. return 0;
  1075. }
  1076. mwAutoInit();
  1077. MW_MUTEX_LOCK();
  1078. TESTS(fn,ln);
  1079. mwIncErr();
  1080. mwCounter++;
  1081. mwWrite( "assert trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps );
  1082. if( mwAriFunction != NULL ) {
  1083. sprintf( buffer, "MEMWATCH: assert trap: %s(%d), %s", fn, ln, exps );
  1084. i = (*mwAriFunction)(buffer);
  1085. switch( i ) {
  1086. case MW_ARI_IGNORE:
  1087. mwWrite( "assert trap: <%ld> IGNORED - execution continues\n", mwCounter );
  1088. MW_MUTEX_UNLOCK();
  1089. return 0;
  1090. case MW_ARI_RETRY:
  1091. mwWrite( "assert trap: <%ld> RETRY - executing again\n", mwCounter );
  1092. MW_MUTEX_UNLOCK();
  1093. return 1;
  1094. }
  1095. }
  1096. else {
  1097. if( mwAriAction & MW_ARI_IGNORE ) {
  1098. mwWrite( "assert trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter );
  1099. MW_MUTEX_UNLOCK();
  1100. return 0;
  1101. }
  1102. fprintf(mwSTDERR,"\nMEMWATCH: assert trap: %s(%d), %s\n", fn, ln, exps );
  1103. }
  1104. FLUSH();
  1105. (void) mwTestNow( fn, ln, 1 );
  1106. FLUSH();
  1107. if( mwAriAction & MW_ARI_NULLREAD ) {
  1108. /* This is made in an attempt to kick in */
  1109. /* any debuggers or OS stack traces */
  1110. FLUSH();
  1111. /*lint -save -e413 */
  1112. i = *((int*)NULL);
  1113. mwDummy( (char)i );
  1114. /*lint -restore */
  1115. }
  1116. MW_MUTEX_UNLOCK();
  1117. exit(255);
  1118. /* NOT REACHED - the return statement is in to keep */
  1119. /* stupid compilers from squeaking about differing return modes. */
  1120. /* Smart compilers instead say 'code unreachable...' */
  1121. /*lint -save -e527 */
  1122. return 0;
  1123. /*lint -restore */
  1124. }
  1125. int mwVerify( int exp, const char *exps, const char *fn, int ln ) {
  1126. int i;
  1127. char buffer[MW_TRACE_BUFFER+8];
  1128. if( exp ) {
  1129. return 0;
  1130. }
  1131. mwAutoInit();
  1132. MW_MUTEX_LOCK();
  1133. TESTS(fn,ln);
  1134. mwIncErr();
  1135. mwCounter++;
  1136. mwWrite( "verify trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps );
  1137. if( mwAriFunction != NULL ) {
  1138. sprintf( buffer, "MEMWATCH: verify trap: %s(%d), %s", fn, ln, exps );
  1139. i = (*mwAriFunction)(buffer);
  1140. if( i == 0 ) {
  1141. mwWrite( "verify trap: <%ld> IGNORED - execution continues\n", mwCounter );
  1142. MW_MUTEX_UNLOCK();
  1143. return 0;
  1144. }
  1145. if( i == 1 ) {
  1146. mwWrite( "verify trap: <%ld> RETRY - executing again\n", mwCounter );
  1147. MW_MUTEX_UNLOCK();
  1148. return 1;
  1149. }
  1150. }
  1151. else {
  1152. if( mwAriAction & MW_ARI_NULLREAD ) {
  1153. /* This is made in an attempt to kick in */
  1154. /* any debuggers or OS stack traces */
  1155. FLUSH();
  1156. /*lint -save -e413 */
  1157. i = *((int*)NULL);
  1158. mwDummy( (char)i );
  1159. /*lint -restore */
  1160. }
  1161. if( mwAriAction & MW_ARI_IGNORE ) {
  1162. mwWrite( "verify trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter );
  1163. MW_MUTEX_UNLOCK();
  1164. return 0;
  1165. }
  1166. fprintf(mwSTDERR,"\nMEMWATCH: verify trap: %s(%d), %s\n", fn, ln, exps );
  1167. }
  1168. FLUSH();
  1169. (void) mwTestNow( fn, ln, 1 );
  1170. FLUSH();
  1171. MW_MUTEX_UNLOCK();
  1172. exit(255);
  1173. /* NOT REACHED - the return statement is in to keep */
  1174. /* stupid compilers from squeaking about differing return modes. */
  1175. /* Smart compilers instead say 'code unreachable...' */
  1176. /*lint -save -e527 */
  1177. return 0;
  1178. /*lint -restore */
  1179. }
  1180. void mwTrace( const char *format, ... ) {
  1181. int tot, oflow = 0;
  1182. va_list mark;
  1183. mwAutoInit();
  1184. MW_MUTEX_LOCK();
  1185. TESTS(NULL,0);
  1186. if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc;
  1187. va_start( mark, format );
  1188. tot = vsprintf( mwPrintBuf, format, mark );
  1189. va_end( mark );
  1190. if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; }
  1191. for(tot=0;mwPrintBuf[tot];tot++)
  1192. (*mwOutFunction)( mwPrintBuf[tot] );
  1193. if( oflow ) {
  1194. mwIncErr();
  1195. mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" );
  1196. }
  1197. FLUSH();
  1198. MW_MUTEX_UNLOCK();
  1199. }
  1200. /***********************************************************************
  1201. ** Grab & Drop
  1202. ***********************************************************************/
  1203. unsigned mwGrab( unsigned kb ) {
  1204. TESTS(NULL,0);
  1205. return mwGrab_( kb, MW_VAL_GRB, 0 );
  1206. }
  1207. unsigned mwDrop( unsigned kb ) {
  1208. TESTS(NULL,0);
  1209. return mwDrop_( kb, MW_VAL_GRB, 0 );
  1210. }
  1211. static void mwDropAll() {
  1212. TESTS(NULL,0);
  1213. (void) mwDrop_( 0, MW_VAL_GRB, 0 );
  1214. (void) mwDrop_( 0, MW_VAL_NML, 0 );
  1215. if( mwGrabList != NULL )
  1216. mwWrite( "internal: the grab list is not empty after mwDropAll()\n");
  1217. }
  1218. static const char *mwGrabType( int type ) {
  1219. switch( type ) {
  1220. case MW_VAL_GRB:
  1221. return "grabbed";
  1222. case MW_VAL_NML:
  1223. return "no-mans-land";
  1224. default:
  1225. /* do nothing */
  1226. ;
  1227. }
  1228. return "<unknown type>";
  1229. }
  1230. static unsigned mwGrab_( unsigned kb, int type, int silent ) {
  1231. unsigned i = kb;
  1232. mwGrabData *gd;
  1233. if( !kb ) i = kb = 65000U;
  1234. for(;kb;kb--) {
  1235. if( mwUseLimit &&
  1236. (mwStatCurAlloc + mwGrabSize + (long)sizeof(mwGrabData) > mwAllocLimit) ) {
  1237. if( !silent ) {
  1238. mwWrite("grabbed: all allowed memory to %s (%u kb)\n",
  1239. mwGrabType(type), i-kb);
  1240. FLUSH();
  1241. }
  1242. return i-kb;
  1243. }
  1244. gd = (mwGrabData*) malloc( sizeof(mwGrabData) );
  1245. if( gd == NULL ) {
  1246. if( !silent ) {
  1247. mwWrite("grabbed: all available memory to %s (%u kb)\n",
  1248. mwGrabType(type), i-kb);
  1249. FLUSH();
  1250. }
  1251. return i-kb;
  1252. }
  1253. mwGrabSize += (long) sizeof(mwGrabData);
  1254. gd->next = mwGrabList;
  1255. memset( gd->blob, type, sizeof(gd->blob) );
  1256. gd->type = type;
  1257. mwGrabList = gd;
  1258. }
  1259. if( !silent ) {
  1260. mwWrite("grabbed: %u kilobytes of %s memory\n", i, mwGrabType(type) );
  1261. FLUSH();
  1262. }
  1263. return i;
  1264. }
  1265. static unsigned mwDrop_( unsigned kb, int type, int silent ) {
  1266. unsigned i = kb;
  1267. mwGrabData *gd,*tmp,*pr;
  1268. const void *p;
  1269. if( mwGrabList == NULL && kb == 0 ) return 0;
  1270. if( !kb ) i = kb = 60000U;
  1271. pr = NULL;
  1272. gd = mwGrabList;
  1273. for(;kb;) {
  1274. if( gd == NULL ) {
  1275. if( i-kb > 0 && !silent ) {
  1276. mwWrite("dropped: all %s memory (%u kb)\n", mwGrabType(type), i-kb);
  1277. FLUSH();
  1278. }
  1279. return i-kb;
  1280. }
  1281. if( gd->type == type ) {
  1282. if( pr ) pr->next = gd->next;
  1283. kb --;
  1284. tmp = gd;
  1285. if( mwGrabList == gd ) mwGrabList = gd->next;
  1286. gd = gd->next;
  1287. p = mwTestMem( tmp->blob, sizeof( tmp->blob ), type );
  1288. if( p != NULL ) {
  1289. mwWrite( "wild pointer: <%ld> %s memory hit at %p\n",
  1290. mwCounter, mwGrabType(type), p );
  1291. FLUSH();
  1292. }
  1293. mwGrabSize -= (long) sizeof(mwGrabData);
  1294. free( tmp );
  1295. }
  1296. else {
  1297. pr = gd;
  1298. gd = gd->next;
  1299. }
  1300. }
  1301. if( !silent ) {
  1302. mwWrite("dropped: %u kilobytes of %s memory\n", i, mwGrabType(type) );
  1303. FLUSH();
  1304. }
  1305. return i;
  1306. }
  1307. /***********************************************************************
  1308. ** No-Mans-Land
  1309. ***********************************************************************/
  1310. void mwNoMansLand( int level ) {
  1311. mwAutoInit();
  1312. TESTS(NULL,0);
  1313. switch( level ) {
  1314. case MW_NML_NONE:
  1315. (void) mwDrop_( 0, MW_VAL_NML, 0 );
  1316. break;
  1317. case MW_NML_FREE:
  1318. break;
  1319. case MW_NML_ALL:
  1320. (void) mwGrab_( 0, MW_VAL_NML, 0 );
  1321. break;
  1322. default:
  1323. return;
  1324. }
  1325. mwNML = level;
  1326. }
  1327. /***********************************************************************
  1328. ** Static functions
  1329. ***********************************************************************/
  1330. static void mwAutoInit( void )
  1331. {
  1332. if( mwInited ) return;
  1333. mwUseAtexit = 1;
  1334. mwInit();
  1335. return;
  1336. }
  1337. static FILE *mwLogR() {
  1338. if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) return mwLog;
  1339. if( mwLog == mwLogB1 ) mwLogB2 = mwLog;
  1340. if( mwLog == mwLogB2 ) mwLogB1 = mwLog;
  1341. if( mwLogB1 == mwLogB2 ) mwLog = mwLogB1;
  1342. if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) {
  1343. mwWrite("internal: log file handle damaged and recovered\n");
  1344. FLUSH();
  1345. return mwLog;
  1346. }
  1347. fprintf(mwSTDERR,"\nMEMWATCH: log file handle destroyed, using mwSTDERR\n" );
  1348. mwLog = mwLogB1 = mwLogB2 = mwSTDERR;
  1349. return mwSTDERR;
  1350. }
  1351. static void mwLogW( FILE *p ) {
  1352. mwLog = mwLogB1 = mwLogB2 = p;
  1353. }
  1354. static int mwFlushR() {
  1355. if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) return mwFlushing;
  1356. if( mwFlushing == mwFlushingB1 ) mwFlushingB2 = mwFlushing;
  1357. if( mwFlushing == mwFlushingB2 ) mwFlushingB1 = mwFlushing;
  1358. if( mwFlushingB1 == mwFlushingB2 ) mwFlushing = mwFlushingB1;
  1359. if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) {
  1360. mwWrite("internal: flushing flag damaged and recovered\n");
  1361. FLUSH();
  1362. return mwFlushing;
  1363. }
  1364. mwWrite("internal: flushing flag destroyed, so set to true\n");
  1365. mwFlushing = mwFlushingB1 = mwFlushingB2 = 1;
  1366. return 1;
  1367. }
  1368. static void mwFlushW( int n ) {
  1369. mwFlushing = mwFlushingB1 = mwFlushingB2 = n;
  1370. }
  1371. static void mwIncErr() {
  1372. mwErrors++;
  1373. mwFlushW( mwFlushR()+1 );
  1374. FLUSH();
  1375. }
  1376. static void mwFlush() {
  1377. if( mwLogR() == NULL ) return;
  1378. #ifdef MW_FLUSH
  1379. fflush( mwLogR() );
  1380. #else
  1381. if( mwFlushR() ) fflush( mwLogR() );
  1382. #endif
  1383. return;
  1384. }
  1385. static void mwUnlink( mwData* mw, const char* file, int line ) {
  1386. if( mw->prev == NULL ) {
  1387. if( mwHead != mw )
  1388. mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 NULL, but not head\n",
  1389. mwCounter, file, line, mw );
  1390. mwHead = mw->next;
  1391. }
  1392. else {
  1393. if( mw->prev->next != mw )
  1394. mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 failure\n",
  1395. mwCounter, file, line, mw );
  1396. else mw->prev->next = mw->next;
  1397. }
  1398. if( mw->next == NULL ) {
  1399. if( mwTail != mw )
  1400. mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 NULL, but not tail\n",
  1401. mwCounter, file, line, mw );
  1402. mwTail = mw->prev;
  1403. }
  1404. else {
  1405. if( mw->next->prev != mw )
  1406. mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 failure\n",
  1407. mwCounter, file, line, mw );
  1408. else mw->next->prev = mw->prev;
  1409. }
  1410. }
  1411. /*
  1412. ** Relinking tries to repair a damaged mw block.
  1413. ** Returns nonzero if it thinks it successfully
  1414. ** repaired the heap chain.
  1415. */
  1416. static int mwRelink( mwData* mw, const char* file, int line ) {
  1417. int fails;
  1418. mwData *mw1, *mw2;
  1419. long count, size;
  1420. mwStat *ms;
  1421. if( file == NULL ) file = "unknown";
  1422. if( mw == NULL ) {
  1423. mwWrite("relink: cannot repair MW at NULL\n");
  1424. FLUSH();
  1425. goto emergency;
  1426. }
  1427. if( !mwIsSafeAddr(mw, mwDataSize) ) {
  1428. mwWrite("relink: MW-%p is a garbage pointer\n", mw);
  1429. FLUSH();
  1430. goto emergency;
  1431. }
  1432. mwWrite("relink: <%ld> %s(%d) attempting to repair MW-%p...\n", mwCounter, file, line, mw );
  1433. FLUSH();
  1434. fails = 0;
  1435. /* Repair from head */
  1436. if( mwHead != mw ) {
  1437. if( !mwIsSafeAddr( mwHead, mwDataSize ) ) {
  1438. mwWrite("relink: failed for MW-%p; head pointer destroyed\n", mw );
  1439. FLUSH();
  1440. goto emergency;
  1441. }
  1442. for( mw1=mwHead; mw1; mw1=mw1->next ) {
  1443. if( mw1->next == mw ) {
  1444. mw->prev = mw1;
  1445. break;
  1446. }
  1447. if( mw1->next &&
  1448. ( !mwIsSafeAddr(mw1->next, mwDataSize ) || mw1->next->prev != mw1) ) {
  1449. mwWrite("relink: failed for MW-%p; forward chain fragmented at MW-%p: 'next' is %p\n", mw, mw1, mw1->next );
  1450. FLUSH();
  1451. goto emergency;
  1452. }
  1453. }
  1454. if( mw1 == NULL ) {
  1455. mwWrite("relink: MW-%p not found in forward chain search\n", mw );
  1456. FLUSH();
  1457. fails ++;
  1458. }
  1459. }
  1460. else
  1461. {
  1462. mwWrite( "relink: MW-%p is the head (first) allocation\n", mw );
  1463. if( mw->prev != NULL )
  1464. {
  1465. mwWrite( "relink: MW-%p prev pointer is non-NULL, you have a wild pointer\n", mw );
  1466. mw->prev = NULL;
  1467. }
  1468. }
  1469. /* Repair from tail */
  1470. if( mwTail != mw ) {
  1471. if( !mwIsSafeAddr( mwTail, mwDataSize ) ) {
  1472. mwWrite("relink: failed for MW-%p; tail pointer destroyed\n", mw );
  1473. FLUSH();
  1474. goto emergency;
  1475. }
  1476. for( mw1=mwTail; mw1; mw1=mw1->prev ) {
  1477. if( mw1->prev == mw ) {
  1478. mw->next = mw1;
  1479. break;
  1480. }
  1481. if( mw1->prev && (!mwIsSafeAddr(mw1->prev, mwDataSize ) || mw1->prev->next != mw1) ) {
  1482. mwWrite("relink: failed for MW-%p; reverse chain fragmented at MW-%p, 'prev' is %p\n", mw, mw1, mw1->prev );
  1483. FLUSH();
  1484. goto emergency;
  1485. }
  1486. }
  1487. if( mw1 == NULL ) {
  1488. mwWrite("relink: MW-%p not found in reverse chain search\n", mw );
  1489. FLUSH();
  1490. fails ++;
  1491. }
  1492. }
  1493. else
  1494. {
  1495. mwWrite( "relink: MW-%p is the tail (last) allocation\n", mw );
  1496. if( mw->next != NULL )
  1497. {
  1498. mwWrite( "relink: MW-%p next pointer is non-NULL, you have a wild pointer\n", mw );
  1499. mw->next = NULL;
  1500. }
  1501. }
  1502. if( fails > 1 ) {
  1503. mwWrite("relink: heap appears intact, MW-%p probably garbage pointer\n", mw );
  1504. FLUSH();
  1505. goto verifyok;
  1506. }
  1507. /* restore MW info where possible */
  1508. if( mwIsReadAddr( mw->file, 1 ) ) {
  1509. ms = mwStatGet( mw->file, -1, 0 );
  1510. if( ms == NULL ) mw->file = "<relinked>";
  1511. }
  1512. mw->check = CHKVAL(mw);
  1513. goto verifyok;
  1514. /* Emergency repair */
  1515. emergency:
  1516. if( mwHead == NULL && mwTail == NULL )
  1517. {
  1518. if( mwStatCurAlloc == 0 )
  1519. mwWrite("relink: <%ld> %s(%d) heap is empty, nothing to repair\n", mwCounter, file, line );
  1520. else
  1521. mwWrite("relink: <%ld> %s(%d) heap damaged beyond repair\n", mwCounter, file, line );
  1522. FLUSH();
  1523. return 0;
  1524. }
  1525. mwWrite("relink: <%ld> %s(%d) attempting emergency repairs...\n", mwCounter, file, line );
  1526. FLUSH();
  1527. if( mwHead == NULL || mwTail == NULL )
  1528. {
  1529. if( mwHead == NULL ) mwWrite("relink: mwHead is NULL, but mwTail is %p\n", mwTail );
  1530. else mwWrite("relink: mwTail is NULL, but mwHead is %p\n", mwHead );
  1531. }
  1532. mw1=NULL;
  1533. if( mwHead != NULL )
  1534. {
  1535. if( !mwIsReadAddr( mwHead, mwDataSize ) || mwHead->check != CHKVAL(mwHead) )
  1536. {
  1537. mwWrite("relink: mwHead (MW-%p) is damaged, skipping forward scan\n", mwHead );
  1538. mwHead = NULL;
  1539. goto scan_reverse;
  1540. }
  1541. if( mwHead->prev != NULL )
  1542. {
  1543. mwWrite("relink: the mwHead pointer's 'prev' member is %p, not NULL\n", mwHead->prev );
  1544. }
  1545. for( mw1=mwHead; mw1; mw1=mw1->next )
  1546. {
  1547. if( mw1->next )
  1548. {
  1549. if( !mwIsReadAddr(mw1->next,mwDataSize) ||
  1550. !mw1->next->check != CHKVAL(mw1) ||
  1551. mw1->next->prev != mw1 )
  1552. {
  1553. mwWrite("relink: forward chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n",
  1554. mw1, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw1->file, mw1->line );
  1555. if( mwIsReadAddr(mw1->next,mwDataSize ) )
  1556. {
  1557. mwWrite("relink: forward chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n",
  1558. mw1->next, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"",
  1559. mwIsReadAddr(mw1->file,16)?mw1->file:"<garbage-pointer>", mw1->line );
  1560. }
  1561. else
  1562. {
  1563. mwWrite("relink: the 'next' pointer of this MW points to %p, which is out-of-legal-access\n",
  1564. mw1->next );
  1565. }
  1566. break;
  1567. }
  1568. }
  1569. }
  1570. }
  1571. scan_reverse:
  1572. mw2=NULL;
  1573. if( mwTail != NULL )
  1574. {
  1575. if( !mwIsReadAddr(mwTail,mwDataSize) || mwTail->check != CHKVAL(mwTail) )
  1576. {
  1577. mwWrite("relink: mwTail (%p) is damaged, skipping reverse scan\n", mwTail );
  1578. mwTail = NULL;
  1579. goto analyze;
  1580. }
  1581. if( mwTail->next != NULL )
  1582. {
  1583. mwWrite("relink: the mwTail pointer's 'next' member is %p, not NULL\n", mwTail->next );
  1584. }
  1585. for( mw2=mwTail; mw2; mw2=mw2->prev )
  1586. {
  1587. if( mw2->prev )
  1588. {
  1589. if( !mwIsReadAddr(mw2->prev,mwDataSize) ||
  1590. !mw2->prev->check != CHKVAL(mw2) ||
  1591. mw2->prev->next != mw2 )
  1592. {
  1593. mwWrite("relink: reverse chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n",
  1594. mw2, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw2->file, mw2->line );
  1595. if( mwIsReadAddr(mw2->prev,mwDataSize ) )
  1596. {
  1597. mwWrite("relink: reverse chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n",
  1598. mw2->prev, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"",
  1599. mwIsReadAddr(mw2->file,16)?mw2->file:"<garbage-pointer>", mw2->line );
  1600. }
  1601. else
  1602. {
  1603. mwWrite("relink: the 'prev' pointer of this MW points to %p, which is out-of-legal-access\n",
  1604. mw2->prev );
  1605. }
  1606. break;
  1607. }
  1608. }
  1609. }
  1610. }
  1611. analyze:
  1612. if( mwHead == NULL && mwTail == NULL )
  1613. {
  1614. mwWrite("relink: both head and tail pointers damaged, aborting program\n");
  1615. mwFlushW(1);
  1616. FLUSH();
  1617. abort();
  1618. }
  1619. if( mwHead == NULL )
  1620. {
  1621. mwHead = mw2;
  1622. mwWrite("relink: heap truncated, MW-%p designated as new mwHead\n", mw2 );
  1623. mw2->prev = NULL;
  1624. mw1 = mw2 = NULL;
  1625. }
  1626. if( mwTail == NULL )
  1627. {
  1628. mwTail = mw1;
  1629. mwWrite("relink: heap truncated, MW-%p designated as new mwTail\n", mw1 );
  1630. mw1->next = NULL;
  1631. mw1 = mw2 = NULL;
  1632. }
  1633. if( mw1 == NULL && mw2 == NULL &&
  1634. mwHead->prev == NULL && mwTail->next == NULL ) {
  1635. mwWrite("relink: verifying heap integrity...\n" );
  1636. FLUSH();
  1637. goto verifyok;
  1638. }
  1639. if( mw1 && mw2 && mw1 != mw2 ) {
  1640. mw1->next = mw2;
  1641. mw2->prev = mw1;
  1642. mwWrite("relink: emergency repairs successful, assessing damage...\n");
  1643. FLUSH();
  1644. }
  1645. else {
  1646. mwWrite("relink: heap totally destroyed, aborting program\n");
  1647. mwFlushW(1);
  1648. FLUSH();
  1649. abort();
  1650. }
  1651. /* Verify by checking that the number of active allocations */
  1652. /* match the number of entries in the chain */
  1653. verifyok:
  1654. if( !mwIsHeapOK( NULL ) ) {
  1655. mwWrite("relink: heap verification FAILS - aborting program\n");
  1656. mwFlushW(1);
  1657. FLUSH();
  1658. abort();
  1659. }
  1660. for( size=count=0, mw1=mwHead; mw1; mw1=mw1->next ) {
  1661. count ++;
  1662. size += (long) mw1->size;
  1663. }
  1664. if( count == mwNumCurAlloc ) {
  1665. mwWrite("relink: successful, ");
  1666. if( size == mwStatCurAlloc ) {
  1667. mwWrite("no allocations lost\n");
  1668. }
  1669. else {
  1670. if( mw != NULL ) {
  1671. mwWrite("size information lost for MW-%p\n", mw);
  1672. mw->size = 0;
  1673. }
  1674. }
  1675. }
  1676. else {
  1677. mwWrite("relink: partial, %ld MW-blocks of %ld bytes lost\n",
  1678. mwNmlNumAlloc+mwNumCurAlloc-count, mwNmlCurAlloc+mwStatCurAlloc-size );
  1679. return 0;
  1680. }
  1681. return 1;
  1682. }
  1683. /*
  1684. ** If mwData* is NULL:
  1685. ** Returns 0 if heap chain is broken.
  1686. ** Returns 1 if heap chain is intact.
  1687. ** If mwData* is not NULL:
  1688. ** Returns 0 if mwData* is missing or if chain is broken.
  1689. ** Returns 1 if chain is intact and mwData* is found.
  1690. */
  1691. static int mwIsHeapOK( mwData *includes_mw ) {
  1692. int found = 0;
  1693. mwData *mw;
  1694. for( mw = mwHead; mw; mw=mw->next ) {
  1695. if( includes_mw == mw ) found++;
  1696. if( !mwIsSafeAddr( mw, mwDataSize ) ) return 0;
  1697. if( mw->prev ) {
  1698. if( !mwIsSafeAddr( mw->prev, mwDataSize ) ) return 0;
  1699. if( mw==mwHead || mw->prev->next != mw ) return 0;
  1700. }
  1701. if( mw->next ) {
  1702. if( !mwIsSafeAddr( mw->next, mwDataSize ) ) return 0;
  1703. if( mw==mwTail || mw->next->prev != mw ) return 0;
  1704. }
  1705. else if( mw!=mwTail ) return 0;
  1706. }
  1707. if( includes_mw != NULL && !found ) return 0;
  1708. return 1;
  1709. }
  1710. static int mwIsOwned( mwData* mw, const char *file, int line ) {
  1711. int retv;
  1712. mwStat *ms;
  1713. /* see if the address is legal according to OS */
  1714. if( !mwIsSafeAddr( mw, mwDataSize ) ) return 0;
  1715. /* make sure we have _anything_ allocated */
  1716. if( mwHead == NULL && mwTail == NULL && mwStatCurAlloc == 0 )
  1717. return 0;
  1718. /* calculate checksum */
  1719. if( mw->check != CHKVAL(mw) ) {
  1720. /* may be damaged checksum, see if block is in heap */
  1721. if( mwIsHeapOK( mw ) ) {
  1722. /* damaged checksum, repair it */
  1723. mwWrite( "internal: <%ld> %s(%d), checksum for MW-%p is incorrect\n",
  1724. mwCounter, file, line, mw );
  1725. mwIncErr();
  1726. if( mwIsReadAddr( mw->file, 1 ) ) {
  1727. ms = mwStatGet( mw->file, -1, 0 );
  1728. if( ms == NULL ) mw->file = "<relinked>";
  1729. }
  1730. else mw->file = "<unknown>";
  1731. mw->size = 0;
  1732. mw->check = CHKVAL(mw);
  1733. return 1;
  1734. }
  1735. /* no, it's just some garbage data */
  1736. return 0;
  1737. }
  1738. /* check that the non-NULL pointers are safe */
  1739. if( mw->prev && !mwIsSafeAddr( mw->prev, mwDataSize ) ) mwRelink( mw, file, line );
  1740. if( mw->next && !mwIsSafeAddr( mw->next, mwDataSize ) ) mwRelink( mw, file, line );
  1741. /* safe address, checksum OK, proceed with heap checks */
  1742. /* see if the block is in the heap */
  1743. retv = 0;
  1744. if( mw->prev ) { if( mw->prev->next == mw ) retv ++; }
  1745. else { if( mwHead == mw ) retv++; }
  1746. if( mw->next ) { if( mw->next->prev == mw ) retv ++; }
  1747. else { if( mwTail == mw ) retv++; }
  1748. if( mw->check == CHKVAL(mw) ) retv ++;
  1749. if( retv > 2 ) return 1;
  1750. /* block not in heap, check heap for corruption */
  1751. if( !mwIsHeapOK( mw ) ) {
  1752. if( mwRelink( mw, file, line ) )
  1753. return 1;
  1754. }
  1755. /* unable to repair */
  1756. mwWrite( "internal: <%ld> %s(%d), mwIsOwned fails for MW-%p\n",
  1757. mwCounter, file, line, mw );
  1758. mwIncErr();
  1759. return 0;
  1760. }
  1761. /*
  1762. ** mwTestBuf:
  1763. ** Checks a buffers links and pre/postfixes.
  1764. ** Writes errors found to the log.
  1765. ** Returns zero if no errors found.
  1766. */
  1767. static int mwTestBuf( mwData* mw, const char* file, int line ) {
  1768. int retv = 0;
  1769. char *p;
  1770. if( file == NULL ) file = "unknown";
  1771. if( !mwIsSafeAddr( mw, mwDataSize + mwOverflowZoneSize ) ) {
  1772. mwWrite( "internal: <%ld> %s(%d): pointer MW-%p is invalid\n",
  1773. mwCounter, file, line, mw );
  1774. mwIncErr();
  1775. return 2;
  1776. }
  1777. if( mw->check != CHKVAL(mw) ) {
  1778. mwWrite( "internal: <%ld> %s(%d), info trashed; relinking\n",
  1779. mwCounter, file, line );
  1780. mwIncErr();
  1781. if( !mwRelink( mw, file, line ) ) return 2;
  1782. }
  1783. if( mw->prev && mw->prev->next != mw ) {
  1784. mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link1 broken\n",
  1785. mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
  1786. mwIncErr();
  1787. if( !mwRelink( mw, file, line ) ) retv = 2;
  1788. }
  1789. if( mw->next && mw->next->prev != mw ) {
  1790. mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link2 broken\n",
  1791. mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
  1792. mwIncErr();
  1793. if( !mwRelink( mw, file, line ) ) retv = 2;
  1794. }
  1795. p = ((char*)mw) + mwDataSize;
  1796. if( mwCheckOF( p ) ) {
  1797. mwWrite( "underflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n",
  1798. mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
  1799. mwIncErr();
  1800. retv = 1;
  1801. }
  1802. p += mwOverflowZoneSize + mw->size;
  1803. if( mwIsReadAddr( p, mwOverflowZoneSize ) && mwCheckOF( p ) ) {
  1804. mwWrite( "overflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n",
  1805. mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line );
  1806. mwIncErr();
  1807. retv = 1;
  1808. }
  1809. return retv;
  1810. }
  1811. static void mwDefaultOutFunc( int c ) {
  1812. if( mwLogR() ) fputc( c, mwLogR() );
  1813. }
  1814. static void mwWrite( const char *format, ... ) {
  1815. int tot, oflow = 0;
  1816. va_list mark;
  1817. mwAutoInit();
  1818. if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc;
  1819. va_start( mark, format );
  1820. tot = vsprintf( mwPrintBuf, format, mark );
  1821. va_end( mark );
  1822. if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; }
  1823. for(tot=0;mwPrintBuf[tot];tot++)
  1824. (*mwOutFunction)( mwPrintBuf[tot] );
  1825. if( oflow ) {
  1826. mwWrite( "\ninternal: mwWrite(): WARNING! OUTPUT EXCEEDED %u CHARS: SYSTEM UNSTABLE\n", MW_TRACE_BUFFER-1 );
  1827. FLUSH();
  1828. }
  1829. return;
  1830. }
  1831. static void mwLogFile( const char *name ) {
  1832. time_t tid;
  1833. (void) time( &tid );
  1834. if( mwLogR() != NULL ) {
  1835. fclose( mwLogR() );
  1836. mwLogW( NULL );
  1837. }
  1838. if( name == NULL ) return;
  1839. mwLogW( fopen( name, "a" COMMIT ) );
  1840. if( mwLogR() == NULL )
  1841. mwWrite( "logfile: failed to open/create file '%s'\n", name );
  1842. }
  1843. /*
  1844. ** Try to free NML memory until a contiguous allocation of
  1845. ** 'needed' bytes can be satisfied. If this is not enough
  1846. ** and the 'urgent' parameter is nonzero, grabbed memory is
  1847. ** also freed.
  1848. */
  1849. static size_t mwFreeUp( size_t needed, int urgent ) {
  1850. void *p;
  1851. mwData *mw, *mw2;
  1852. char *data;
  1853. /* free grabbed NML memory */
  1854. for(;;) {
  1855. if( mwDrop_( 1, MW_VAL_NML, 1 ) == 0 ) break;
  1856. p = malloc( needed );
  1857. if( p == NULL ) continue;
  1858. free( p );
  1859. return needed;
  1860. }
  1861. /* free normal NML memory */
  1862. mw = mwHead;
  1863. while( mw != NULL ) {
  1864. if( !(mw->flag & MW_NML) ) mw = mw->next;
  1865. else {
  1866. data = ((char*)mw)+mwDataSize+mwOverflowZoneSize;
  1867. if( mwTestMem( data, mw->size, MW_VAL_NML ) ) {
  1868. mwIncErr();
  1869. mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
  1870. mw->count, data + mwOverflowZoneSize, mw->file, mw->line );
  1871. }
  1872. mw2 = mw->next;
  1873. mwUnlink( mw, "mwFreeUp", 0 );
  1874. free( mw );
  1875. mw = mw2;
  1876. p = malloc( needed );
  1877. if( p == NULL ) continue;
  1878. free( p );
  1879. return needed;
  1880. }
  1881. }
  1882. /* if not urgent (for internal purposes), fail */
  1883. if( !urgent ) return 0;
  1884. /* free grabbed memory */
  1885. for(;;) {
  1886. if( mwDrop_( 1, MW_VAL_GRB, 1 ) == 0 ) break;
  1887. p = malloc( needed );
  1888. if( p == NULL ) continue;
  1889. free( p );
  1890. return needed;
  1891. }
  1892. return 0;
  1893. }
  1894. static const void * mwTestMem( const void *p, unsigned len, int c ) {
  1895. const unsigned char *ptr;
  1896. ptr = (const unsigned char *) p;
  1897. while( len-- ) {
  1898. if( *ptr != (unsigned char)c ) return (const void*)ptr;
  1899. ptr ++;
  1900. }
  1901. return NULL;
  1902. }
  1903. static int mwStrCmpI( const char *s1, const char *s2 ) {
  1904. if( s1 == NULL || s2 == NULL ) return 0;
  1905. while( *s1 ) {
  1906. if( toupper(*s2) == toupper(*s1) ) { s1++; s2++; continue; }
  1907. return 1;
  1908. }
  1909. return 0;
  1910. }
  1911. #define AIPH() if( always_invoked ) { mwWrite("autocheck: <%ld> %s(%d) ", mwCounter, file, line ); always_invoked = 0; }
  1912. static int mwTestNow( const char *file, int line, int always_invoked ) {
  1913. int retv = 0;
  1914. mwData *mw;
  1915. char *data;
  1916. if( file && !always_invoked )
  1917. mwWrite("check: <%ld> %s(%d), checking %s%s%s\n",
  1918. mwCounter, file, line,
  1919. (mwTestFlags & MW_TEST_CHAIN) ? "chain ": "",
  1920. (mwTestFlags & MW_TEST_ALLOC) ? "alloc ": "",
  1921. (mwTestFlags & MW_TEST_NML) ? "nomansland ": ""
  1922. );
  1923. if( mwTestFlags & MW_TEST_CHAIN ) {
  1924. for( mw = mwHead; mw; mw=mw->next ) {
  1925. if( !mwIsSafeAddr(mw, mwDataSize) ) {
  1926. AIPH();
  1927. mwWrite("check: heap corruption detected\n");
  1928. mwIncErr();
  1929. return retv + 1;
  1930. }
  1931. if( mw->prev ) {
  1932. if( !mwIsSafeAddr(mw->prev, mwDataSize) ) {
  1933. AIPH();
  1934. mwWrite("check: heap corruption detected\n");
  1935. mwIncErr();
  1936. return retv + 1;
  1937. }
  1938. if( mw==mwHead || mw->prev->next != mw ) {
  1939. AIPH();
  1940. mwWrite("check: heap chain broken, prev link incorrect\n");
  1941. mwIncErr();
  1942. retv ++;
  1943. }
  1944. }
  1945. if( mw->next ) {
  1946. if( !mwIsSafeAddr(mw->next, mwDataSize) ) {
  1947. AIPH();
  1948. mwWrite("check: heap corruption detected\n");
  1949. mwIncErr();
  1950. return retv + 1;
  1951. }
  1952. if( mw==mwTail || mw->next->prev != mw ) {
  1953. AIPH();
  1954. mwWrite("check: heap chain broken, next link incorrect\n");
  1955. mwIncErr();
  1956. retv ++;
  1957. }
  1958. }
  1959. else if( mw!=mwTail ) {
  1960. AIPH();
  1961. mwWrite("check: heap chain broken, tail incorrect\n");
  1962. mwIncErr();
  1963. retv ++;
  1964. }
  1965. }
  1966. }
  1967. if( mwTestFlags & MW_TEST_ALLOC ) {
  1968. for( mw = mwHead; mw; mw=mw->next ) {
  1969. if( mwTestBuf( mw, file, line ) ) retv ++;
  1970. }
  1971. }
  1972. if( mwTestFlags & MW_TEST_NML ) {
  1973. for( mw = mwHead; mw; mw=mw->next ) {
  1974. if( (mw->flag & MW_NML) ) {
  1975. data = ((char*)mw)+mwDataSize+mwOverflowZoneSize;
  1976. if( mwTestMem( data, mw->size, MW_VAL_NML ) ) {
  1977. mwIncErr();
  1978. mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n",
  1979. mw->count, data + mwOverflowZoneSize, mw->file, mw->line );
  1980. }
  1981. }
  1982. }
  1983. }
  1984. if( file && !always_invoked && !retv )
  1985. mwWrite("check: <%ld> %s(%d), complete; no errors\n",
  1986. mwCounter, file, line );
  1987. return retv;
  1988. }
  1989. /**********************************************************************
  1990. ** Statistics
  1991. **********************************************************************/
  1992. static void mwStatReport()
  1993. {
  1994. mwStat* ms, *ms2;
  1995. const char *modname;
  1996. int modnamelen;
  1997. /* global statistics report */
  1998. mwWrite( "\nMemory usage statistics (global):\n" );
  1999. mwWrite( " N)umber of allocations made: %ld\n", mwStatNumAlloc );
  2000. mwWrite( " L)argest memory usage : %ld\n", mwStatMaxAlloc );
  2001. mwWrite( " T)otal of all alloc() calls: %ld\n", mwStatTotAlloc );
  2002. mwWrite( " U)nfreed bytes totals : %ld\n", mwStatCurAlloc );
  2003. FLUSH();
  2004. if( mwStatLevel < 1 ) return;
  2005. /* on a per-module basis */
  2006. mwWrite( "\nMemory usage statistics (detailed):\n");
  2007. mwWrite( " Module/Line Number Largest Total Unfreed \n");
  2008. for( ms=mwStatList; ms; ms=ms->next )
  2009. {
  2010. if( ms->line == -1 )
  2011. {
  2012. if( ms->file == NULL || !mwIsReadAddr(ms->file,22) ) modname = "<unknown>";
  2013. else modname = ms->file;
  2014. modnamelen = strlen(modname);
  2015. if( modnamelen > 42 )
  2016. {
  2017. modname = modname + modnamelen - 42;
  2018. }
  2019. mwWrite(" %-42s %-8ld %-8ld %-8ld %-8ld\n",
  2020. modname, ms->num, ms->max, ms->total, ms->curr );
  2021. if( ms->file && mwStatLevel > 1 )
  2022. {
  2023. for( ms2=mwStatList; ms2; ms2=ms2->next )
  2024. {
  2025. if( ms2->line!=-1 && ms2->file!=NULL && !mwStrCmpI( ms2->file, ms->file ) )
  2026. {
  2027. mwWrite( " %-8d %-8ld %-8ld %-8ld %-8ld\n",
  2028. ms2->line, ms2->num, ms2->max, ms2->total, ms2->curr );
  2029. }
  2030. }
  2031. }
  2032. }
  2033. }
  2034. }
  2035. static mwStat* mwStatGet( const char *file, int line, int makenew ) {
  2036. mwStat* ms;
  2037. if( mwStatLevel < 2 ) line = -1;
  2038. for( ms=mwStatList; ms!=NULL; ms=ms->next ) {
  2039. if( line != ms->line ) continue;
  2040. if( file==NULL ) {
  2041. if( ms->file == NULL ) break;
  2042. continue;
  2043. }
  2044. if( ms->file == NULL ) continue;
  2045. if( !strcmp( ms->file, file ) ) break;
  2046. }
  2047. if( ms != NULL ) return ms;
  2048. if( !makenew ) return NULL;
  2049. ms = (mwStat*) malloc( sizeof(mwStat) );
  2050. if( ms == NULL ) {
  2051. if( mwFreeUp( sizeof(mwStat), 0 ) < sizeof(mwStat) ||
  2052. (ms=(mwStat*)malloc(sizeof(mwStat))) == NULL ) {
  2053. mwWrite("internal: memory low, statistics incomplete for '%s'\n", file );
  2054. return NULL;
  2055. }
  2056. }
  2057. ms->file = file;
  2058. ms->line = line;
  2059. ms->total = 0L;
  2060. ms->max = 0L;
  2061. ms->num = 0L;
  2062. ms->curr = 0L;
  2063. ms->next = mwStatList;
  2064. mwStatList = ms;
  2065. return ms;
  2066. }
  2067. static void mwStatAlloc( size_t size, const char* file, int line ) {
  2068. mwStat* ms;
  2069. /* update the module statistics */
  2070. ms = mwStatGet( file, -1, 1 );
  2071. if( ms != NULL ) {
  2072. ms->total += (long) size;
  2073. ms->curr += (long) size;
  2074. ms->num ++;
  2075. if( ms->curr > ms->max ) ms->max = ms->curr;
  2076. }
  2077. /* update the line statistics */
  2078. if( mwStatLevel > 1 && line != -1 && file ) {
  2079. ms = mwStatGet( file, line, 1 );
  2080. if( ms != NULL ) {
  2081. ms->total += (long) size;
  2082. ms->curr += (long) size;
  2083. ms->num ++;
  2084. if( ms->curr > ms->max ) ms->max = ms->curr;
  2085. }
  2086. }
  2087. }
  2088. static void mwStatFree( size_t size, const char* file, int line ) {
  2089. mwStat* ms;
  2090. /* update the module statistics */
  2091. ms = mwStatGet( file, -1, 1 );
  2092. if( ms != NULL ) ms->curr -= (long) size;
  2093. /* update the line statistics */
  2094. if( mwStatLevel > 1 && line != -1 && file ) {
  2095. ms = mwStatGet( file, line, 1 );
  2096. if( ms != NULL ) ms->curr -= (long) size;
  2097. }
  2098. }
  2099. /***********************************************************************
  2100. ** Safe memory checkers
  2101. **
  2102. ** Using ifdefs, implement the operating-system specific mechanism
  2103. ** of identifying a piece of memory as legal to access with read
  2104. ** and write priviliges. Default: return nonzero for non-NULL pointers.
  2105. ***********************************************************************/
  2106. static char mwDummy( char c )
  2107. {
  2108. return c;
  2109. }
  2110. #ifndef MW_SAFEADDR
  2111. #ifdef WIN32
  2112. #define MW_SAFEADDR
  2113. #define WIN32_LEAN_AND_MEAN
  2114. #include <windows.h>
  2115. int mwIsReadAddr( const void *p, unsigned len )
  2116. {
  2117. if( p == NULL ) return 0;
  2118. if( IsBadReadPtr(p,len) ) return 0;
  2119. return 1;
  2120. }
  2121. int mwIsSafeAddr( void *p, unsigned len )
  2122. {
  2123. /* NOTE: For some reason, under Win95 the IsBad... */
  2124. /* can return false for invalid pointers. */
  2125. if( p == NULL ) return 0;
  2126. if( IsBadReadPtr(p,len) || IsBadWritePtr(p,len) ) return 0;
  2127. return 1;
  2128. }
  2129. #endif /* WIN32 */
  2130. #endif /* MW_SAFEADDR */
  2131. #ifndef MW_SAFEADDR
  2132. #ifdef SIGSEGV
  2133. #define MW_SAFEADDR
  2134. typedef void (*mwSignalHandlerPtr)( int );
  2135. mwSignalHandlerPtr mwOldSIGSEGV = (mwSignalHandlerPtr) 0;
  2136. jmp_buf mwSIGSEGVjump;
  2137. static void mwSIGSEGV( int n );
  2138. static void mwSIGSEGV( int n )
  2139. {
  2140. n = n;
  2141. longjmp( mwSIGSEGVjump, 1 );
  2142. }
  2143. int mwIsReadAddr( const void *p, unsigned len )
  2144. {
  2145. const char *ptr;
  2146. if( p == NULL ) return 0;
  2147. if( !len ) return 1;
  2148. /* set up to catch the SIGSEGV signal */
  2149. mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV );
  2150. if( setjmp( mwSIGSEGVjump ) )
  2151. {
  2152. signal( SIGSEGV, mwOldSIGSEGV );
  2153. return 0;
  2154. }
  2155. /* read all the bytes in the range */
  2156. ptr = (const char *)p;
  2157. ptr += len;
  2158. /* the reason for this rather strange construct is that */
  2159. /* we want to keep the number of used parameters and locals */
  2160. /* to a minimum. if we use len for a counter gcc will complain */
  2161. /* it may get clobbered by longjmp() at high warning levels. */
  2162. /* it's a harmless warning, but this way we don't have to see it. */
  2163. do
  2164. {
  2165. ptr --;
  2166. if( *ptr == 0x7C ) (void) mwDummy( (char)0 );
  2167. } while( (const void*) ptr != p );
  2168. /* remove the handler */
  2169. signal( SIGSEGV, mwOldSIGSEGV );
  2170. return 1;
  2171. }
  2172. int mwIsSafeAddr( void *p, unsigned len )
  2173. {
  2174. char *ptr;
  2175. if( p == NULL ) return 0;
  2176. if( !len ) return 1;
  2177. /* set up to catch the SIGSEGV signal */
  2178. mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV );
  2179. if( setjmp( mwSIGSEGVjump ) )
  2180. {
  2181. signal( SIGSEGV, mwOldSIGSEGV );
  2182. return 0;
  2183. }
  2184. /* read and write-back all the bytes in the range */
  2185. ptr = (char *)p;
  2186. ptr += len;
  2187. /* the reason for this rather strange construct is that */
  2188. /* we want to keep the number of used parameters and locals */
  2189. /* to a minimum. if we use len for a counter gcc will complain */
  2190. /* it may get clobbered by longjmp() at high warning levels. */
  2191. /* it's a harmless warning, but this way we don't have to see it. */
  2192. do
  2193. {
  2194. ptr --;
  2195. *ptr = mwDummy( *ptr );
  2196. } while( (void*) ptr != p );
  2197. /* remove the handler */
  2198. signal( SIGSEGV, mwOldSIGSEGV );
  2199. return 1;
  2200. }
  2201. #endif /* SIGSEGV */
  2202. #endif /* MW_SAFEADDR */
  2203. #ifndef MW_SAFEADDR
  2204. int mwIsReadAddr( const void *p, unsigned len )
  2205. {
  2206. if( p == NULL ) return 0;
  2207. if( len == 0 ) return 1;
  2208. return 1;
  2209. }
  2210. int mwIsSafeAddr( void *p, unsigned len )
  2211. {
  2212. if( p == NULL ) return 0;
  2213. if( len == 0 ) return 1;
  2214. return 1;
  2215. }
  2216. #endif
  2217. /**********************************************************************
  2218. ** Mutex handling
  2219. **********************************************************************/
  2220. #if defined(WIN32) || defined(__WIN32__)
  2221. static void mwMutexInit( void )
  2222. {
  2223. mwGlobalMutex = CreateMutex( NULL, FALSE, NULL);
  2224. return;
  2225. }
  2226. static void mwMutexTerm( void )
  2227. {
  2228. CloseHandle( mwGlobalMutex );
  2229. return;
  2230. }
  2231. static void mwMutexLock( void )
  2232. {
  2233. if( WaitForSingleObject(mwGlobalMutex, 1000 ) == WAIT_TIMEOUT )
  2234. {
  2235. mwWrite( "mwMutexLock: timed out, possible deadlock\n" );
  2236. }
  2237. return;
  2238. }
  2239. static void mwMutexUnlock( void )
  2240. {
  2241. ReleaseMutex( mwGlobalMutex );
  2242. return;
  2243. }
  2244. #endif
  2245. #if defined(MW_PTHREADS) || defined(HAVE_PTHREAD_H)
  2246. static void mwMutexInit( void )
  2247. {
  2248. pthread_mutex_init( &mwGlobalMutex, NULL );
  2249. return;
  2250. }
  2251. static void mwMutexTerm( void )
  2252. {
  2253. pthread_mutex_destroy( &mwGlobalMutex );
  2254. return;
  2255. }
  2256. static void mwMutexLock( void )
  2257. {
  2258. pthread_mutex_lock(&mwGlobalMutex);
  2259. return;
  2260. }
  2261. static void mwMutexUnlock( void )
  2262. {
  2263. pthread_mutex_unlock(&mwGlobalMutex);
  2264. return;
  2265. }
  2266. #endif
  2267. /**********************************************************************
  2268. ** C++ new & delete
  2269. **********************************************************************/
  2270. #if 0 /* 980317: disabled C++ */
  2271. #ifdef __cplusplus
  2272. #ifndef MEMWATCH_NOCPP
  2273. int mwNCur = 0;
  2274. const char *mwNFile = NULL;
  2275. int mwNLine = 0;
  2276. class MemWatch {
  2277. public:
  2278. MemWatch();
  2279. ~MemWatch();
  2280. };
  2281. MemWatch::MemWatch() {
  2282. if( mwInited ) return;
  2283. mwUseAtexit = 0;
  2284. mwInit();
  2285. }
  2286. MemWatch::~MemWatch() {
  2287. if( mwUseAtexit ) return;
  2288. mwTerm();
  2289. }
  2290. /*
  2291. ** This global new will catch all 'new' calls where MEMWATCH is
  2292. ** not active.
  2293. */
  2294. void* operator new( unsigned size ) {
  2295. mwNCur = 0;
  2296. return mwMalloc( size, "<unknown>", 0 );
  2297. }
  2298. /*
  2299. ** This is the new operator that's called when a module uses mwNew.
  2300. */
  2301. void* operator new( unsigned size, const char *file, int line ) {
  2302. mwNCur = 0;
  2303. return mwMalloc( size, file, line );
  2304. }
  2305. /*
  2306. ** This is the new operator that's called when a module uses mwNew[].
  2307. ** -- hjc 07/16/02
  2308. */
  2309. void* operator new[] ( unsigned size, const char *file, int line ) {
  2310. mwNCur = 0;
  2311. return mwMalloc( size, file, line );
  2312. }
  2313. /*
  2314. ** Since this delete operator will recieve ALL delete's
  2315. ** even those from within libraries, we must accept
  2316. ** delete's before we've been initialized. Nor can we
  2317. ** reliably check for wild free's if the mwNCur variable
  2318. ** is not set.
  2319. */
  2320. void operator delete( void *p ) {
  2321. if( p == NULL ) return;
  2322. if( !mwInited ) {
  2323. free( p );
  2324. return;
  2325. }
  2326. if( mwNCur ) {
  2327. mwFree( p, mwNFile, mwNLine );
  2328. mwNCur = 0;
  2329. return;
  2330. }
  2331. mwFree_( p );
  2332. }
  2333. void operator delete[]( void *p ) {
  2334. if( p == NULL ) return;
  2335. if( !mwInited ) {
  2336. free( p );
  2337. return;
  2338. }
  2339. if( mwNCur ) {
  2340. mwFree( p, mwNFile, mwNLine );
  2341. mwNCur = 0;
  2342. return;
  2343. }
  2344. mwFree_( p );
  2345. }
  2346. #endif /* MEMWATCH_NOCPP */
  2347. #endif /* __cplusplus */
  2348. #endif /* 980317: disabled C++ */
  2349. /* MEMWATCH.C */