Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

562 lines
14 KiB

  1. /*************************************************************************
  2. * Microsoft Windows NT *
  3. * *
  4. * Copyright(c) Microsoft Corp., 1994 *
  5. * *
  6. * Revision History: *
  7. * *
  8. * Jan. 24,94 Koti Created *
  9. * *
  10. * Description: *
  11. * *
  12. * This file contains debug support routines for the LPD Service. *
  13. * This file is based on (in fact, borrowed and then modified) on the *
  14. * debug.c in the ftpsvc module. *
  15. * *
  16. *************************************************************************/
  17. #include <stdio.h>
  18. #include "lpd.h"
  19. #if DBG
  20. //
  21. // Private constants.
  22. //
  23. #define LPD_OUT_FILE "lpdout.log"
  24. #define LPD_ERR_FILE "lpderr.log"
  25. #define MAX_PRINTF_OUTPUT 1024 // characters
  26. #define LPD_OUTPUT_LABEL "LPDSVC"
  27. #define DEBUG_HEAP 0 // enable/disable heap debugging
  28. //
  29. // Private globals.
  30. //
  31. FILE * pErrFile; // Debug output log file.
  32. FILE * pOutFile; // Debug output log file.
  33. BOOL fFirstTimeErr=TRUE;
  34. BOOL fFirstTimeOut=TRUE;
  35. //
  36. // every LocalAlloc gets linked to this list and LocalFree gets unlinked
  37. // (so that we can catch any memory leaks!)
  38. //
  39. LIST_ENTRY DbgMemList;
  40. //
  41. // synchronization for DbgMemList
  42. //
  43. CRITICAL_SECTION CS;
  44. //
  45. // Public functions.
  46. //
  47. /*******************************************************************
  48. NAME: DbgInit
  49. SYNOPSIS: Peforms initialization for debug memory allocator
  50. ENTRY: void
  51. HISTORY:
  52. Frankbee 05-Jun-1996 Created.
  53. ********************************************************************/
  54. VOID
  55. DbgInit()
  56. {
  57. InitializeCriticalSection( &CS );
  58. }
  59. /*******************************************************************
  60. NAME: DbgUninit
  61. SYNOPSIS: Peforms cleanup for debug memory allocator
  62. ENTRY: void
  63. HISTORY:
  64. Frankbee 05-Jun-1996 Created.
  65. ********************************************************************/
  66. VOID
  67. DbgUninit()
  68. {
  69. DeleteCriticalSection( &CS );
  70. }
  71. //
  72. // Public functions.
  73. //
  74. /*******************************************************************
  75. NAME: LpdAssert
  76. SYNOPSIS: Called if an assertion fails. Displays the failed
  77. assertion, file name, and line number. Gives the
  78. user the opportunity to ignore the assertion or
  79. break into the debugger.
  80. ENTRY: pAssertion - The text of the failed expression.
  81. pFileName - The containing source file.
  82. nLineNumber - The guilty line number.
  83. HISTORY:
  84. KeithMo 07-Mar-1993 Created.
  85. ********************************************************************/
  86. VOID
  87. LpdAssert( VOID * pAssertion,
  88. VOID * pFileName,
  89. ULONG nLineNumber
  90. )
  91. {
  92. RtlAssert( pAssertion, pFileName, nLineNumber, NULL );
  93. } // LpdAssert
  94. /*******************************************************************
  95. NAME: LpdPrintf
  96. SYNOPSIS: Customized debug output routine.
  97. ENTRY: Usual printf-style parameters.
  98. HISTORY:
  99. KeithMo 07-Mar-1993 Created.
  100. ********************************************************************/
  101. VOID
  102. LpdPrintf(
  103. CHAR * pszFormat,
  104. ...
  105. )
  106. {
  107. CHAR szOutput[MAX_PRINTF_OUTPUT];
  108. DWORD dwErrcode;
  109. va_list ArgList;
  110. DWORD cchOutputLength;
  111. PSTR pszErrorBuffer;
  112. dwErrcode = GetLastError();
  113. sprintf( szOutput,
  114. "%s (%lu): ",
  115. LPD_OUTPUT_LABEL,
  116. GetCurrentThreadId() );
  117. va_start( ArgList, pszFormat );
  118. vsprintf( szOutput + strlen(szOutput), pszFormat, ArgList );
  119. va_end( ArgList );
  120. cchOutputLength = FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM + FORMAT_MESSAGE_ALLOCATE_BUFFER,
  121. NULL,
  122. dwErrcode,
  123. 0,
  124. (LPTSTR)&pszErrorBuffer,
  125. 1,
  126. NULL
  127. );
  128. if ( cchOutputLength == 0 )
  129. {
  130. sprintf( szOutput + strlen(szOutput), " Error = %ld\n",dwErrcode);
  131. pszErrorBuffer = NULL;
  132. }
  133. else
  134. {
  135. pszErrorBuffer[ cchOutputLength - 1 ] = '\0';
  136. sprintf( szOutput + strlen(szOutput),
  137. " Error = %ld (%s)\n",
  138. dwErrcode,
  139. pszErrorBuffer );
  140. }
  141. if ( pszErrorBuffer != NULL )
  142. {
  143. //
  144. // Why is "LocalFree" in parentheses? Because LocalFree might be #define'd
  145. // to a debugging function, but pszErrorBuffer was LocalAlloc()'d with the
  146. // normal function. The parens prevent macro expansion and guarantee that
  147. // we call the real LocalFree() function.
  148. //
  149. (LocalFree)( pszErrorBuffer );
  150. }
  151. if( pErrFile == NULL )
  152. {
  153. if ( fFirstTimeErr )
  154. {
  155. pErrFile = fopen( LPD_ERR_FILE, "w+" );
  156. fFirstTimeErr = FALSE;
  157. }
  158. else
  159. pErrFile = fopen( LPD_ERR_FILE, "a+" );
  160. }
  161. if( pErrFile != NULL )
  162. {
  163. fputs( szOutput, pErrFile );
  164. fflush( pErrFile );
  165. }
  166. } // LpdPrintf
  167. /*******************************************************************
  168. NAME: StripPath
  169. SYNOPSIS: Given a fully qualified filename, returns the filename
  170. sans path
  171. ENTRY: char *szPath - filename, possibly including path
  172. RETURNS: filename
  173. HISTORY:
  174. Frankbee 6/18/96 Created.
  175. ********************************************************************/
  176. char *
  177. StripPath( char *szPath )
  178. {
  179. char *p;
  180. p = szPath + strlen( szPath );
  181. while( p != szPath && *p != '\\' )
  182. p--;
  183. if ( *p == '\\' )
  184. ++p;
  185. return p;
  186. }
  187. /*******************************************************************
  188. NAME: DbgDumpLeaks
  189. SYNOPSIS: Checks DbgMemList for memory that wasn't deallocated.
  190. For each leaked block, the following is written to
  191. the error log:
  192. - Filename
  193. - Line #
  194. - Requested Size
  195. ENTRY: VOID
  196. RETURNS: VOID
  197. HISTORY:
  198. Frankbee 6/18/96 Created
  199. ********************************************************************/
  200. void
  201. DbgDumpLeaks()
  202. {
  203. LIST_ENTRY *p = DbgMemList.Flink;
  204. if ( IsListEmpty( &DbgMemList ) )
  205. return; // no leaks
  206. LPD_DEBUG("DbgDumpLeaks: memory leaks detected:\n");
  207. while ( p != &DbgMemList )
  208. {
  209. DbgMemBlkHdr *pHdr = (DbgMemBlkHdr*) p;
  210. LpdPrintf( "%s, line %d: %d byte block\n", pHdr->szFile, pHdr->dwLine,
  211. pHdr->ReqSize );
  212. p = p->Flink;
  213. }
  214. LPD_ASSERT(0);
  215. }
  216. /*******************************************************************
  217. NAME: DbgAllocMem
  218. SYNOPSIS: Keep track of all allocated memory so we can catch
  219. memory leak when we unload
  220. This is only on debug builds. On non-debug builds
  221. this function doesn't exist: calls directly go to
  222. LocalAlloc
  223. ENTRY: pscConn - connection which is requesting memory
  224. flag - whatever flags are passed in
  225. ReqSize - how much memory is needed
  226. RETURNS: PVOID - pointer to the memory block that client will
  227. use directly.
  228. HISTORY:
  229. Koti 3-Dec-1994 Created.
  230. ********************************************************************/
  231. //
  232. // IMPORTANT: we are undef'ing LocalAlloc because we need to make a
  233. // call to the actual function here!. That's why
  234. // this function and this undef are at the end of the file.
  235. //
  236. #undef LocalAlloc
  237. PVOID
  238. DbgAllocMem( PSOCKCONN pscConn,
  239. DWORD flag,
  240. DWORD ReqSize,
  241. DWORD dwLine,
  242. char *szFile
  243. )
  244. {
  245. DWORD ActualSize;
  246. PVOID pBuffer;
  247. DbgMemBlkHdr *pMemHdr;
  248. PVOID pRetAddr;
  249. ActualSize = ReqSize + sizeof(DbgMemBlkHdr);
  250. pBuffer = LocalAlloc( flag, ActualSize );
  251. if ( !pBuffer )
  252. {
  253. LPD_DEBUG("DbgAllocMem: couldn't allocate memory: returning!\n");
  254. return( NULL );
  255. }
  256. pMemHdr = (DbgMemBlkHdr *)pBuffer;
  257. pMemHdr->Verify = DBG_MEMALLOC_VERIFY;
  258. pMemHdr->ReqSize = ReqSize;
  259. pMemHdr->dwLine = dwLine;
  260. strncpy( pMemHdr->szFile, StripPath( szFile ), DBG_MAXFILENAME );
  261. pMemHdr->szFile[ DBG_MAXFILENAME - 1 ] = '\0';
  262. pMemHdr->Owner[0] = (DWORD_PTR)pscConn;
  263. //
  264. // for private builds on x86 machines, remove the #if 0
  265. // (this code saves stack trace as to exactly who allocated memory)
  266. //
  267. #if 0
  268. pRetAddr = &pMemHdr->Owner[0];
  269. _asm
  270. {
  271. push ebx
  272. push ecx
  273. push edx
  274. mov ebx, pRetAddr
  275. mov eax, ebp
  276. mov edx, dword ptr [eax+4] ; return address
  277. mov dword ptr [ebx], edx
  278. mov eax, dword ptr [eax] ; previous frame pointer
  279. pop edx
  280. pop ecx
  281. pop ebx
  282. }
  283. #endif
  284. InitializeListHead(&pMemHdr->Linkage);
  285. EnterCriticalSection( &CS );
  286. InsertTailList(&DbgMemList, &pMemHdr->Linkage);
  287. LeaveCriticalSection( &CS );
  288. return( (PCHAR)pBuffer + sizeof(DbgMemBlkHdr) );
  289. }
  290. /*******************************************************************
  291. NAME: DbgReAllocMem
  292. SYNOPSIS: Keep track of all allocated memory so we can catch
  293. memory leak when we unload
  294. This is only on debug builds. On non-debug builds
  295. this function doesn't exist: calls directly go to
  296. LocalReAlloc
  297. ENTRY: pscConn - connection which is requesting memory
  298. pPartBuf - the originally allocated buffer
  299. ReqSize - how much memory is needed
  300. flag - whatever flags are passed in
  301. RETURNS: PVOID - pointer to the memory block that client will
  302. use directly.
  303. HISTORY:
  304. Koti 3-Dec-1994 Created.
  305. ********************************************************************/
  306. //
  307. // IMPORTANT: we are undef'ing LocalReAlloc because we need to make a
  308. // call to the actual function here!. That's why
  309. // this function and this undef are at the end of the file.
  310. //
  311. #undef LocalReAlloc
  312. PVOID
  313. DbgReAllocMem(
  314. PSOCKCONN pscConn,
  315. PVOID pPartBuf,
  316. DWORD ReqSize,
  317. DWORD flag,
  318. DWORD dwLine,
  319. char *szFile
  320. )
  321. {
  322. DbgMemBlkHdr *pMemHdr;
  323. PVOID pRetAddr;
  324. if ( !pPartBuf )
  325. {
  326. LPD_DEBUG("DbgReAllocMem: invalid memory: returning!\n");
  327. return( NULL );
  328. }
  329. pMemHdr = (DbgMemBlkHdr *)((PCHAR)pPartBuf - sizeof(DbgMemBlkHdr));
  330. if( pMemHdr->Verify != DBG_MEMALLOC_VERIFY )
  331. {
  332. LPD_DEBUG("DbgReAllocMem: invalid memory being realloced: returning!\n");
  333. return( NULL );
  334. }
  335. EnterCriticalSection( &CS );
  336. RemoveEntryList(&pMemHdr->Linkage);
  337. LeaveCriticalSection( &CS );
  338. pMemHdr = LocalReAlloc((PCHAR)pMemHdr, ReqSize+sizeof(DbgMemBlkHdr), flag);
  339. if ( !pMemHdr )
  340. {
  341. LPD_DEBUG("DbgReAllocMem: LocalReAlloc failed: returning!\n");
  342. return( NULL );
  343. }
  344. pMemHdr->Verify = DBG_MEMALLOC_VERIFY;
  345. pMemHdr->ReqSize = ReqSize;
  346. pMemHdr->dwLine = dwLine;
  347. strncpy( pMemHdr->szFile, StripPath( szFile ), DBG_MAXFILENAME );
  348. pMemHdr->szFile[ DBG_MAXFILENAME - 1 ] = '\0';
  349. pMemHdr->Owner[0] = (DWORD_PTR)pscConn;
  350. //
  351. // for private builds on x86 machines, remove the #if 0
  352. // (this code saves stack trace as to exactly who allocated memory)
  353. //
  354. #if 0
  355. pRetAddr = &pMemHdr->Owner[0];
  356. _asm
  357. {
  358. push ebx
  359. push ecx
  360. push edx
  361. mov ebx, pRetAddr
  362. mov eax, ebp
  363. mov edx, dword ptr [eax+4] ; return address
  364. mov dword ptr [ebx], edx
  365. mov eax, dword ptr [eax] ; previous frame pointer
  366. pop edx
  367. pop ecx
  368. pop ebx
  369. }
  370. #endif
  371. InitializeListHead(&pMemHdr->Linkage);
  372. EnterCriticalSection( &CS );
  373. InsertTailList(&DbgMemList, &pMemHdr->Linkage);
  374. LeaveCriticalSection( &CS );
  375. return( (PCHAR)pMemHdr + sizeof(DbgMemBlkHdr) );
  376. }
  377. /*******************************************************************
  378. NAME: DbgFreeMem
  379. SYNOPSIS: This routine removes the memory block from our list and
  380. frees the memory by calling the CTE function CTEFreeMem
  381. ENTRY: pBufferToFree - memory to free (caller's buffer)
  382. RETURNS: nothing
  383. HISTORY:
  384. Koti 11-Nov-1994 Created.
  385. ********************************************************************/
  386. //
  387. // IMPORTANT: we are undef'ing CTEFreeMem because we need to make a
  388. // call to the actual CTE function CTEFreeMem. That's why
  389. // this function and this undef are at the end of the file.
  390. //
  391. #undef LocalFree
  392. VOID
  393. DbgFreeMem( PVOID pBufferToFree )
  394. {
  395. DbgMemBlkHdr *pMemHdr;
  396. if ( !pBufferToFree )
  397. {
  398. return;
  399. }
  400. pMemHdr = (DbgMemBlkHdr *)((PCHAR)pBufferToFree - sizeof(DbgMemBlkHdr));
  401. if( pMemHdr->Verify != DBG_MEMALLOC_VERIFY )
  402. {
  403. LPD_DEBUG("DbgFreeMem: attempt to free invalid memory: returning!\n");
  404. LPD_ASSERT(0);
  405. return;
  406. }
  407. //
  408. // change our signature: if we are freeing some memory twice, we'll know!
  409. //
  410. pMemHdr->Verify -= 1;
  411. EnterCriticalSection( &CS );
  412. RemoveEntryList(&pMemHdr->Linkage);
  413. LeaveCriticalSection( &CS );
  414. LocalFree( (PVOID)pMemHdr );
  415. }
  416. #endif // DBG