VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 17 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
RevLine 
[1]1/* $Id: assert.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
[25528]3 * IPRT - Assertions, common code.
[1]4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[1]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
[5999]11 *
[96407]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 *
[5999]25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
[96407]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
[5999]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.
[96407]33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
[1]35 */
36
37
[57358]38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
[1]41#include <iprt/assert.h>
[21337]42#include "internal/iprt.h"
43
[25518]44#include <iprt/asm.h>
[73762]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
[76452]51#include <iprt/errcore.h>
[1]52#include <iprt/log.h>
53#include <iprt/string.h>
54#include <iprt/stdarg.h>
55#ifdef IN_RING3
[74344]56# include <iprt/env.h>
[95809]57# ifndef IPRT_NO_CRT
58# include <stdio.h>
59# endif
[74344]60# ifdef RT_OS_WINDOWS
61# include <iprt/win/windows.h>
[96476]62# include "../../r3/win/internal-r3-win.h"
[74344]63# endif
[1]64#endif
[25528]65#include "internal/assert.h"
[1]66
67
[57358]68/*********************************************************************************************************************************
69* Global Variables *
70*********************************************************************************************************************************/
[73762]71/** The last assertion message, 1st part. */
[25528]72RTDATADECL(char) g_szRTAssertMsg1[1024];
73RT_EXPORT_SYMBOL(g_szRTAssertMsg1);
[73762]74/** The last assertion message, 2nd part. */
[25536]75RTDATADECL(char) g_szRTAssertMsg2[4096];
[25528]76RT_EXPORT_SYMBOL(g_szRTAssertMsg2);
[73762]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
[25536]82/** The length of the g_szRTAssertMsg2 content.
83 * @remarks Race. */
84static uint32_t volatile g_cchRTAssertMsg2;
[73762]85/** The last assertion message, expression. */
[25528]86RTDATADECL(const char * volatile) g_pszRTAssertExpr;
87RT_EXPORT_SYMBOL(g_pszRTAssertExpr);
[73762]88/** The last assertion message, function name. */
[25528]89RTDATADECL(const char * volatile) g_pszRTAssertFunction;
90RT_EXPORT_SYMBOL(g_pszRTAssertFunction);
[73762]91/** The last assertion message, file name. */
[25528]92RTDATADECL(const char * volatile) g_pszRTAssertFile;
93RT_EXPORT_SYMBOL(g_pszRTAssertFile);
[73762]94/** The last assertion message, line number. */
[25528]95RTDATADECL(uint32_t volatile) g_u32RTAssertLine;
96RT_EXPORT_SYMBOL(g_u32RTAssertLine);
97
98
[25518]99/** Set if assertions are quiet. */
[25528]100static bool volatile g_fQuiet = false;
[25518]101/** Set if assertions may panic. */
[64286]102static bool volatile g_fMayPanic = true;
[25518]103
104
105RTDECL(bool) RTAssertSetQuiet(bool fQuiet)
106{
107 return ASMAtomicXchgBool(&g_fQuiet, fQuiet);
108}
[25528]109RT_EXPORT_SYMBOL(RTAssertSetQuiet);
[25518]110
111
112RTDECL(bool) RTAssertAreQuiet(void)
113{
114 return ASMAtomicUoReadBool(&g_fQuiet);
115}
[25528]116RT_EXPORT_SYMBOL(RTAssertAreQuiet);
[25518]117
118
119RTDECL(bool) RTAssertSetMayPanic(bool fMayPanic)
120{
121 return ASMAtomicXchgBool(&g_fMayPanic, fMayPanic);
122}
[25528]123RT_EXPORT_SYMBOL(RTAssertSetMayPanic);
[25518]124
125
126RTDECL(bool) RTAssertMayPanic(void)
127{
128 return ASMAtomicUoReadBool(&g_fMayPanic);
129}
[25528]130RT_EXPORT_SYMBOL(RTAssertMayPanic);
[25518]131
132
[25528]133RTDECL(void) RTAssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
134{
135 /*
136 * Fill in the globals.
137 */
[30111]138 ASMAtomicUoWritePtr(&g_pszRTAssertExpr, pszExpr);
139 ASMAtomicUoWritePtr(&g_pszRTAssertFile, pszFile);
140 ASMAtomicUoWritePtr(&g_pszRTAssertFunction, pszFunction);
[25528]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);
[1]147
[25528]148 /*
149 * If not quiet, make noise.
150 */
[25518]151 if (!RTAssertAreQuiet())
152 {
[37233]153 RTERRVARS SavedErrVars;
154 RTErrVarsSave(&SavedErrVars);
155
[73762]156#ifdef IPRT_WITH_ASSERT_STACK
157 /* The stack dump. */
[75235]158 static volatile bool s_fDumpingStackAlready = false; /* for simple recursion prevention */
[74344]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. */
[96476]162 bool fStack = (!g_pfnIsDebuggerPresent || !g_pfnIsDebuggerPresent()) && !RTEnvExist("IPRT_ASSERT_NO_STACK");
[74344]163# elif defined(IN_RING3)
164 bool fStack = !RTEnvExist("IPRT_ASSERT_NO_STACK");
165# else
166 bool fStack = true;
167# endif
[75235]168 szStack[0] = '\0';
169 if (fStack && !s_fDumpingStackAlready)
170 {
171 s_fDumpingStackAlready = true;
[74344]172 cchStack = RTDbgStackDumpSelf(szStack, sizeof(szStack), 0);
[75235]173 s_fDumpingStackAlready = false;
174 }
[73762]175 memcpy(g_szRTAssertStack, szStack, cchStack + 1);
176#endif
177
[25528]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 */
[25518]189
[1]190
[96448]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(
[25528]196# endif
[96448]197 "\n!!Assertion Failed!!\n"
198 "Expression: %s\n"
199 "Location : %s(%d) %s\n"
[73762]200# ifdef IPRT_WITH_ASSERT_STACK
[96448]201 "Stack :\n%s\n"
[73762]202# endif
[96448]203 , pszExpr, pszFile, uLine, pszFunction
204# ifdef IPRT_WITH_ASSERT_STACK
205 , szStack
[25528]206# endif
[96448]207 );
[1]208
[25528]209# ifdef IN_RING3
[25518]210 /* print to stderr, helps user and gdb debugging. */
[95809]211# ifndef IPRT_NO_CRT
[25518]212 fprintf(stderr,
213 "\n!!Assertion Failed!!\n"
214 "Expression: %s\n"
215 "Location : %s(%d) %s\n",
[90803]216 RT_VALID_PTR(pszExpr) ? pszExpr : "<none>",
217 RT_VALID_PTR(pszFile) ? pszFile : "<none>",
[25518]218 uLine,
[90803]219 RT_VALID_PTR(pszFunction) ? pszFunction : "");
[95809]220# ifdef IPRT_WITH_ASSERT_STACK
[73762]221 fprintf(stderr, "Stack :\n%s\n", szStack);
[95809]222# endif
[25518]223 fflush(stderr);
[95809]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
[25528]241# endif
242#endif /* !IN_RING0 */
[37233]243
244 RTErrVarsRestore(&SavedErrVars);
[25518]245 }
[1]246}
[25528]247RT_EXPORT_SYMBOL(RTAssertMsg1);
[1]248
249
[25536]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)
[1]258{
[25528]259 va_list vaCopy;
[25536]260 size_t cch;
[1]261
[25528]262 /*
263 * The global first.
264 */
[25536]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 }
[25528]283
284 /*
285 * If not quiet, make some noise.
286 */
[25518]287 if (!RTAssertAreQuiet())
288 {
[37233]289 RTERRVARS SavedErrVars;
290 RTErrVarsSave(&SavedErrVars);
291
[25528]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. */
[25536]299 rtR0AssertNativeMsg2V(fInitial, pszFormat, va);
[1]300
[25528]301#else /* !IN_RING0 */
[96448]302
303# if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT))
304 if (g_pfnRTLogAssert)
[25528]305# endif
[25518]306 {
[25528]307 va_copy(vaCopy, va);
[96448]308# if defined(IN_RING3) && (defined(IN_RT_STATIC) || defined(IPRT_NO_CRT))
309 g_pfnRTLogAssertV(pszFormat, vaCopy);
310# else
311 RTLogAssertV(pszFormat, vaCopy);
[25528]312# endif
313 va_end(vaCopy);
[25518]314 }
[1]315
[25528]316# ifdef IN_RING3
[25518]317 /* print to stderr, helps user and gdb debugging. */
[36827]318 char szMsg[sizeof(g_szRTAssertMsg2)];
[25528]319 va_copy(vaCopy, va);
[95809]320 size_t cchMsg = RTStrPrintfV(szMsg, sizeof(szMsg), pszFormat, vaCopy);
[25528]321 va_end(vaCopy);
[95809]322# ifndef IPRT_NO_CRT
323 fwrite(szMsg, 1, cchMsg, stderr);
[25518]324 fflush(stderr);
[95809]325# else
326 RTLogWriteStdErr(szMsg, cchMsg);
327# endif
[25528]328# endif
329#endif /* !IN_RING0 */
[37233]330
331 RTErrVarsRestore(&SavedErrVars);
[25518]332 }
[1]333}
[25536]334
335
336RTDECL(void) RTAssertMsg2V(const char *pszFormat, va_list va)
337{
338 rtAssertMsg2Worker(true /*fInitial*/, pszFormat, va);
339}
[25528]340RT_EXPORT_SYMBOL(RTAssertMsg2V);
[1]341
[25536]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.

© 2023 Oracle
ContactPrivacy policyTerms of Use