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.

340 lines
9.7 KiB

  1. /***
  2. *error.cpp - RTC support
  3. *
  4. * Copyright (c) 1998-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *
  7. *Revision History:
  8. * 07-28-98 JWM Module incorporated into CRTs (from KFrei)
  9. * 11-03-98 KBF added throw() to eliminate C++ EH code
  10. * 05-11-99 KBF Error if RTC support define not enabled
  11. * 05-26-99 KBF Added -RTCu stuff, _RTC_ prefix on all non-statics
  12. * 11-30-99 PML Compile /Wp64 clean.
  13. * 03-19-01 KBF Fix buffer overruns (vs7#227306), eliminate all /GS
  14. * checks (vs7#224261).
  15. * 03-26-01 PML Use GetVersionExA, not GetVersionEx (vs7#230286)
  16. * 07-15-01 PML Remove all ALPHA, MIPS, and PPC code
  17. *
  18. ****/
  19. #ifndef _RTC
  20. #error RunTime Check support not enabled!
  21. #endif
  22. #include "rtcpriv.h"
  23. #pragma intrinsic(strcpy)
  24. #pragma intrinsic(strcat)
  25. #pragma intrinsic(strlen)
  26. static int __cdecl _IsDebuggerPresent();
  27. int _RTC_ErrorLevels[_RTC_ILLEGAL] = {1,1,1,1};
  28. static const char *_RTC_ErrorMessages[_RTC_ILLEGAL+1] =
  29. {
  30. "The value of ESP was not properly saved across a function "
  31. "call. This is usually a result of calling a function "
  32. "declared with one calling convention with a function "
  33. "pointer declared with a different calling convention.\n\r",
  34. "A cast to a smaller data type has caused a loss of data. "
  35. "If this was intentional, you should mask the source of "
  36. "the cast with the appropriate bitmask. For example: \n\r"
  37. "\tchar c = (i & 0xFF);\n\r"
  38. "Changing the code in this way will not affect the quality of the resulting optimized code.\n\r",
  39. "Stack memory was corrupted\n\r",
  40. "A local variable was used before it was initialized\n\r",
  41. #ifdef _RTC_ADVMEM
  42. "Referencing invalid memory\n\r",
  43. "Referencing memory across different blocks\n\r",
  44. #endif
  45. "Unknown Runtime Check Error\n\r"
  46. };
  47. static const BOOL _RTC_NoFalsePositives[_RTC_ILLEGAL+1] =
  48. {
  49. TRUE, // ESP was trashed
  50. FALSE, // Shortening convert
  51. TRUE, // Stack corruption
  52. TRUE, // Uninitialized use
  53. #ifdef _RTC_ADVMEM
  54. TRUE, // Invalid memory reference
  55. FALSE, // Different memory blocks
  56. #endif
  57. TRUE // Illegal
  58. };
  59. // returns TRUE if debugger understands, FALSE if not
  60. static BOOL
  61. DebuggerProbe( DWORD dwLevelRequired ) throw()
  62. {
  63. EXCEPTION_VISUALCPP_DEBUG_INFO info;
  64. BYTE bDebuggerListening = FALSE;
  65. info.dwType = EXCEPTION_DEBUGGER_PROBE;
  66. info.DebuggerProbe.dwLevelRequired = dwLevelRequired;
  67. info.DebuggerProbe.pbDebuggerPresent = &bDebuggerListening;
  68. __try
  69. {
  70. HelloVC( info );
  71. }
  72. __except(EXCEPTION_CONTINUE_EXECUTION)
  73. {
  74. }
  75. return (BOOL)bDebuggerListening;
  76. }
  77. // returns TRUE if debugger reported it (or was ignored), FALSE if runtime needs to report it
  78. static int
  79. DebuggerRuntime( DWORD dwErrorNumber, BOOL bRealBug, PVOID pvReturnAddr, LPCWSTR pwMessage ) throw()
  80. {
  81. EXCEPTION_VISUALCPP_DEBUG_INFO info;
  82. BYTE bDebuggerListening = FALSE;
  83. info.dwType = EXCEPTION_DEBUGGER_RUNTIMECHECK;
  84. info.RuntimeError.dwRuntimeNumber = dwErrorNumber;
  85. info.RuntimeError.bRealBug = bRealBug;
  86. info.RuntimeError.pvReturnAddress = pvReturnAddr;
  87. info.RuntimeError.pbDebuggerPresent = &bDebuggerListening;
  88. info.RuntimeError.pwRuntimeMessage = pwMessage;
  89. __try
  90. {
  91. HelloVC( info );
  92. }
  93. __except(EXCEPTION_CONTINUE_EXECUTION)
  94. {
  95. }
  96. return (BOOL)bDebuggerListening;
  97. }
  98. static void
  99. failwithmessage(void *retaddr, int crttype, int errnum, const char *msg)
  100. {
  101. _RTC_error_fn fn = _RTC_GetErrorFunc(retaddr);
  102. bool dobreak;
  103. if (DebuggerProbe( EXCEPTION_DEBUGGER_RUNTIMECHECK ))
  104. {
  105. wchar_t *buf = (wchar_t*)_alloca(sizeof(wchar_t) * (strlen(msg) + 2));
  106. int i;
  107. for (i = 0; msg[i]; i++)
  108. buf[i] = msg[i];
  109. buf[i] = 0;
  110. if (DebuggerRuntime(errnum, _RTC_NoFalsePositives[errnum], retaddr, buf))
  111. return;
  112. dobreak = false;
  113. } else
  114. dobreak = true;
  115. if (!fn || (dobreak && _IsDebuggerPresent()))
  116. DebugBreak();
  117. else
  118. {
  119. char *srcName = (char*)_alloca(sizeof(char) * 513);
  120. int lineNum;
  121. char *moduleName;
  122. _RTC_GetSrcLine(((DWORD)(uintptr_t)retaddr)-5, srcName, 512, &lineNum, &moduleName);
  123. // We're just running - report it like the user setup (or the default way)
  124. // If we don't recognize this type, it defaults to an error
  125. if (fn(crttype, srcName, lineNum, moduleName,
  126. "Run-Time Check Failure #%d - %s", errnum, msg) == 1)
  127. DebugBreak();
  128. }
  129. }
  130. void __cdecl
  131. _RTC_Failure(void *retaddr, int errnum)
  132. {
  133. int crttype;
  134. const char *msg;
  135. if (errnum < _RTC_ILLEGAL && errnum >= 0) {
  136. crttype = _RTC_ErrorLevels[errnum];
  137. msg = _RTC_ErrorMessages[errnum];
  138. } else {
  139. crttype = 1;
  140. msg = _RTC_ErrorMessages[_RTC_ILLEGAL];
  141. errnum = _RTC_ILLEGAL;
  142. }
  143. // If we're running inside a debugger, raise an exception
  144. if (crttype != _RTC_ERRTYPE_IGNORE)
  145. {
  146. failwithmessage(retaddr, crttype, errnum, msg);
  147. }
  148. }
  149. static
  150. char *IntToString(int i)
  151. {
  152. static char buf[15];
  153. bool neg = i < 0;
  154. int pos = 14;
  155. buf[14] = 0;
  156. do {
  157. buf[--pos] = i % 10 + '0';
  158. i /= 10;
  159. } while (i);
  160. if (neg)
  161. buf[--pos] = '-';
  162. return &buf[pos];
  163. }
  164. void __cdecl
  165. _RTC_MemFailure(void *retaddr, int errnum, const void *assign)
  166. {
  167. char *srcName = (char*)_alloca(sizeof(char) * 513);
  168. int lineNum;
  169. char *moduleName;
  170. int crttype = _RTC_ErrorLevels[errnum];
  171. if (crttype == _RTC_ERRTYPE_IGNORE)
  172. return;
  173. _RTC_GetSrcLine(((DWORD)(uintptr_t)assign)-5, srcName, 512, &lineNum, &moduleName);
  174. if (!lineNum)
  175. _RTC_Failure(retaddr, errnum);
  176. else
  177. {
  178. char *msg = (char*)_alloca(strlen(_RTC_ErrorMessages[errnum]) +
  179. strlen(srcName) + strlen(moduleName) +
  180. 150);
  181. strcpy(msg, _RTC_ErrorMessages[errnum]);
  182. strcat(msg, "Invalid pointer was assigned at\n\rFile:\t");
  183. strcat(msg, srcName);
  184. strcat(msg, "\n\rLine:\t");
  185. strcat(msg, IntToString(lineNum));
  186. strcat(msg, "\n\rModule:\t");
  187. strcat(msg, moduleName);
  188. failwithmessage(retaddr, crttype, errnum, msg);
  189. }
  190. }
  191. void __cdecl
  192. _RTC_StackFailure(void *retaddr, const char *varname)
  193. {
  194. int crttype = _RTC_ErrorLevels[_RTC_CORRUPT_STACK];
  195. if (crttype != _RTC_ERRTYPE_IGNORE)
  196. {
  197. char *msg = (char*)_alloca(strlen(varname) + 80);
  198. strcpy(msg, "Stack around the variable '");
  199. strcat(msg, varname);
  200. strcat(msg, "' was corrupted.");
  201. failwithmessage(retaddr, crttype, _RTC_CORRUPT_STACK, msg);
  202. }
  203. }
  204. void __cdecl
  205. _RTC_UninitUse(const char *varname)
  206. {
  207. int crttype = _RTC_ErrorLevels[_RTC_UNINIT_LOCAL_USE];
  208. if (crttype != _RTC_ERRTYPE_IGNORE)
  209. {
  210. char *msg = (char*)_alloca(strlen(varname) + 80);
  211. if (varname)
  212. {
  213. strcpy(msg, "The variable '");
  214. strcat(msg, varname);
  215. strcat(msg, "' is being used without being defined.");
  216. } else
  217. {
  218. strcpy(msg, "A variable is being used without being defined.");
  219. }
  220. failwithmessage(_ReturnAddress(), crttype, _RTC_UNINIT_LOCAL_USE, msg);
  221. }
  222. }
  223. /* The rest of this file just implements "IsDebuggerPresent" functionality */
  224. #pragma pack (push, 1)
  225. typedef struct _TIB {
  226. PVOID ExceptionList;
  227. PVOID StackLimit;
  228. PVOID StackBase;
  229. PVOID SubSystemTib;
  230. PVOID Something1;
  231. PVOID ArbitraryUserPointer;
  232. struct _TIB* Self;
  233. WORD Flags;
  234. WORD Win16MutextCount;
  235. PVOID DebugContext;
  236. DWORD CurrentPriority;
  237. DWORD MessageQueueSelector;
  238. PVOID* TlsSlots; // most likely an array
  239. } TIB;
  240. #pragma pack (pop)
  241. //
  242. // Define function to return the current Thread Environment Block
  243. // Information Block
  244. #pragma warning (disable:4035)
  245. #define OffsetTib 0x18
  246. static _inline TIB* GetCurrentTib() { __asm mov eax, fs:[OffsetTib] }
  247. #pragma warning (default:4035)
  248. #define DLL_NOT_FOUND_EXCEPTION (0xc0000135L)
  249. typedef BOOL (WINAPI* NT_IS_DEBUGGER_PRESENT) ();
  250. static NT_IS_DEBUGGER_PRESENT FnIsDebuggerPresent = NULL;
  251. static PVOID
  252. WinGetDebugContext()
  253. {
  254. return GetCurrentTib()->DebugContext;
  255. }
  256. // here's the Win95 version of IsDebuggerPresent
  257. static BOOL WINAPI
  258. Win95IsDebuggerPresent()
  259. {
  260. if (WinGetDebugContext ()) {
  261. return TRUE;
  262. } else {
  263. return FALSE;
  264. }
  265. }
  266. static BOOL
  267. Initialize()
  268. {
  269. HINSTANCE hInst = NULL;
  270. hInst = LoadLibrary ("Kernel32.dll");
  271. FnIsDebuggerPresent =
  272. (NT_IS_DEBUGGER_PRESENT) GetProcAddress (hInst, "IsDebuggerPresent");
  273. if (!FnIsDebuggerPresent) {
  274. OSVERSIONINFOA *VersionInfo = (OSVERSIONINFOA*)_alloca(sizeof(OSVERSIONINFOA));
  275. VersionInfo->dwOSVersionInfoSize = sizeof (OSVERSIONINFOA);
  276. if (GetVersionExA (VersionInfo) &&
  277. VersionInfo->dwPlatformId == VER_PLATFORM_WIN32_WINDOWS &&
  278. VersionInfo->dwMajorVersion == 4)
  279. FnIsDebuggerPresent = Win95IsDebuggerPresent;
  280. }
  281. return !!(FnIsDebuggerPresent);
  282. }
  283. // This is a version of IsDebuggerPresent () that works for all Win32 platforms.
  284. static int __cdecl
  285. _IsDebuggerPresent()
  286. {
  287. static BOOL fInited = FALSE;
  288. if (!fInited) {
  289. if (!Initialize())
  290. RaiseException (DLL_NOT_FOUND_EXCEPTION, 0, 0, NULL);
  291. fInited = TRUE;
  292. }
  293. return FnIsDebuggerPresent();
  294. }