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.

392 lines
12 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 2002.
  5. //
  6. // File: ciexcpt.cxx
  7. //
  8. // Contents: Macro package for C++ exception support
  9. //
  10. // Classes: CException -- The base for all exception classes
  11. // CExceptionContext -- Per-thread exception context.
  12. // CUnwindable -- Classes with destructors inherit
  13. // from this.
  14. //
  15. // History: 22-May-91 KyleP Created Interface.
  16. // 15-Aug-91 SethuR Included terminate(),unexpected()
  17. // set_unexpected(),set_terminate()
  18. // 18-Oct-91 KyleP Win32 try/except implementation
  19. // 19-Nov-91 KyleP Fix heap unwind, multiple inheritance
  20. // 14-May-92 BryanT Disable heapchk for FLAT builds.
  21. // 25-Apr-95 DwightKr Native C++ exception support
  22. // 30-Oct-98 KLam Translate in page error to disk full
  23. // when appropriate
  24. // 07-Jan-99 KLam Debug out when in page error occurs
  25. //
  26. // Notest: This file is a hack until C 9.x supports exceptions for
  27. // compilers on all platforms
  28. //
  29. //----------------------------------------------------------------------------
  30. #include <pch.cxx>
  31. #pragma hdrstop
  32. //
  33. // If EXCEPT_TEST is defined, then the exception code can be compiled
  34. // without use the the 'Win4 environment'. This is only to facilitate
  35. // testing. When EXCEPT_TEST is defined debug messages are printed
  36. // to stdout instead of the debug terminal.
  37. //
  38. #if !defined( EXCEPT_TEST )
  39. # if CIDBG == 1
  40. DECLARE_DEBUG( ex )
  41. //
  42. // See ciexcpt.hxx for an explanation of why exInlineDebugOut isn't used.
  43. //
  44. void exInlineDebugOut2(unsigned long fDebugMask, char const *pszfmt, ...)
  45. {
  46. va_list ArgList;
  47. va_start(ArgList, pszfmt);
  48. if (exInfoLevel & fDebugMask)
  49. {
  50. vdprintf(fDebugMask, exInfoLevelString, (char const *) pszfmt, ArgList);
  51. }
  52. va_end(ArgList);
  53. }
  54. # endif // (CIDBG == 1)
  55. # if CIDBG == 1
  56. //
  57. // The default is to print exception messages to debug terminal.
  58. //
  59. unsigned long Win4ExceptionLevel = EXCEPT_MESSAGE;
  60. # if !defined( DECLARE_INFOLEVEL )
  61. extern EXTRNC unsigned long comp##InfoLevel = DEF_INFOLEVEL;
  62. extern EXTRNC char *comp##InfoLevelString = #comp;
  63. # else
  64. DECLARE_INFOLEVEL(ex)
  65. # endif
  66. # endif // (CIDBG == 1)
  67. //+---------------------------------------------------------------------------
  68. //
  69. // Function: SetWin4ExceptionLevel
  70. //
  71. // Synopsis: Sets global exception level
  72. //
  73. // History: 15-Sep-91 KevinRo Created
  74. //
  75. //----------------------------------------------------------------------------
  76. # if (CIDBG == 1)
  77. EXPORTIMP unsigned long APINOT
  78. SetWin4ExceptionLevel(
  79. unsigned long ulNewValue)
  80. {
  81. unsigned long ul;
  82. ul = Win4ExceptionLevel;
  83. Win4ExceptionLevel = ulNewValue;
  84. return(ul);
  85. }
  86. ULONG GetWin4ExceptionLevel(void)
  87. {
  88. return Win4ExceptionLevel;
  89. }
  90. # endif // (CIDBG == 1)
  91. #endif // !EXCEPT_TEST
  92. //
  93. // Heap checking can be turned on with this variable.
  94. // 0x00000001 = Always check new/delete
  95. // 0x00000002 = Check delete during unwind.
  96. //
  97. extern "C"
  98. {
  99. int newHeapCheck = 0;
  100. }
  101. //
  102. // In a multi-threaded (e.g. Win32) environment, we need one
  103. // exception context per thread.
  104. //
  105. enum Unwindability
  106. {
  107. NonUnwindable
  108. };
  109. void * __cdecl
  110. operator new ( size_t s, Unwindability dummy )
  111. {
  112. #if defined ( _AUTOCHECK_ )
  113. return RtlAllocateHeap( RtlProcessHeap(), 0, s );
  114. #else
  115. return(malloc(s));
  116. #endif // _AUTOCHECK_
  117. }
  118. //+-------------------------------------------------------------------------
  119. //
  120. // Function: GetScodeError, public
  121. //
  122. // Synopsis: Translates an NTSTATUS or HRESULT into an HRESULT (SCODE)
  123. //
  124. // Arguments: [e] -- The exception object
  125. //
  126. // Returns A SCODE equivalent
  127. //
  128. // History: 3-Feb-98 dlee Created
  129. //
  130. //--------------------------------------------------------------------------
  131. EXPORTIMP SCODE APINOT GetScodeError( CException & e )
  132. {
  133. //
  134. // This function normalizes NTSTATUS, HRESULTS, and Win32 error codes
  135. // into a Win32 error. Note that it is illegal in CI to throw Win32
  136. // error codes because they will be confused with HRESULT success codes
  137. //
  138. // n.b. A side effect is that this error is set in the thread's LastError
  139. //
  140. SCODE sc = e.GetErrorCode();
  141. // If it looks like an HRESULT already, just return it.
  142. if ( 0x80000000 == ( 0xC0000000 & sc ) )
  143. return sc;
  144. //
  145. // If it's a CI 0xC error, don't try to map it since it'll return
  146. // ERROR_MR_MID_NOT_FOUND (and DbgBreak on checked builds).
  147. //
  148. if ( 0xC0041000 == ( 0xC0041000 & sc ) )
  149. return sc;
  150. DWORD dwError = RtlNtStatusToDosError( sc );
  151. if ( ERROR_MR_MID_NOT_FOUND == dwError )
  152. {
  153. ciDebugOut(( DEB_WARN, "mr mid for error %#x\n", sc ));
  154. return sc;
  155. }
  156. return HRESULT_FROM_WIN32( dwError );
  157. } //GetScodeError
  158. //+-------------------------------------------------------------------------
  159. //
  160. // Method: IsOleError, public
  161. //
  162. // Synopsis: return TRUE if sc looks like an OLE SCODE.
  163. //
  164. // History: 19-Apr-95 BartoszM Created
  165. //
  166. //--------------------------------------------------------------------------
  167. inline BOOL IsOleError (NTSTATUS sc)
  168. {
  169. // if it's a win32 facility error in an hresult, only certain
  170. // instances are allowed returned by oledb. Map others to E_FAIL.
  171. if ( 0x80070000 == ( sc & 0x80070000 ) )
  172. {
  173. if ( E_OUTOFMEMORY == sc ||
  174. E_INVALIDARG == sc ||
  175. E_HANDLE == sc ||
  176. E_ACCESSDENIED == sc )
  177. return TRUE;
  178. else
  179. return FALSE;
  180. }
  181. else if ( 0x80030000 == ( sc & 0x80030000 ) )
  182. {
  183. // storage errors aren't allowed by ole-db
  184. return FALSE;
  185. }
  186. return ((sc & 0xFFF00000) == 0x80000000) ||
  187. (SUCCEEDED(sc) && (sc & 0xFFFFF000) != 0);
  188. } //IsOleError
  189. //+-------------------------------------------------------------------------
  190. //
  191. // Method: GetOleError, public
  192. //
  193. // History: 19-Apr-95 BartoszM Created
  194. // 26-Apr-95 DwightKr Converted from method to function
  195. // so that it can be independent from
  196. // the class CException which is now
  197. // part of the C++ run-time package.
  198. //
  199. //--------------------------------------------------------------------------
  200. EXPORTIMP SCODE APINOT GetOleError(CException & e)
  201. {
  202. NTSTATUS scError = e.GetErrorCode();
  203. if (IsOleError(scError))
  204. {
  205. return scError;
  206. }
  207. else if ( ( STATUS_NO_MEMORY == scError ) ||
  208. ( STATUS_COMMITMENT_LIMIT == scError ) ||
  209. ( STATUS_INSUFFICIENT_RESOURCES == scError ) ||
  210. ( HRESULT_FROM_WIN32( ERROR_COMMITMENT_LIMIT ) == scError ) ||
  211. ( HRESULT_FROM_WIN32( ERROR_NO_SYSTEM_RESOURCES ) == scError ) ||
  212. ( STG_E_TOOMANYOPENFILES == scError ) ||
  213. ( STG_E_INSUFFICIENTMEMORY == scError ) )
  214. {
  215. return E_OUTOFMEMORY;
  216. }
  217. else if ( STATUS_ACCESS_DENIED == scError )
  218. return E_ACCESSDENIED;
  219. else if ( STATUS_INVALID_HANDLE == scError )
  220. return E_HANDLE;
  221. else if ( STATUS_INVALID_PARAMETER == scError )
  222. return E_INVALIDARG;
  223. else
  224. {
  225. exDebugOut(( DEB_ITRACE, "GetOleError - mapping %08x to E_FAIL\n", scError));
  226. return E_FAIL;
  227. }
  228. }
  229. CException::CException()
  230. : _lError( HRESULT_FROM_WIN32( GetLastError() ) ),
  231. _dbgInfo( 0 )
  232. {
  233. } //CException
  234. #if CIDBG == 1
  235. //+---------------------------------------------------------------------------
  236. //
  237. // Function: ExceptionReport
  238. //
  239. // Synopsis: Outputs Exception messages based on the Win4ExceptionLevel
  240. // variable. Used by programs compiled with DEBUG defined
  241. //
  242. // History: 15-Sep-91 KevinRo Created
  243. //
  244. //----------------------------------------------------------------------------
  245. EXPORTIMP void APINOT
  246. ExceptionReport(
  247. unsigned int iLine,
  248. char *szFile,
  249. char *szMsg,
  250. long lError )
  251. {
  252. # if DBG
  253. if (Win4ExceptionLevel & EXCEPT_MESSAGE)
  254. {
  255. DWORD tid = GetCurrentThreadId();
  256. exDebugOut((DEB_FORCE,
  257. "%s - line: %u file: %s, thread id %x\n",
  258. szMsg, iLine, szFile, tid));
  259. if (lError != -1)
  260. exDebugOut((DEB_FORCE,"\terror code 0x%lx\n", lError ));
  261. }
  262. # endif
  263. if (Win4ExceptionLevel & EXCEPT_POPUP)
  264. {
  265. if(PopUpError(szMsg,iLine,szFile) == IDCANCEL)
  266. {
  267. DebugBreak();
  268. }
  269. }
  270. else
  271. {
  272. if (Win4ExceptionLevel & EXCEPT_BREAK)
  273. {
  274. DebugBreak();
  275. }
  276. }
  277. }
  278. #endif // CIDBG == 1
  279. //+-------------------------------------------------------------------------
  280. //
  281. // Setup the runtime package to translate system exceptions (i.e. those
  282. // usually processed by try / except blocks) into C++ exceptions (those
  283. // processed by try / catch blocks). This has no effect on try / except
  284. // blocks; as they will still continue to see the standard C exception.
  285. //
  286. // The translation is accomplished by telling the C run-time package to
  287. // call a user-specified function each time a system exception occurs. The
  288. // function translates the exception into a class and rethrows with the
  289. // class. If their is a following CATCH block, then the C++ class will
  290. // be caught. If there is a following except, then the original system
  291. // exception will be caught.
  292. //
  293. //--------------------------------------------------------------------------
  294. //
  295. // Convert system exceptions to a C++ exception.
  296. //
  297. void _cdecl SystemExceptionTranslator( unsigned int uiWhat,
  298. struct _EXCEPTION_POINTERS * pexcept )
  299. {
  300. //
  301. // Intentionally don't translate STATUS_PRIVILEGED_INSTRUCTION (see
  302. // Win4AssertEx for details.
  303. //
  304. //
  305. // In certain situations when a compressed or sparse file is mapped and we
  306. // run out of disk space the system can throw an in page error instead of
  307. // the appropriate error
  308. //
  309. // Throw the proper exception code so that the error can be handled correctly
  310. //
  311. if ( STATUS_IN_PAGE_ERROR == pexcept->ExceptionRecord->ExceptionCode &&
  312. pexcept->ExceptionRecord->NumberParameters >= 3 )
  313. {
  314. exDebugOut(( DEB_WARN, "SystemExceptionTranslator: Received In Page IO Error\n"));
  315. Win4Assert ( STATUS_IN_PAGE_ERROR == uiWhat );
  316. if ( STATUS_DISK_FULL == pexcept->ExceptionRecord->ExceptionInformation[2] ||
  317. STATUS_VOLUME_DISMOUNTED == pexcept->ExceptionRecord->ExceptionInformation[2] ||
  318. STATUS_INSUFFICIENT_RESOURCES == pexcept->ExceptionRecord->ExceptionInformation[2] )
  319. {
  320. exDebugOut(( DEB_WARN, "SystemExceptionTranslator: Translating In Page IO Error to 0x%x\n",
  321. (unsigned int) pexcept->ExceptionRecord->ExceptionInformation[2] ));
  322. uiWhat = (unsigned int) pexcept->ExceptionRecord->ExceptionInformation[2];
  323. pexcept->ExceptionRecord->ExceptionCode = (NTSTATUS) pexcept->ExceptionRecord->ExceptionInformation[2];
  324. }
  325. }
  326. #if CIDBG == 1
  327. if ( ASSRT_STRESSEXCEPTION != uiWhat )
  328. throw CException( uiWhat ) ;
  329. #else
  330. throw CException( uiWhat ) ;
  331. #endif
  332. } //SystemExceptionTranslator