VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 3 years ago

scm copyright and license note update

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

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