VirtualBox

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

Last change on this file since 106061 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 11.2 KB
Line 
1/* $Id: assert.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - Assertions, common code.
4 */
5
6/*
7 * Copyright (C) 2006-2024 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# include "../../r3/win/internal-r3-win.h"
63# endif
64#endif
65#include "internal/assert.h"
66
67
68/*********************************************************************************************************************************
69* Global Variables *
70*********************************************************************************************************************************/
71/** The last assertion message, 1st part. */
72RTDATADECL(char) g_szRTAssertMsg1[1024];
73RT_EXPORT_SYMBOL(g_szRTAssertMsg1);
74/** The last assertion message, 2nd part. */
75RTDATADECL(char) g_szRTAssertMsg2[4096];
76RT_EXPORT_SYMBOL(g_szRTAssertMsg2);
77#ifdef IPRT_WITH_ASSERT_STACK
78/** The last assertion message, stack part. */
79RTDATADECL(char) g_szRTAssertStack[4096];
80RT_EXPORT_SYMBOL(g_szRTAssertStack);
81#endif
82/** The length of the g_szRTAssertMsg2 content.
83 * @remarks Race. */
84static uint32_t volatile g_cchRTAssertMsg2;
85/** The last assertion message, expression. */
86RTDATADECL(const char * volatile) g_pszRTAssertExpr;
87RT_EXPORT_SYMBOL(g_pszRTAssertExpr);
88/** The last assertion message, function name. */
89RTDATADECL(const char * volatile) g_pszRTAssertFunction;
90RT_EXPORT_SYMBOL(g_pszRTAssertFunction);
91/** The last assertion message, file name. */
92RTDATADECL(const char * volatile) g_pszRTAssertFile;
93RT_EXPORT_SYMBOL(g_pszRTAssertFile);
94/** The last assertion message, line number. */
95RTDATADECL(uint32_t volatile) g_u32RTAssertLine;
96RT_EXPORT_SYMBOL(g_u32RTAssertLine);
97
98
99/** Set if assertions are quiet. */
100static bool volatile g_fQuiet = false;
101/** Set if assertions may panic. */
102static bool volatile g_fMayPanic = true;
103
104
105RTDECL(bool) RTAssertSetQuiet(bool fQuiet)
106{
107 return ASMAtomicXchgBool(&g_fQuiet, fQuiet);
108}
109RT_EXPORT_SYMBOL(RTAssertSetQuiet);
110
111
112RTDECL(bool) RTAssertAreQuiet(void)
113{
114 return ASMAtomicUoReadBool(&g_fQuiet);
115}
116RT_EXPORT_SYMBOL(RTAssertAreQuiet);
117
118
119RTDECL(bool) RTAssertSetMayPanic(bool fMayPanic)
120{
121 return ASMAtomicXchgBool(&g_fMayPanic, fMayPanic);
122}
123RT_EXPORT_SYMBOL(RTAssertSetMayPanic);
124
125
126RTDECL(bool) RTAssertMayPanic(void)
127{
128 return ASMAtomicUoReadBool(&g_fMayPanic);
129}
130RT_EXPORT_SYMBOL(RTAssertMayPanic);
131
132
133RTDECL(void) RTAssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
134{
135 /*
136 * Fill in the globals.
137 */
138 ASMAtomicUoWritePtr(&g_pszRTAssertExpr, pszExpr);
139 ASMAtomicUoWritePtr(&g_pszRTAssertFile, pszFile);
140 ASMAtomicUoWritePtr(&g_pszRTAssertFunction, pszFunction);
141 ASMAtomicUoWriteU32(&g_u32RTAssertLine, uLine);
142 RTStrPrintf(g_szRTAssertMsg1, sizeof(g_szRTAssertMsg1),
143 "\n!!Assertion Failed!!\n"
144 "Expression: %s\n"
145 "Location : %s(%d) %s\n",
146 pszExpr, pszFile, uLine, pszFunction);
147
148 /*
149 * If not quiet, make noise.
150 */
151 if (!RTAssertAreQuiet())
152 {
153 RTERRVARS SavedErrVars;
154 RTErrVarsSave(&SavedErrVars);
155
156#ifdef IPRT_WITH_ASSERT_STACK
157 /* The stack dump. */
158 static volatile bool s_fDumpingStackAlready = false; /* for simple recursion prevention */
159 char szStack[sizeof(g_szRTAssertStack)];
160 size_t cchStack = 0;
161# if defined(IN_RING3) && defined(RT_OS_WINDOWS) /** @todo make this stack on/off thing more modular. */
162 bool fStack = (!g_pfnIsDebuggerPresent || !g_pfnIsDebuggerPresent()) && !RTEnvExist("IPRT_ASSERT_NO_STACK");
163# elif defined(IN_RING3)
164 bool fStack = !RTEnvExist("IPRT_ASSERT_NO_STACK");
165# else
166 bool fStack = true;
167# endif
168 szStack[0] = '\0';
169 if (fStack && !s_fDumpingStackAlready)
170 {
171 s_fDumpingStackAlready = true;
172 cchStack = RTDbgStackDumpSelf(szStack, sizeof(szStack), 0);
173 s_fDumpingStackAlready = false;
174 }
175 memcpy(g_szRTAssertStack, szStack, cchStack + 1);
176#endif
177
178#ifdef IN_RING0
179# ifdef IN_GUEST_R0
180 RTLogBackdoorPrintf("\n!!Assertion Failed!!\n"
181 "Expression: %s\n"
182 "Location : %s(%d) %s\n",
183 pszExpr, pszFile, uLine, pszFunction);
184# endif
185 /** @todo fully integrate this with the logger... play safe a bit for now. */
186 rtR0AssertNativeMsg1(pszExpr, uLine, pszFile, pszFunction);
187
188#else /* !IN_RING0 */
189
190
191# if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT)) /* ugly */
192 if (g_pfnRTLogAssert)
193 g_pfnRTLogAssert(
194# else
195 RTLogAssert(
196# endif
197 "\n!!Assertion Failed!!\n"
198 "Expression: %s\n"
199 "Location : %s(%d) %s\n"
200# ifdef IPRT_WITH_ASSERT_STACK
201 "Stack :\n%s\n"
202# endif
203 , pszExpr, pszFile, uLine, pszFunction
204# ifdef IPRT_WITH_ASSERT_STACK
205 , szStack
206# endif
207 );
208
209# ifdef IN_RING3
210 /* print to stderr, helps user and gdb debugging. */
211# ifndef IPRT_NO_CRT
212 fprintf(stderr,
213 "\n!!Assertion Failed!!\n"
214 "Expression: %s\n"
215 "Location : %s(%d) %s\n",
216 RT_VALID_PTR(pszExpr) ? pszExpr : "<none>",
217 RT_VALID_PTR(pszFile) ? pszFile : "<none>",
218 uLine,
219 RT_VALID_PTR(pszFunction) ? pszFunction : "");
220# ifdef IPRT_WITH_ASSERT_STACK
221 fprintf(stderr, "Stack :\n%s\n", szStack);
222# endif
223 fflush(stderr);
224# else
225 char szMsg[2048];
226 size_t cchMsg = RTStrPrintf(szMsg, sizeof(szMsg),
227 "\n!!Assertion Failed!!\n"
228 "Expression: %s\n"
229 "Location : %s(%d) %s\n",
230 RT_VALID_PTR(pszExpr) ? pszExpr : "<none>",
231 RT_VALID_PTR(pszFile) ? pszFile : "<none>",
232 uLine,
233 RT_VALID_PTR(pszFunction) ? pszFunction : "");
234 RTLogWriteStdErr(szMsg, cchMsg);
235# ifdef IPRT_WITH_ASSERT_STACK
236 RTLogWriteStdErr(RT_STR_TUPLE("Stack :\n"));
237 RTLogWriteStdErr(szStack, strlen(szStack));
238 RTLogWriteStdErr(RT_STR_TUPLE("\n"));
239# endif
240# endif
241# endif
242#endif /* !IN_RING0 */
243
244 RTErrVarsRestore(&SavedErrVars);
245 }
246}
247RT_EXPORT_SYMBOL(RTAssertMsg1);
248
249
250/**
251 * Worker for RTAssertMsg2V and RTAssertMsg2AddV
252 *
253 * @param fInitial True if it's RTAssertMsg2V, otherwise false.
254 * @param pszFormat The message format string.
255 * @param va The format arguments.
256 */
257static void rtAssertMsg2Worker(bool fInitial, const char *pszFormat, va_list va)
258{
259 va_list vaCopy;
260 size_t cch;
261
262 /*
263 * The global first.
264 */
265 if (fInitial)
266 {
267 va_copy(vaCopy, va);
268 cch = RTStrPrintfV(g_szRTAssertMsg2, sizeof(g_szRTAssertMsg2), pszFormat, vaCopy);
269 ASMAtomicWriteU32(&g_cchRTAssertMsg2, (uint32_t)cch);
270 va_end(vaCopy);
271 }
272 else
273 {
274 cch = ASMAtomicReadU32(&g_cchRTAssertMsg2);
275 if (cch < sizeof(g_szRTAssertMsg2) - 4)
276 {
277 va_copy(vaCopy, va);
278 cch += RTStrPrintfV(&g_szRTAssertMsg2[cch], sizeof(g_szRTAssertMsg2) - cch, pszFormat, vaCopy);
279 ASMAtomicWriteU32(&g_cchRTAssertMsg2, (uint32_t)cch);
280 va_end(vaCopy);
281 }
282 }
283
284 /*
285 * If not quiet, make some noise.
286 */
287 if (!RTAssertAreQuiet())
288 {
289 RTERRVARS SavedErrVars;
290 RTErrVarsSave(&SavedErrVars);
291
292#ifdef IN_RING0
293# ifdef IN_GUEST_R0
294 va_copy(vaCopy, va);
295 RTLogBackdoorPrintfV(pszFormat, vaCopy);
296 va_end(vaCopy);
297# endif
298 /** @todo fully integrate this with the logger... play safe a bit for now. */
299 rtR0AssertNativeMsg2V(fInitial, pszFormat, va);
300
301#else /* !IN_RING0 */
302
303# if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT))
304 if (g_pfnRTLogAssert)
305# endif
306 {
307 va_copy(vaCopy, va);
308# if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT))
309 g_pfnRTLogAssertV(pszFormat, vaCopy);
310# else
311 RTLogAssertV(pszFormat, vaCopy);
312# endif
313 va_end(vaCopy);
314 }
315
316# ifdef IN_RING3
317 /* print to stderr, helps user and gdb debugging. */
318 char szMsg[sizeof(g_szRTAssertMsg2)];
319 va_copy(vaCopy, va);
320 size_t cchMsg = RTStrPrintfV(szMsg, sizeof(szMsg), pszFormat, vaCopy);
321 va_end(vaCopy);
322# ifndef IPRT_NO_CRT
323 fwrite(szMsg, 1, cchMsg, stderr);
324 fflush(stderr);
325# else
326 RTLogWriteStdErr(szMsg, cchMsg);
327# endif
328# endif
329#endif /* !IN_RING0 */
330
331 RTErrVarsRestore(&SavedErrVars);
332 }
333}
334
335
336RTDECL(void) RTAssertMsg2V(const char *pszFormat, va_list va)
337{
338 rtAssertMsg2Worker(true /*fInitial*/, pszFormat, va);
339}
340RT_EXPORT_SYMBOL(RTAssertMsg2V);
341
342
343RTDECL(void) RTAssertMsg2AddV(const char *pszFormat, va_list va)
344{
345 rtAssertMsg2Worker(false /*fInitial*/, pszFormat, va);
346}
347RT_EXPORT_SYMBOL(RTAssertMsg2AddV);
348
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