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.

345 lines
7.7 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name :
  4. randfail.c
  5. Abstract :
  6. This module implements the initialization function for the random
  7. failure library, plus the code to determine if it's time to fail.
  8. Author :
  9. Sam Neely
  10. Revision History :
  11. --*/
  12. #include <windows.h>
  13. #include <stdio.h>
  14. #include "traceint.h"
  15. #include "randint.h"
  16. #include "exchmem.h"
  17. static long s_nCount = 0;
  18. long nFailRate = kDontFail;
  19. DWORD dwRandFailTlsIndex=0xffffffff;
  20. const DWORD g_dwMaxCallStack = 1024;
  21. //
  22. // Call stack buffer array
  23. //
  24. CHAR **g_ppchCallStack = NULL;
  25. //
  26. // Randfail call stack file and its handle
  27. //
  28. CHAR g_szRandFailFile[MAX_PATH+1];
  29. HANDLE g_hRandFailFile = INVALID_HANDLE_VALUE;
  30. HANDLE g_hRandFailMutex = INVALID_HANDLE_VALUE;
  31. //
  32. // Number of buffers allocated for randfail call stack
  33. //
  34. LONG g_cCallStack = 1;
  35. //
  36. // Current index in the buffer array
  37. //
  38. LONG g_iCallStack = 0;
  39. VOID
  40. DumpCallStack( DWORD_PTR *rgdwCall,
  41. DWORD dwCallers,
  42. PBYTE pbCallstack,
  43. DWORD& cbCallstack )
  44. /*++
  45. Routine description:
  46. Dump call stack into the given buffer.
  47. Arguments:
  48. rgdwCall - Array of caller's address
  49. dwCallers - Number of callers
  50. pbCallstack - The buffer to put the call stack string into
  51. cbCallstack - In: How big the buffer is, Out: how much stuff I have put
  52. in there
  53. Return value:
  54. None.
  55. --*/
  56. {
  57. DWORD i;
  58. CHAR Buffer[g_dwMaxCallStack];
  59. DWORD dwLine = 0;
  60. DWORD dwBufferAvail = cbCallstack - 2*sizeof(CHAR);
  61. PBYTE pbStart = pbCallstack;
  62. DWORD dwBytesWritten = 0;
  63. BOOL fRetry = TRUE;
  64. char szModuleName[MAX_PATH];
  65. char* pszFileName;
  66. char* pszExtension;
  67. _ASSERT( pbStart );
  68. _ASSERT( cbCallstack > 0 );
  69. cbCallstack = 0;
  70. //
  71. // Get the executable's filename and point past the last slash
  72. // in the path, if it's present. Also, whack off the extension
  73. // if it's .EXE
  74. //
  75. if (GetModuleFileName(NULL, szModuleName, MAX_PATH) == 0) {
  76. strcpy (szModuleName, "Unknown");
  77. }
  78. pszFileName = strrchr(szModuleName, '\\');
  79. if (pszFileName == NULL) {
  80. pszFileName = szModuleName;
  81. } else {
  82. pszFileName++;
  83. }
  84. pszExtension = strrchr(pszFileName, '.');
  85. if (pszExtension) {
  86. if (_stricmp(pszExtension+1, "exe") == 0) {
  87. *pszExtension = NULL;
  88. }
  89. }
  90. //
  91. // Format a header line
  92. //
  93. dwBytesWritten = _snprintf((char*)pbStart,
  94. g_dwMaxCallStack,
  95. "*** %s, Process: %d(%#x), Thread: %d(%#x) ***\r\n",
  96. pszFileName,
  97. GetCurrentProcessId(), GetCurrentProcessId(),
  98. GetCurrentThreadId(), GetCurrentThreadId());
  99. cbCallstack += dwBytesWritten;
  100. pbStart += dwBytesWritten;
  101. dwBufferAvail -= dwBytesWritten;
  102. //
  103. // Dump call stack
  104. // Note that we skip the first two entries. These are the internal
  105. // calls to ExchmemGetCallStack and g_TestTrace
  106. for (i = 2; i < dwCallers && rgdwCall[i] != 0; i++)
  107. {
  108. ExchmemFormatSymbol(
  109. GetCurrentProcess(),
  110. rgdwCall[i],
  111. Buffer,
  112. g_dwMaxCallStack );
  113. dwLine = strlen( Buffer );
  114. if ( dwLine+2 < dwBufferAvail ) {
  115. CopyMemory( pbStart, Buffer, dwLine );
  116. *(pbStart+dwLine) = '\r';
  117. *(pbStart+dwLine+1) = '\n';
  118. dwBufferAvail -= (dwLine + 2*sizeof(CHAR));
  119. pbStart += (dwLine + 2*sizeof(CHAR));
  120. cbCallstack +=( dwLine + 2*sizeof(CHAR));
  121. } else {
  122. break;
  123. }
  124. }
  125. //
  126. // Add an extra \r\n at the end
  127. //
  128. *(pbCallstack + cbCallstack) = '\r';
  129. *(pbCallstack + cbCallstack + 1) = '\n';
  130. cbCallstack += 2;
  131. //
  132. // Dump it to the log file as well, if we do have a log file
  133. //
  134. if ( INVALID_HANDLE_VALUE != g_hRandFailFile &&
  135. INVALID_HANDLE_VALUE != g_hRandFailMutex ) {
  136. WaitForSingleObject (g_hRandFailMutex, INFINITE);
  137. DWORD dwOffset = SetFilePointer( g_hRandFailFile, 0, 0, FILE_END );
  138. //
  139. // if the file is too big then we need to truncate it
  140. //
  141. if (dwOffset > dwMaxFileSize)
  142. {
  143. SetFilePointer(g_hRandFailFile, 0, 0, FILE_BEGIN);
  144. SetEndOfFile(g_hRandFailFile);
  145. }
  146. try_again:
  147. BOOL b = WriteFile(
  148. g_hRandFailFile,
  149. pbCallstack,
  150. cbCallstack,
  151. &dwBytesWritten,
  152. NULL );
  153. if ( b == FALSE || dwBytesWritten != cbCallstack )
  154. {
  155. DWORD dwError = GetLastError();
  156. if( dwError && fRetry )
  157. {
  158. fRetry = FALSE;
  159. Sleep( 100 );
  160. goto try_again;
  161. }
  162. INT_TRACE( "Error writing to file: %d, number of bytes %d:%d\n",
  163. dwError,
  164. cbCallstack,
  165. dwBytesWritten );
  166. }
  167. ReleaseMutex(g_hRandFailMutex);
  168. }
  169. }
  170. //
  171. // See if it's time for this API to fail
  172. //
  173. // Note: This routine was renamed from fTimeToFail to g_TestTrace
  174. // to hide the symbol from someone dumping the dll
  175. //
  176. extern "C" __declspec(dllexport)
  177. int
  178. __stdcall
  179. g_TestTrace(void) {
  180. /*++
  181. Routine Description:
  182. Check to see if it's time for an instrumented API to fail.
  183. Note: This routine was renamed from fTimeToFail to g_TestTrace
  184. to hide the symbol from someone dumping the dll
  185. Arguments:
  186. None
  187. Return Value:
  188. true if it's time for us to fail, false if not or we're disabled.
  189. --*/
  190. LONG l;
  191. // Never fail?
  192. if (nFailRate == kDontFail)
  193. return 0;
  194. // Have failures been suspended?
  195. if (dwRandFailTlsIndex != 0xffffffff &&
  196. TlsGetValue (dwRandFailTlsIndex) != NULL)
  197. return 0;
  198. // This is good enough for now..
  199. l = InterlockedIncrement(&s_nCount) % nFailRate;
  200. if ( l == 0 ) {
  201. // We are going to fail
  202. if ( g_ppchCallStack ) {
  203. LONG i = 0;
  204. const DWORD dwMaxCallStack = 20;
  205. DWORD dwCallStackBuffer = g_dwMaxCallStack;
  206. DWORD_PTR rgdwCaller[dwMaxCallStack];
  207. i = InterlockedIncrement( &g_iCallStack );
  208. if ( i <= g_cCallStack ) {
  209. i--;
  210. if ( g_ppchCallStack[i] ) {
  211. ZeroMemory( rgdwCaller, sizeof(DWORD_PTR)*dwMaxCallStack );
  212. ExchmemGetCallStack(rgdwCaller, dwMaxCallStack);
  213. DumpCallStack( rgdwCaller, dwMaxCallStack, (PBYTE)g_ppchCallStack[i], dwCallStackBuffer );
  214. }
  215. } else {
  216. InterlockedExchange( &g_iCallStack, g_cCallStack );
  217. }
  218. }
  219. return TRUE;
  220. } else
  221. return FALSE;
  222. }
  223. extern "C" __declspec(dllexport)
  224. void
  225. __stdcall
  226. g_TestTraceDisable(void) {
  227. /*++
  228. Routine Description:
  229. Function to temporarily suspend g_TestTrace's ability to return a
  230. failure. This is used when you want to call one of the instrumented
  231. APIs that you don't want to fail. This function is nestable up to
  232. 128(abitrary) levels deep.
  233. Arguments:
  234. None
  235. Return Value:
  236. None
  237. --*/
  238. if (dwRandFailTlsIndex == 0xffffffff)
  239. return;
  240. SIZE_T OldValue = (SIZE_T)TlsGetValue(dwRandFailTlsIndex);
  241. ASSERT (OldValue <= 128);
  242. TlsSetValue(dwRandFailTlsIndex, (LPVOID)(OldValue+1));
  243. }
  244. extern "C" __declspec(dllexport)
  245. void
  246. __stdcall
  247. g_TestTraceEnable(void) {
  248. /*++
  249. Routine Description:
  250. Resume g_TestTrace's normal functionality if the nesting level has
  251. returned to zero.
  252. Arguments:
  253. None
  254. Return Value:
  255. None
  256. --*/
  257. if (dwRandFailTlsIndex == 0xffffffff)
  258. return;
  259. SIZE_T OldValue = (SIZE_T)TlsGetValue(dwRandFailTlsIndex);
  260. ASSERT (OldValue > 0 && OldValue <= 128);
  261. TlsSetValue(dwRandFailTlsIndex, (LPVOID)(OldValue-1));
  262. }