VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/assert.cpp@ 96014

Last change on this file since 96014 was 95809, checked in by vboxsync, 2 years ago

IPRT/assert.cpp: Use RTLogWriteStdErr instead of fprintf/stderr in IPRT_NO_CRT mode. bugref:10261

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 12.1 KB
Line 
1/* $Id: assert.cpp 95809 2022-07-25 13:19:34Z vboxsync $ */
2/** @file
3 * IPRT - Assertions, common code.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/assert.h>
32#include "internal/iprt.h"
33
34#include <iprt/asm.h>
35#ifdef IPRT_WITH_ASSERT_STACK
36# ifndef IN_RING3
37# error "IPRT_WITH_ASSERT_STACK is only for ring-3 at present."
38# endif
39# include <iprt/dbg.h>
40#endif
41#include <iprt/errcore.h>
42#include <iprt/log.h>
43#include <iprt/string.h>
44#include <iprt/stdarg.h>
45#ifdef IN_RING3
46# include <iprt/env.h>
47# ifndef IPRT_NO_CRT
48# include <stdio.h>
49# endif
50# ifdef RT_OS_WINDOWS
51# include <iprt/win/windows.h>
52# endif
53#endif
54#include "internal/assert.h"
55
56
57/*********************************************************************************************************************************
58* Global Variables *
59*********************************************************************************************************************************/
60/** The last assertion message, 1st part. */
61RTDATADECL(char) g_szRTAssertMsg1[1024];
62RT_EXPORT_SYMBOL(g_szRTAssertMsg1);
63/** The last assertion message, 2nd part. */
64RTDATADECL(char) g_szRTAssertMsg2[4096];
65RT_EXPORT_SYMBOL(g_szRTAssertMsg2);
66#ifdef IPRT_WITH_ASSERT_STACK
67/** The last assertion message, stack part. */
68RTDATADECL(char) g_szRTAssertStack[4096];
69RT_EXPORT_SYMBOL(g_szRTAssertStack);
70#endif
71/** The length of the g_szRTAssertMsg2 content.
72 * @remarks Race. */
73static uint32_t volatile g_cchRTAssertMsg2;
74/** The last assertion message, expression. */
75RTDATADECL(const char * volatile) g_pszRTAssertExpr;
76RT_EXPORT_SYMBOL(g_pszRTAssertExpr);
77/** The last assertion message, function name. */
78RTDATADECL(const char * volatile) g_pszRTAssertFunction;
79RT_EXPORT_SYMBOL(g_pszRTAssertFunction);
80/** The last assertion message, file name. */
81RTDATADECL(const char * volatile) g_pszRTAssertFile;
82RT_EXPORT_SYMBOL(g_pszRTAssertFile);
83/** The last assertion message, line number. */
84RTDATADECL(uint32_t volatile) g_u32RTAssertLine;
85RT_EXPORT_SYMBOL(g_u32RTAssertLine);
86
87
88/** Set if assertions are quiet. */
89static bool volatile g_fQuiet = false;
90/** Set if assertions may panic. */
91static bool volatile g_fMayPanic = true;
92
93
94RTDECL(bool) RTAssertSetQuiet(bool fQuiet)
95{
96 return ASMAtomicXchgBool(&g_fQuiet, fQuiet);
97}
98RT_EXPORT_SYMBOL(RTAssertSetQuiet);
99
100
101RTDECL(bool) RTAssertAreQuiet(void)
102{
103 return ASMAtomicUoReadBool(&g_fQuiet);
104}
105RT_EXPORT_SYMBOL(RTAssertAreQuiet);
106
107
108RTDECL(bool) RTAssertSetMayPanic(bool fMayPanic)
109{
110 return ASMAtomicXchgBool(&g_fMayPanic, fMayPanic);
111}
112RT_EXPORT_SYMBOL(RTAssertSetMayPanic);
113
114
115RTDECL(bool) RTAssertMayPanic(void)
116{
117 return ASMAtomicUoReadBool(&g_fMayPanic);
118}
119RT_EXPORT_SYMBOL(RTAssertMayPanic);
120
121
122RTDECL(void) RTAssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
123{
124 /*
125 * Fill in the globals.
126 */
127 ASMAtomicUoWritePtr(&g_pszRTAssertExpr, pszExpr);
128 ASMAtomicUoWritePtr(&g_pszRTAssertFile, pszFile);
129 ASMAtomicUoWritePtr(&g_pszRTAssertFunction, pszFunction);
130 ASMAtomicUoWriteU32(&g_u32RTAssertLine, uLine);
131 RTStrPrintf(g_szRTAssertMsg1, sizeof(g_szRTAssertMsg1),
132 "\n!!Assertion Failed!!\n"
133 "Expression: %s\n"
134 "Location : %s(%d) %s\n",
135 pszExpr, pszFile, uLine, pszFunction);
136
137 /*
138 * If not quiet, make noise.
139 */
140 if (!RTAssertAreQuiet())
141 {
142 RTERRVARS SavedErrVars;
143 RTErrVarsSave(&SavedErrVars);
144
145#ifdef IPRT_WITH_ASSERT_STACK
146 /* The stack dump. */
147 static volatile bool s_fDumpingStackAlready = false; /* for simple recursion prevention */
148 char szStack[sizeof(g_szRTAssertStack)];
149 size_t cchStack = 0;
150# if defined(IN_RING3) && defined(RT_OS_WINDOWS) /** @todo make this stack on/off thing more modular. */
151 bool fStack = !IsDebuggerPresent() && !RTEnvExist("IPRT_ASSERT_NO_STACK");
152# elif defined(IN_RING3)
153 bool fStack = !RTEnvExist("IPRT_ASSERT_NO_STACK");
154# else
155 bool fStack = true;
156# endif
157 szStack[0] = '\0';
158 if (fStack && !s_fDumpingStackAlready)
159 {
160 s_fDumpingStackAlready = true;
161 cchStack = RTDbgStackDumpSelf(szStack, sizeof(szStack), 0);
162 s_fDumpingStackAlready = false;
163 }
164 memcpy(g_szRTAssertStack, szStack, cchStack + 1);
165#endif
166
167#ifdef IN_RING0
168# ifdef IN_GUEST_R0
169 RTLogBackdoorPrintf("\n!!Assertion Failed!!\n"
170 "Expression: %s\n"
171 "Location : %s(%d) %s\n",
172 pszExpr, pszFile, uLine, pszFunction);
173# endif
174 /** @todo fully integrate this with the logger... play safe a bit for now. */
175 rtR0AssertNativeMsg1(pszExpr, uLine, pszFile, pszFunction);
176
177#else /* !IN_RING0 */
178# if !defined(IN_RING3) && !defined(LOG_NO_COM)
179# if 0 /* Enable this iff you have a COM port and really want this debug info. */
180 RTLogComPrintf("\n!!Assertion Failed!!\n"
181 "Expression: %s\n"
182 "Location : %s(%d) %s\n",
183 pszExpr, pszFile, uLine, pszFunction);
184# endif
185# endif
186
187 PRTLOGGER pLog = RTLogRelGetDefaultInstance();
188 if (pLog)
189 {
190 RTLogRelPrintf("\n!!Assertion Failed!!\n"
191 "Expression: %s\n"
192 "Location : %s(%d) %s\n",
193 pszExpr, pszFile, uLine, pszFunction);
194# ifdef IPRT_WITH_ASSERT_STACK
195 RTLogRelPrintf("Stack :\n%s\n", szStack);
196# endif
197# ifndef IN_RC /* flushing is done automatically in RC */
198 RTLogFlush(pLog);
199# endif
200 }
201
202# ifndef LOG_ENABLED
203 if (!pLog)
204# endif
205 {
206 pLog = RTLogDefaultInstance();
207 if (pLog)
208 {
209 RTLogPrintf("\n!!Assertion Failed!!\n"
210 "Expression: %s\n"
211 "Location : %s(%d) %s\n",
212 pszExpr, pszFile, uLine, pszFunction);
213# ifdef IPRT_WITH_ASSERT_STACK
214 RTLogPrintf("Stack :\n%s\n", szStack);
215# endif
216# ifndef IN_RC /* flushing is done automatically in RC */
217 RTLogFlush(pLog);
218# endif
219 }
220 }
221
222# ifdef IN_RING3
223 /* print to stderr, helps user and gdb debugging. */
224# ifndef IPRT_NO_CRT
225 fprintf(stderr,
226 "\n!!Assertion Failed!!\n"
227 "Expression: %s\n"
228 "Location : %s(%d) %s\n",
229 RT_VALID_PTR(pszExpr) ? pszExpr : "<none>",
230 RT_VALID_PTR(pszFile) ? pszFile : "<none>",
231 uLine,
232 RT_VALID_PTR(pszFunction) ? pszFunction : "");
233# ifdef IPRT_WITH_ASSERT_STACK
234 fprintf(stderr, "Stack :\n%s\n", szStack);
235# endif
236 fflush(stderr);
237# else
238 char szMsg[2048];
239 size_t cchMsg = RTStrPrintf(szMsg, sizeof(szMsg),
240 "\n!!Assertion Failed!!\n"
241 "Expression: %s\n"
242 "Location : %s(%d) %s\n",
243 RT_VALID_PTR(pszExpr) ? pszExpr : "<none>",
244 RT_VALID_PTR(pszFile) ? pszFile : "<none>",
245 uLine,
246 RT_VALID_PTR(pszFunction) ? pszFunction : "");
247 RTLogWriteStdErr(szMsg, cchMsg);
248# ifdef IPRT_WITH_ASSERT_STACK
249 RTLogWriteStdErr(RT_STR_TUPLE("Stack :\n"));
250 RTLogWriteStdErr(szStack, strlen(szStack));
251 RTLogWriteStdErr(RT_STR_TUPLE("\n"));
252# endif
253# endif
254# endif
255#endif /* !IN_RING0 */
256
257 RTErrVarsRestore(&SavedErrVars);
258 }
259}
260RT_EXPORT_SYMBOL(RTAssertMsg1);
261
262
263/**
264 * Worker for RTAssertMsg2V and RTAssertMsg2AddV
265 *
266 * @param fInitial True if it's RTAssertMsg2V, otherwise false.
267 * @param pszFormat The message format string.
268 * @param va The format arguments.
269 */
270static void rtAssertMsg2Worker(bool fInitial, const char *pszFormat, va_list va)
271{
272 va_list vaCopy;
273 size_t cch;
274
275 /*
276 * The global first.
277 */
278 if (fInitial)
279 {
280 va_copy(vaCopy, va);
281 cch = RTStrPrintfV(g_szRTAssertMsg2, sizeof(g_szRTAssertMsg2), pszFormat, vaCopy);
282 ASMAtomicWriteU32(&g_cchRTAssertMsg2, (uint32_t)cch);
283 va_end(vaCopy);
284 }
285 else
286 {
287 cch = ASMAtomicReadU32(&g_cchRTAssertMsg2);
288 if (cch < sizeof(g_szRTAssertMsg2) - 4)
289 {
290 va_copy(vaCopy, va);
291 cch += RTStrPrintfV(&g_szRTAssertMsg2[cch], sizeof(g_szRTAssertMsg2) - cch, pszFormat, vaCopy);
292 ASMAtomicWriteU32(&g_cchRTAssertMsg2, (uint32_t)cch);
293 va_end(vaCopy);
294 }
295 }
296
297 /*
298 * If not quiet, make some noise.
299 */
300 if (!RTAssertAreQuiet())
301 {
302 RTERRVARS SavedErrVars;
303 RTErrVarsSave(&SavedErrVars);
304
305#ifdef IN_RING0
306# ifdef IN_GUEST_R0
307 va_copy(vaCopy, va);
308 RTLogBackdoorPrintfV(pszFormat, vaCopy);
309 va_end(vaCopy);
310# endif
311 /** @todo fully integrate this with the logger... play safe a bit for now. */
312 rtR0AssertNativeMsg2V(fInitial, pszFormat, va);
313
314#else /* !IN_RING0 */
315# if !defined(IN_RING3) && !defined(LOG_NO_COM)
316# if 0 /* Enable this iff you have a COM port and really want this debug info. */
317 va_copy(vaCopy, va);
318 RTLogComPrintfV(pszFormat, vaCopy);
319 va_end(vaCopy);
320# endif
321# endif
322
323 PRTLOGGER pLog = RTLogRelGetDefaultInstance();
324 if (pLog)
325 {
326 va_copy(vaCopy, va);
327 RTLogRelPrintfV(pszFormat, vaCopy);
328 va_end(vaCopy);
329# ifndef IN_RC /* flushing is done automatically in RC */
330 RTLogFlush(pLog);
331# endif
332 }
333
334 pLog = RTLogDefaultInstance();
335 if (pLog)
336 {
337 va_copy(vaCopy, va);
338 RTLogPrintfV(pszFormat, vaCopy);
339 va_end(vaCopy);
340# ifndef IN_RC /* flushing is done automatically in RC */
341 RTLogFlush(pLog);
342#endif
343 }
344
345# ifdef IN_RING3
346 /* print to stderr, helps user and gdb debugging. */
347 char szMsg[sizeof(g_szRTAssertMsg2)];
348 va_copy(vaCopy, va);
349 size_t cchMsg = RTStrPrintfV(szMsg, sizeof(szMsg), pszFormat, vaCopy);
350 va_end(vaCopy);
351# ifndef IPRT_NO_CRT
352 fwrite(szMsg, 1, cchMsg, stderr);
353 fflush(stderr);
354# else
355 RTLogWriteStdErr(szMsg, cchMsg);
356# endif
357# endif
358#endif /* !IN_RING0 */
359
360 RTErrVarsRestore(&SavedErrVars);
361 }
362}
363
364
365RTDECL(void) RTAssertMsg2V(const char *pszFormat, va_list va)
366{
367 rtAssertMsg2Worker(true /*fInitial*/, pszFormat, va);
368}
369RT_EXPORT_SYMBOL(RTAssertMsg2V);
370
371
372RTDECL(void) RTAssertMsg2AddV(const char *pszFormat, va_list va)
373{
374 rtAssertMsg2Worker(false /*fInitial*/, pszFormat, va);
375}
376RT_EXPORT_SYMBOL(RTAssertMsg2AddV);
377
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette