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.

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