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.

332 lines
11 KiB

  1. /***
  2. *assert.c - Display a message and abort
  3. *
  4. * Copyright (c) 1988-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *
  8. *Revision History:
  9. * 05-19-88 JCR Module created.
  10. * 08-10-88 PHG Corrected copyright date
  11. * 03-14-90 GJF Replaced _LOAD_DS with _CALLTYPE1 and added #include
  12. * <cruntime.h>. Also, fixed the copyright.
  13. * 04-05-90 GJF Added #include <assert.h>
  14. * 10-04-90 GJF New-style function declarator.
  15. * 06-19-91 GJF Conditionally use setvbuf() on stderr to prevent
  16. * the implicit call to malloc() if stderr is being used
  17. * for the first time (assert() should work even if the
  18. * heap is trashed).
  19. * 01-25-92 RID Mac module created from x86 version
  20. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  21. * 09-06-94 GJF Substantially revised to use MessageBox for GUI apps.
  22. * 02-15-95 CFW Make all CRT message boxes look alike.
  23. * 02-16-95 JWM Spliced _WIN32 & Mac versions.
  24. * 02-24-95 CFW Use __crtMessageBoxA.
  25. * 02-27-95 CFW Change debug break scheme, change __crtMBoxA params.
  26. * 03-29-95 BWT Fix posix build by adding _exit prototype.
  27. * 06-06-95 CFW Remove _MB_SERVICE_NOTIFICATION.
  28. * 10-17-96 GJF Thou shalt not scribble on the caller's filename
  29. * string! Also, fixed miscount of double newline.
  30. * 05-17-99 PML Remove all Macintosh support.
  31. * 10-20-99 GB Fix dotdotdot for filename. VS7#4731
  32. * 03-28-01 PML Protect against GetModuleFileName overflow (vs7#231284)
  33. * 07-15-01 PML Remove all ALPHA, MIPS, and PPC code
  34. *
  35. *******************************************************************************/
  36. #include <cruntime.h>
  37. #include <windows.h>
  38. #include <file2.h>
  39. #include <internal.h>
  40. #include <stdlib.h>
  41. #include <stdio.h>
  42. #include <string.h>
  43. #include <signal.h>
  44. #include <awint.h>
  45. #ifdef NDEBUG
  46. #undef NDEBUG
  47. #endif
  48. #define _ASSERT_OK
  49. #include <assert.h>
  50. #ifdef _POSIX_
  51. _CRTIMP void __cdecl _exit(int);
  52. #endif
  53. /*
  54. * assertion format string for use with output to stderr
  55. */
  56. static char _assertstring[] = "Assertion failed: %s, file %s, line %d\n";
  57. /* Format of MessageBox for assertions:
  58. *
  59. * ================= Microsft Visual C++ Debug Library ================
  60. *
  61. * Assertion Failed!
  62. *
  63. * Program: c:\test\mytest\foo.exe
  64. * File: c:\test\mytest\bar.c
  65. * Line: 69
  66. *
  67. * Expression: <expression>
  68. *
  69. * For information on how your program can cause an assertion
  70. * failure, see the Visual C++ documentation on asserts
  71. *
  72. * (Press Retry to debug the application - JIT must be enabled)
  73. *
  74. * ===================================================================
  75. */
  76. /*
  77. * assertion string components for message box
  78. */
  79. #define BOXINTRO "Assertion failed!"
  80. #define PROGINTRO "Program: "
  81. #define FILEINTRO "File: "
  82. #define LINEINTRO "Line: "
  83. #define EXPRINTRO "Expression: "
  84. #define INFOINTRO "For information on how your program can cause an assertion\n" \
  85. "failure, see the Visual C++ documentation on asserts"
  86. #define HELPINTRO "(Press Retry to debug the application - JIT must be enabled)"
  87. static char * dotdotdot = "...";
  88. static char * newline = "\n";
  89. static char * dblnewline = "\n\n";
  90. #define DOTDOTDOTSZ 3
  91. #define NEWLINESZ 1
  92. #define DBLNEWLINESZ 2
  93. #define MAXLINELEN 60 /* max length for line in message box */
  94. #define ASSERTBUFSZ (MAXLINELEN * 9) /* 9 lines in message box */
  95. #if defined(_M_IX86)
  96. #define _DbgBreak() __asm { int 3 }
  97. #elif defined(_M_IA64)
  98. void __break(int);
  99. #pragma intrinsic (__break)
  100. #define _DbgBreak() __break(0x80016)
  101. #else
  102. #define _DbgBreak() DebugBreak()
  103. #endif
  104. /***
  105. *_assert() - Display a message and abort
  106. *
  107. *Purpose:
  108. * The assert macro calls this routine if the assert expression is
  109. * true. By placing the assert code in a subroutine instead of within
  110. * the body of the macro, programs that call assert multiple times will
  111. * save space.
  112. *
  113. *Entry:
  114. *
  115. *Exit:
  116. *
  117. *Exceptions:
  118. *
  119. *******************************************************************************/
  120. void __cdecl _assert (
  121. void *expr,
  122. void *filename,
  123. unsigned lineno
  124. )
  125. {
  126. /*
  127. * Build the assertion message, then write it out. The exact form
  128. * depends on whether it is to be written out via stderr or the
  129. * MessageBox API.
  130. */
  131. if ( (__error_mode == _OUT_TO_STDERR) || ((__error_mode ==
  132. _OUT_TO_DEFAULT) && (__app_type == _CONSOLE_APP)) )
  133. {
  134. /*
  135. * Build message and write it out to stderr. It will be of the
  136. * form:
  137. * Assertion failed: <expr>, file <filename>, line <lineno>
  138. */
  139. if ( !anybuf(stderr) )
  140. /*
  141. * stderr is unused, hence unbuffered, as yet. set it to
  142. * single character buffering (to avoid a malloc() of a
  143. * stream buffer).
  144. */
  145. (void) setvbuf(stderr, NULL, _IONBF, 0);
  146. fprintf(stderr, _assertstring, expr, filename, lineno);
  147. fflush(stderr);
  148. }
  149. else {
  150. int nCode;
  151. char * pch;
  152. char assertbuf[ASSERTBUFSZ];
  153. char progname[MAX_PATH + 1];
  154. /*
  155. * Line 1: box intro line
  156. */
  157. strcpy( assertbuf, BOXINTRO );
  158. strcat( assertbuf, dblnewline );
  159. /*
  160. * Line 2: program line
  161. */
  162. strcat( assertbuf, PROGINTRO );
  163. progname[MAX_PATH] = '\0';
  164. if ( !GetModuleFileName( NULL, progname, MAX_PATH ))
  165. strcpy( progname, "<program name unknown>");
  166. pch = (char *)progname;
  167. /* sizeof(PROGINTRO) includes the NULL terminator */
  168. if ( sizeof(PROGINTRO) + strlen(progname) + NEWLINESZ > MAXLINELEN )
  169. {
  170. pch += (sizeof(PROGINTRO) + strlen(progname) + NEWLINESZ) - MAXLINELEN;
  171. strncpy( pch, dotdotdot, DOTDOTDOTSZ );
  172. }
  173. strcat( assertbuf, pch );
  174. strcat( assertbuf, newline );
  175. /*
  176. * Line 3: file line
  177. */
  178. strcat( assertbuf, FILEINTRO );
  179. /* sizeof(FILEINTRO) includes the NULL terminator */
  180. if ( sizeof(FILEINTRO) + strlen(filename) + NEWLINESZ > MAXLINELEN )
  181. {
  182. size_t p, len, ffn;
  183. pch = (char *) filename;
  184. ffn = MAXLINELEN - sizeof(FILEINTRO) - NEWLINESZ;
  185. for ( len = strlen(filename), p = 1;
  186. pch[len - p] != '\\' && pch[len - p] != '/' && p < len;
  187. p++ );
  188. /* keeping pathname almost 2/3rd of full filename and rest
  189. * is filename
  190. */
  191. if ( (ffn - ffn/3) < (len - p) && ffn/3 > p )
  192. {
  193. /* too long. using first part of path and the
  194. filename string */
  195. strncat( assertbuf, pch, ffn - DOTDOTDOTSZ - p );
  196. strcat( assertbuf, dotdotdot );
  197. strcat( assertbuf, pch + len - p );
  198. }
  199. else if ( ffn - ffn/3 > len - p )
  200. {
  201. /* pathname is smaller. keeping full pathname and putting
  202. * dotdotdot in the middle of filename
  203. */
  204. p = p/2;
  205. strncat( assertbuf, pch, ffn - DOTDOTDOTSZ - p );
  206. strcat( assertbuf, dotdotdot );
  207. strcat( assertbuf, pch + len - p );
  208. }
  209. else
  210. {
  211. /* both are long. using first part of path. using first and
  212. * last part of filename.
  213. */
  214. strncat( assertbuf, pch, ffn - ffn/3 - DOTDOTDOTSZ );
  215. strcat( assertbuf, dotdotdot );
  216. strncat( assertbuf, pch + len - p, ffn/6 - 1 );
  217. strcat( assertbuf, dotdotdot );
  218. strcat( assertbuf, pch + len - (ffn/3 - ffn/6 - 2) );
  219. }
  220. }
  221. else
  222. /* plenty of room on the line, just append the filename */
  223. strcat( assertbuf, filename );
  224. strcat( assertbuf, newline );
  225. /*
  226. * Line 4: line line
  227. */
  228. strcat( assertbuf, LINEINTRO );
  229. _itoa( lineno, assertbuf + strlen(assertbuf), 10 );
  230. strcat( assertbuf, dblnewline );
  231. /*
  232. * Line 5: message line
  233. */
  234. strcat( assertbuf, EXPRINTRO );
  235. /* sizeof(HELPINTRO) includes the NULL terminator */
  236. if ( strlen(assertbuf) +
  237. strlen(expr) +
  238. 2*DBLNEWLINESZ +
  239. sizeof(INFOINTRO)-1 +
  240. sizeof(HELPINTRO) > ASSERTBUFSZ )
  241. {
  242. strncat( assertbuf, expr,
  243. ASSERTBUFSZ -
  244. (strlen(assertbuf) +
  245. DOTDOTDOTSZ +
  246. 2*DBLNEWLINESZ +
  247. sizeof(INFOINTRO)-1 +
  248. sizeof(HELPINTRO)) );
  249. strcat( assertbuf, dotdotdot );
  250. }
  251. else
  252. strcat( assertbuf, expr );
  253. strcat( assertbuf, dblnewline );
  254. /*
  255. * Line 6, 7: info line
  256. */
  257. strcat(assertbuf, INFOINTRO);
  258. strcat( assertbuf, dblnewline );
  259. /*
  260. * Line 8: help line
  261. */
  262. strcat(assertbuf, HELPINTRO);
  263. /*
  264. * Write out via MessageBox
  265. */
  266. nCode = __crtMessageBoxA(assertbuf,
  267. "Microsoft Visual C++ Runtime Library",
  268. MB_ABORTRETRYIGNORE|MB_ICONHAND|MB_SETFOREGROUND|MB_TASKMODAL);
  269. /* Abort: abort the program */
  270. if (nCode == IDABORT)
  271. {
  272. /* raise abort signal */
  273. raise(SIGABRT);
  274. /* We usually won't get here, but it's possible that
  275. SIGABRT was ignored. So exit the program anyway. */
  276. _exit(3);
  277. }
  278. /* Retry: call the debugger */
  279. if (nCode == IDRETRY)
  280. {
  281. _DbgBreak();
  282. /* return to user code */
  283. return;
  284. }
  285. /* Ignore: continue execution */
  286. if (nCode == IDIGNORE)
  287. return;
  288. }
  289. abort();
  290. }