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.

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