Leaked source code of windows server 2003
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.

719 lines
20 KiB

  1. /*****************************************************************************
  2. *
  3. * Assert.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Assertions and squirties.
  10. *
  11. * Contents:
  12. *
  13. * SquirtSqflPtszV
  14. * AssertPtszPtszLn
  15. * ArgsPalPszV
  16. * EnterSqflPszPal
  17. * ExitSqflPalHresPpv
  18. *
  19. *****************************************************************************/
  20. #include "dinputpr.h"
  21. #ifdef XDEBUG
  22. /*****************************************************************************
  23. *
  24. * WarnPszV
  25. *
  26. * Display a message, suitable for framing.
  27. *
  28. *****************************************************************************/
  29. #pragma BEGIN_CONST_DATA
  30. CHAR c_szPrefix[] = "DINPUT: ";
  31. #pragma END_CONST_DATA
  32. void EXTERNAL
  33. WarnPszV(LPCSTR ptsz, ...)
  34. {
  35. va_list ap;
  36. CHAR sz[1024];
  37. lstrcpyA(sz, c_szPrefix);
  38. va_start(ap, ptsz);
  39. #ifdef WIN95
  40. {
  41. char *psz = NULL;
  42. char szDfs[1024]={0};
  43. strcpy(szDfs,ptsz); // make a local copy of format string
  44. while (psz = strstr(szDfs,"%p")) // find each %p
  45. *(psz+1) = 'x'; // replace each %p with %x
  46. wvsprintfA(sz + cA(c_szPrefix) - 1, szDfs, ap); // use the local format string
  47. }
  48. #else
  49. {
  50. wvsprintfA(sz + cA(c_szPrefix) - 1, ptsz, ap);
  51. }
  52. #endif
  53. va_end(ap);
  54. lstrcatA(sz, "\r\n");
  55. OutputDebugStringA(sz);
  56. }
  57. #endif
  58. #ifdef DEBUG
  59. /*****************************************************************************
  60. *
  61. * Globals
  62. *
  63. *****************************************************************************/
  64. BYTE g_rgbSqfl[sqflMaxArea];
  65. extern TCHAR g_tszLogFile[];
  66. /*****************************************************************************
  67. *
  68. * Sqfl_Init
  69. *
  70. * Load our initial Sqfl settings from win.ini[debug].
  71. *
  72. * We take one sqfl for each area, of the form
  73. *
  74. * dinput.n=v
  75. *
  76. * where n = 0, ..., sqflMaxArea-1, and where v is one of the
  77. * hiword sqfl values.
  78. *
  79. * The default value for all areas is to squirt only errors.
  80. *
  81. *****************************************************************************/
  82. void EXTERNAL
  83. Sqfl_Init(void)
  84. {
  85. int sqfl;
  86. TCHAR tsz[20];
  87. sqfl = 0x0;
  88. wsprintf(tsz, TEXT("dinput"));
  89. g_rgbSqfl[sqfl] = (BYTE)
  90. GetProfileInt(TEXT("DEBUG"), tsz, HIWORD(0x0));
  91. for (sqfl = 0; sqfl < sqflMaxArea; sqfl++) {
  92. wsprintf(tsz, TEXT("dinput.%d"), sqfl);
  93. g_rgbSqfl[sqfl] = (BYTE)
  94. GetProfileInt(TEXT("DEBUG"), tsz, g_rgbSqfl[0]);
  95. }
  96. }
  97. /*****************************************************************************
  98. *
  99. * SquirtPtsz
  100. *
  101. * Squirt a message to the debugger and maybe a log file.
  102. *
  103. *****************************************************************************/
  104. void INTERNAL
  105. SquirtPtsz(LPCTSTR ptsz)
  106. {
  107. OutputDebugString(ptsz);
  108. if (g_tszLogFile[0]) {
  109. HANDLE h = CreateFile(g_tszLogFile, GENERIC_WRITE,
  110. FILE_SHARE_READ | FILE_SHARE_WRITE,
  111. 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  112. if (h != INVALID_HANDLE_VALUE) {
  113. #ifdef UNICODE
  114. CHAR szBuf[1024];
  115. #endif
  116. SetFilePointer(h, 0, 0, FILE_END);
  117. #ifdef UNICODE
  118. _lwrite((HFILE)(UINT_PTR)h, szBuf, UToA(szBuf, cA(szBuf), ptsz));
  119. #else
  120. _lwrite((HFILE)(UINT_PTR)h, ptsz, cbCtch(lstrlen(ptsz)));
  121. #endif
  122. CloseHandle(h);
  123. }
  124. }
  125. }
  126. /*****************************************************************************
  127. *
  128. * SquirtPtszA
  129. *
  130. * Squirt an ANSI message to the debugger and maybe a log file.
  131. *
  132. *****************************************************************************/
  133. #ifdef UNICODE
  134. void INTERNAL
  135. SquirtPtszA(LPCSTR psz)
  136. {
  137. OutputDebugStringA(psz);
  138. if (g_tszLogFile[0]) {
  139. HANDLE h = CreateFile(g_tszLogFile, GENERIC_WRITE,
  140. FILE_SHARE_READ | FILE_SHARE_WRITE,
  141. 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  142. if (h != INVALID_HANDLE_VALUE) {
  143. _lwrite((HFILE)(UINT_PTR)h, psz, cbCch(lstrlenA(psz)));
  144. CloseHandle(h);
  145. }
  146. }
  147. }
  148. #else
  149. #define SquirtPtszA SquirtPtsz
  150. #endif
  151. /*****************************************************************************
  152. *
  153. * SquirtSqflPtszV
  154. *
  155. * Squirt a message with a trailing crlf.
  156. *
  157. *****************************************************************************/
  158. void EXTERNAL
  159. SquirtSqflPtszV(SQFL sqfl, LPCTSTR ptsz, ...)
  160. {
  161. if (IsSqflSet(sqfl)) {
  162. va_list ap;
  163. TCHAR tsz[1024];
  164. va_start(ap, ptsz);
  165. #ifdef WIN95
  166. {
  167. char *psz = NULL;
  168. char szDfs[1024]={0};
  169. strcpy(szDfs,ptsz); // make a local copy of format string
  170. while (psz = strstr(szDfs,"%p")) // find each %p
  171. *(psz+1) = 'x'; // replace each %p with %x
  172. wvsprintf(tsz, szDfs, ap); // use the local format string
  173. }
  174. #else
  175. {
  176. wvsprintf(tsz, ptsz, ap);
  177. }
  178. #endif
  179. va_end(ap);
  180. lstrcat(tsz, TEXT("\r\n"));
  181. SquirtPtsz(tsz);
  182. }
  183. }
  184. /*****************************************************************************
  185. *
  186. * AssertPtszPtszLn
  187. *
  188. * Something bad happened.
  189. *
  190. *****************************************************************************/
  191. int EXTERNAL
  192. AssertPtszPtszLn(LPCTSTR ptszExpr, LPCTSTR ptszFile, int iLine)
  193. {
  194. SquirtSqflPtszV(sqflAlways, TEXT("Assertion failed: `%s' at %s(%d)"),
  195. ptszExpr, ptszFile, iLine);
  196. DebugBreak();
  197. return 0;
  198. }
  199. /*****************************************************************************
  200. *
  201. * Procedure call tracing is gross because of the C preprocessor.
  202. *
  203. * Oh, if only we had support for m4...
  204. *
  205. *****************************************************************************/
  206. /*****************************************************************************
  207. *
  208. * dwSafeGetPdw
  209. *
  210. * Deference a dword, but don't barf if the dword is bad.
  211. *
  212. *****************************************************************************/
  213. DWORD INTERNAL
  214. dwSafeGetPdw(LPDWORD pdw)
  215. {
  216. if (IsBadReadPtr(pdw, cbX(*pdw))) {
  217. return 0xBAADBAAD;
  218. } else {
  219. return *pdw;
  220. }
  221. }
  222. /*****************************************************************************
  223. *
  224. * ArgsPszV
  225. *
  226. * Collect arguments to a procedure.
  227. *
  228. * psz -> ASCIIZ format string
  229. * ... = argument list
  230. *
  231. * The characters in the format string are listed in EmitPal.
  232. *
  233. *****************************************************************************/
  234. void EXTERNAL
  235. ArgsPalPszV(PARGLIST pal, LPCSTR psz, ...)
  236. {
  237. va_list ap;
  238. va_start(ap, psz);
  239. if (psz) {
  240. PPV ppv;
  241. pal->pszFormat = psz;
  242. for (ppv = pal->rgpv; *psz; psz++) {
  243. *ppv++ = va_arg(ap, PV);
  244. }
  245. } else {
  246. pal->pszFormat = "";
  247. }
  248. }
  249. /*****************************************************************************
  250. *
  251. * EmitPal
  252. *
  253. * OutputDebugString the information, given a pal. No trailing
  254. * carriage return is emitted.
  255. *
  256. * pal -> place where info was saved
  257. *
  258. * Format characters:
  259. *
  260. * p - 32-bit flat pointer
  261. * x - 32-bit hex integer
  262. * s - TCHAR string
  263. * S - SCHAR string
  264. * A - ANSI string
  265. * W - UNICODE string
  266. * G - GUID
  267. * u - unsigned integer
  268. * C - clipboard format
  269. *
  270. *****************************************************************************/
  271. void INTERNAL
  272. EmitPal(PARGLIST pal)
  273. {
  274. char sz[MAX_PATH];
  275. int i;
  276. SquirtPtszA(pal->pszProc);
  277. SquirtPtsz(TEXT("("));
  278. for (i = 0; pal->pszFormat[i]; i++) {
  279. if (i) {
  280. SquirtPtsz(TEXT(", "));
  281. }
  282. switch (pal->pszFormat[i]) {
  283. case 'p': /* 32-bit flat pointer */
  284. // 7/18/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  285. #ifdef WIN95
  286. wsprintfA(sz, "%x", pal->rgpv[i]);
  287. #else
  288. wsprintfA(sz, "%p", pal->rgpv[i]);
  289. #endif
  290. SquirtPtszA(sz);
  291. break;
  292. case 'x': /* 32-bit hex */
  293. wsprintfA(sz, "%x", pal->rgpv[i]);
  294. SquirtPtszA(sz);
  295. break;
  296. case 's': /* TCHAR string */
  297. if (pal->rgpv[i] && lstrlen(pal->rgpv[i])) {
  298. SquirtPtsz(pal->rgpv[i]);
  299. }
  300. break;
  301. #ifdef UNICODE
  302. case 'S': /* SCHAR string */
  303. #endif
  304. case 'A': /* ANSI string */
  305. if (pal->rgpv[i] && lstrlenA(pal->rgpv[i])) {
  306. SquirtPtszA(pal->rgpv[i]);
  307. }
  308. break;
  309. #ifndef UNICODE
  310. case 'S': /* SCHAR string */
  311. #endif
  312. case 'W': /* UNICODE string */
  313. if (pal->rgpv[i] && lstrlenW(pal->rgpv[i])) {
  314. #ifdef UNICODE
  315. OutputDebugStringW(pal->rgpv[i]);
  316. #else
  317. UToA(sz, cA(sz), pal->rgpv[i]);
  318. SquirtPtszA(sz);
  319. #endif
  320. }
  321. break;
  322. case 'G': /* GUID */
  323. #if 1
  324. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  325. wsprintfA(sz, "%p",
  326. HIWORD((DWORD)(UINT_PTR)pal->rgpv[i])
  327. ? dwSafeGetPdw((LPDWORD)pal->rgpv[i])
  328. : (UINT_PTR)pal->rgpv[i]);
  329. SquirtPtszA(sz);
  330. #else
  331. if( HIWORD((DWORD)(UINT_PTR)pal->rgpv[i])
  332. && !(IsBadReadPtr( pal->rgpv[i], cbX(pal->rgpv[i]) ) ) )
  333. {
  334. NameFromGUID( (PTCHAR)sz, pal->rgpv[i] );
  335. #ifdef UNICODE
  336. SquirtPtsz( &((PWCHAR)sz)[ctchNamePrefix]);
  337. #else
  338. SquirtPtszA( &sz[ctchNamePrefix] );
  339. #endif
  340. }
  341. else
  342. {
  343. // 7/19/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  344. wsprintfA(sz, "%p",(UINT_PTR)pal->rgpv[i]);
  345. SquirtPtszA(sz);
  346. }
  347. #endif
  348. break;
  349. case 'u': /* 32-bit unsigned decimal */
  350. wsprintfA(sz, "%u", pal->rgpv[i]);
  351. SquirtPtszA(sz);
  352. break;
  353. case 'C':
  354. if (GetClipboardFormatNameA((UINT)(UINT_PTR)pal->rgpv[i], sz, cA(sz))) {
  355. } else {
  356. wsprintfA(sz, "[%04x]", pal->rgpv[i]);
  357. }
  358. SquirtPtszA(sz);
  359. break;
  360. default: AssertF(0); /* Invalid */
  361. }
  362. }
  363. SquirtPtsz(TEXT(")"));
  364. }
  365. /*****************************************************************************
  366. *
  367. * EnterSqflPtsz
  368. *
  369. * Mark entry to a procedure. Arguments were already collected by
  370. * ArgsPszV.
  371. *
  372. * If sqfl contains the sqflBenign flag, then any error we detect
  373. * should be classified as sqflBenign and not sqflError.
  374. *
  375. * sqfl -> squirty flags
  376. * pszProc -> procedure name
  377. * pal -> place to save the name and get the format/args
  378. *
  379. *****************************************************************************/
  380. void EXTERNAL
  381. EnterSqflPszPal(SQFL sqfl, LPCSTR pszProc, PARGLIST pal)
  382. {
  383. pal->pszProc = pszProc;
  384. sqfl |= sqflIn;
  385. if (IsSqflSet(sqfl)) {
  386. EmitPal(pal);
  387. SquirtPtsz(TEXT("\r\n"));
  388. }
  389. }
  390. void EXTERNAL
  391. ExitSqflPalHresPpv(SQFL sqfl, PARGLIST pal, HRESULT hres, PPV ppvObj)
  392. {
  393. BOOL fInternalError;
  394. SQFL sqflIsError;
  395. DWORD le = GetLastError();
  396. if (sqfl & sqflBenign) {
  397. sqfl &= ~sqflBenign;
  398. sqflIsError = sqflBenign;
  399. } else {
  400. sqflIsError = sqflError;
  401. }
  402. sqfl |= sqflOut;
  403. fInternalError = 0;
  404. if (ppvObj == ppvVoid || ppvObj == ppvDword) {
  405. } else if (ppvObj == ppvBool) {
  406. if (hres == 0) {
  407. sqfl |= sqflIsError;
  408. }
  409. } else {
  410. if (FAILED(hres)) {
  411. if (fLimpFF(ppvObj && !IsBadWritePtr(ppvObj, cbX(*ppvObj)),
  412. *ppvObj == 0)) {
  413. } else {
  414. fInternalError = 1;
  415. }
  416. if (hres == E_NOTIMPL) { /* E_NOTIMPL is always benign */
  417. sqfl |= sqflBenign;
  418. } else {
  419. sqfl |= sqflIsError;
  420. }
  421. }
  422. }
  423. if (IsSqflSet(sqfl) || fInternalError) {
  424. EmitPal(pal);
  425. SquirtPtsz(TEXT(" -> "));
  426. if (ppvObj != ppvVoid) {
  427. TCHAR tszBuf[32];
  428. wsprintf(tszBuf, TEXT("%08x"), hres);
  429. SquirtPtsz(tszBuf);
  430. if (HIWORD((UINT_PTR)ppvObj)) {
  431. wsprintf(tszBuf, TEXT(" [%08x]"),
  432. dwSafeGetPdw((LPDWORD)ppvObj));
  433. SquirtPtsz(tszBuf);
  434. } else if (ppvObj == ppvDword) {
  435. wsprintf(tszBuf, TEXT(" [%08x]"), hres);
  436. SquirtPtsz(tszBuf);
  437. } else if (ppvObj == ppvBool) {
  438. wsprintf(tszBuf, hres ? TEXT(" OK ") :
  439. TEXT(" le=[%d]"), le);
  440. SquirtPtsz(tszBuf);
  441. }
  442. }
  443. SquirtPtsz(TEXT("\r\n"));
  444. AssertF(!fInternalError);
  445. }
  446. /*
  447. * This redundant test prevents a breakpoint on SetLastError()
  448. * from being hit constantly.
  449. */
  450. if (le != GetLastError()) {
  451. SetLastError(le);
  452. }
  453. }
  454. #endif
  455. #ifdef XDEBUG
  456. /*****************************************************************************
  457. *
  458. * @doc INTERNAL
  459. *
  460. * @func DWORD | Random |
  461. *
  462. * Returns a pseudorandom dword. The value doesn't need to be
  463. * statistically wonderful.
  464. *
  465. * @returns
  466. * A not very random dword.
  467. *
  468. *****************************************************************************/
  469. DWORD s_dwRandom = 1; /* Random number seed */
  470. DWORD INLINE
  471. Random(void)
  472. {
  473. s_dwRandom = s_dwRandom * 214013 + 2531011;
  474. return s_dwRandom;
  475. }
  476. /*****************************************************************************
  477. *
  478. * @doc INTERNAL
  479. *
  480. * @func void | ScrambleBuf |
  481. *
  482. * Fill a buffer with garbage. Used in RDEBUG to make sure
  483. * the caller is not relying on buffer data.
  484. *
  485. * Note: If the buffer is not a multiple of dwords in size,
  486. * the leftover bytes are not touched.
  487. *
  488. * @parm OUT LPVOID | pv |
  489. *
  490. * The buffer to be scrambled.
  491. *
  492. * @parm UINT | cb |
  493. *
  494. * The size of the buffer.
  495. *
  496. *****************************************************************************/
  497. void EXTERNAL
  498. ScrambleBuf(LPVOID pv, UINT cb)
  499. {
  500. UINT idw;
  501. UINT cdw = cb / 4;
  502. LPDWORD pdw = pv;
  503. for (idw = 0; idw < cdw; idw++) {
  504. pdw[idw] = Random();
  505. }
  506. }
  507. /*****************************************************************************
  508. *
  509. * @doc INTERNAL
  510. *
  511. * @func void | ScrambleBit |
  512. *
  513. * Randomly set or clear a bit.
  514. *
  515. * @parm OUT LPDWORD | pdw |
  516. *
  517. * The dword whose bit is to be set randomly.
  518. *
  519. * @parm UINT | flMask |
  520. *
  521. * Mask for the bits to scramble.
  522. *
  523. *****************************************************************************/
  524. void EXTERNAL ScrambleBit(LPDWORD pdw, DWORD flMask)
  525. {
  526. *pdw ^= (*pdw ^ Random()) & flMask;
  527. }
  528. /*****************************************************************************
  529. *
  530. * @doc INTERNAL
  531. *
  532. * @func BOOL | Callback_CompareContexts |
  533. *
  534. * Check if two <t CONTEXT> structures are substantially the same
  535. * to the extent required by the Win32 calling convention.
  536. *
  537. * This is necessary because lots of applications pass
  538. * incorrectly prototyped functions as callbacks. Others will
  539. * write callback functions that trash registers that are
  540. * supposed to be nonvolatile.
  541. *
  542. * NOTE! Platform-dependent code!
  543. *
  544. * @parm LPCONTEXT | pctx1 |
  545. *
  546. * Context structure before we call the callback.
  547. *
  548. * @parm LPCONTEXT | pctx2 |
  549. *
  550. * Context structure after we call the callback.
  551. *
  552. * @returns
  553. *
  554. * Nonzero if the two contexts are substantially the same.
  555. *
  556. *****************************************************************************/
  557. BOOL INLINE
  558. Callback_CompareContexts(LPCONTEXT pctx1, LPCONTEXT pctx2)
  559. {
  560. #if defined(_X86_)
  561. return pctx1->Esp == pctx2->Esp; /* Stack pointer */
  562. #if 0
  563. /*
  564. * Can't test these registers because Win95 doesn't preserve
  565. * them properly. GetThreadContext() stashes what happens to
  566. * be in the registers when you finally reach the bowels of
  567. * kernel, at which point who knows what they contain...
  568. */
  569. pctx1->Ebx == pctx2->Ebx && /* Nonvolatile registers */
  570. pctx1->Esi == pctx2->Esi &&
  571. pctx1->Edi == pctx2->Edi &&
  572. pctx1->Ebp == pctx2->Ebp;
  573. #endif
  574. #elif defined(_AMD64_)
  575. return pctx1->Rbx == pctx2->Rbx &&
  576. pctx1->Rbp == pctx2->Rbp &&
  577. pctx1->Rsp == pctx2->Rsp &&
  578. pctx1->Rdi == pctx2->Rdi &&
  579. pctx1->Rsi == pctx2->Rsi &&
  580. pctx1->R12 == pctx2->R12 &&
  581. pctx1->R13 == pctx2->R13 &&
  582. pctx1->R14 == pctx2->R14 &&
  583. pctx1->R15 == pctx2->R15;
  584. #elif defined(_IA64_)
  585. return pctx1->IntSp == pctx2->IntSp && /* Stack pointer */
  586. pctx1->RsBSP == pctx2->RsBSP && /* Backing store pointer */
  587. pctx1->IntS0 == pctx2->IntS0 && /* Nonvolatile registers */
  588. pctx1->IntS1 == pctx2->IntS1 &&
  589. pctx1->IntS2 == pctx2->IntS2 &&
  590. pctx1->IntS3 == pctx2->IntS3;
  591. #else
  592. #error "No Target Architecture"
  593. #endif
  594. }
  595. /*****************************************************************************
  596. *
  597. * @doc INTERNAL
  598. *
  599. * @func BOOL | Callback |
  600. *
  601. * Perform a callback the paranoid way, checking that the
  602. * application used the correct calling convention and preserved
  603. * all nonvolatile registers.
  604. *
  605. * NOTE! Platform-dependent code!
  606. *
  607. * @parm DICALLBACKPROC | pfn |
  608. *
  609. * Procedure to call back.
  610. *
  611. * @parm PV | pv1 |
  612. *
  613. * First parameter to callback.
  614. *
  615. * @parm PV | pv2 |
  616. *
  617. * Second parameter to callback.
  618. *
  619. * @returns
  620. *
  621. * Whatever the callback returns.
  622. *
  623. *****************************************************************************/
  624. BOOL EXTERNAL
  625. Callback(DICALLBACKPROC pfn, PV pv1, PV pv2)
  626. {
  627. CONTEXT ctxPre; /* Thread context before call */
  628. CONTEXT ctxPost; /* Thread context after call */
  629. volatile BOOL fRc; /* To prevent compiler from enregistering */
  630. /* Get state of registers before the callback */
  631. ctxPre.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
  632. GetThreadContext(GetCurrentThread(), &ctxPre);
  633. fRc = pfn(pv1, pv2);
  634. ctxPost.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
  635. if (GetThreadContext(GetCurrentThread(), &ctxPost) &&
  636. !Callback_CompareContexts(&ctxPre, &ctxPost)) {
  637. RPF("DINPUT: Incorrectly prototyped callback! Crash soon!");
  638. ValidationException();
  639. }
  640. return fRc;
  641. }
  642. #endif