diff options
Diffstat (limited to 'src/corelib/global/qassert.cpp')
-rw-r--r-- | src/corelib/global/qassert.cpp | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/src/corelib/global/qassert.cpp b/src/corelib/global/qassert.cpp new file mode 100644 index 0000000000..6a29cbfa21 --- /dev/null +++ b/src/corelib/global/qassert.cpp @@ -0,0 +1,277 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qassert.h" + +#include <QtCore/qlogging.h> + +#include <cstdlib> +#include <cstdio> +#include <exception> +#ifndef QT_NO_EXCEPTIONS +#include <new> +#endif + +#if defined(Q_CC_MSVC) +# include <crtdbg.h> +#endif +#ifdef Q_OS_WIN +# include <qt_windows.h> +#endif + +QT_BEGIN_NAMESPACE + +void qAbort() +{ +#ifdef Q_OS_WIN + // std::abort() in the MSVC runtime will call _exit(3) if the abort + // behavior is _WRITE_ABORT_MSG - see also _set_abort_behavior(). This is + // the default for a debug-mode build of the runtime. Worse, MinGW's + // std::abort() implementation (in msvcrt.dll) is basically a call to + // _exit(3) too. Unfortunately, _exit() and _Exit() *do* run the static + // destructors of objects in DLLs, a violation of the C++ standard (see + // [support.start.term]). So we bypass std::abort() and directly + // terminate the application. + +# if defined(Q_CC_MSVC) + if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE)) + __fastfail(FAST_FAIL_FATAL_APP_EXIT); +# else + RaiseFailFastException(nullptr, nullptr, 0); +# endif + + // Fallback + TerminateProcess(GetCurrentProcess(), STATUS_FATAL_APP_EXIT); + + // Tell the compiler the application has stopped. + Q_UNREACHABLE_IMPL(); +#else // !Q_OS_WIN + std::abort(); +#endif +} + +/*! + \macro void Q_ASSERT(bool test) + \relates <QtAssert> + + Prints a warning message containing the source code file name and + line number if \a test is \c false. + + Q_ASSERT() is useful for testing pre- and post-conditions + during development. It does nothing if \c QT_NO_DEBUG was defined + during compilation. + + Example: + + \snippet code/src_corelib_global_qglobal.cpp 17 + + If \c b is zero, the Q_ASSERT statement will output the following + message using the qFatal() function: + + \snippet code/src_corelib_global_qglobal.cpp 18 + + \sa Q_ASSERT_X(), qFatal(), {Debugging Techniques} +*/ + +/*! + \macro void Q_ASSERT_X(bool test, const char *where, const char *what) + \relates <QtAssert> + + Prints the message \a what together with the location \a where, + the source file name and line number if \a test is \c false. + + Q_ASSERT_X is useful for testing pre- and post-conditions during + development. It does nothing if \c QT_NO_DEBUG was defined during + compilation. + + Example: + + \snippet code/src_corelib_global_qglobal.cpp 19 + + If \c b is zero, the Q_ASSERT_X statement will output the following + message using the qFatal() function: + + \snippet code/src_corelib_global_qglobal.cpp 20 + + \sa Q_ASSERT(), qFatal(), {Debugging Techniques} +*/ + +/* + The Q_ASSERT macro calls this function when the test fails. +*/ +void qt_assert(const char *assertion, const char *file, int line) noexcept +{ + QMessageLogger(file, line, nullptr) + .fatal("ASSERT: \"%s\" in file %s, line %d", assertion, file, line); +} + +/* + The Q_ASSERT_X macro calls this function when the test fails. +*/ +void qt_assert_x(const char *where, const char *what, const char *file, int line) noexcept +{ + QMessageLogger(file, line, nullptr) + .fatal("ASSERT failure in %s: \"%s\", file %s, line %d", where, what, file, line); +} + +/*! + \macro void Q_CHECK_PTR(void *pointer) + \relates <QtAssert> + + If \a pointer is \nullptr, prints a message containing the source + code's file name and line number, saying that the program ran out + of memory and aborts program execution. It throws \c std::bad_alloc instead + if exceptions are enabled. + + Q_CHECK_PTR does nothing if \c QT_NO_DEBUG and \c QT_NO_EXCEPTIONS were + defined during compilation. Therefore you must not use Q_CHECK_PTR to check + for successful memory allocations because the check will be disabled in + some cases. + + Example: + + \snippet code/src_corelib_global_qglobal.cpp 21 + + \sa qWarning(), {Debugging Techniques} +*/ + +/*! + \fn template <typename T> T *q_check_ptr(T *p) + \relates <QtAssert> + + Uses Q_CHECK_PTR on \a p, then returns \a p. + + This can be used as an inline version of Q_CHECK_PTR. +*/ + +/*! + \internal + The Q_CHECK_PTR macro calls this function if an allocation check + fails. +*/ +void qt_check_pointer(const char *n, int l) noexcept +{ + // make separate printing calls so that the first one may flush; + // the second one could want to allocate memory (fputs prints a + // newline and stderr auto-flushes). + fputs("Out of memory", stderr); + fprintf(stderr, " in %s, line %d\n", n, l); + + std::terminate(); +} + +/* + \internal + Allows you to throw an exception without including <new> + Called internally from Q_CHECK_PTR on certain OS combinations +*/ +void qBadAlloc() +{ +#ifndef QT_NO_EXCEPTIONS + throw std::bad_alloc(); +#else + std::terminate(); +#endif +} + +/*! + \macro void Q_ASSUME(bool expr) + \deprecated + \relates <QtAssert> + \since 5.0 + + Causes the compiler to assume that \a expr is \c true. + + This macro is known to produce worse code than when no assumption was + inserted in the code, with some compiler versions. The arguments passed to + it are always evaluated, even in release mode, with some compilers and not + others, so application code needs to be aware of those possible differences + in behavior. + + Do not use it in new code. It is retained as-is for compatibility with old + code and will likely be removed in the next major version Qt. + + \sa Q_ASSERT(), Q_UNREACHABLE(), Q_LIKELY() +*/ + +/*! + \macro QT_TERMINATE_ON_EXCEPTION(expr) + \relates <QtGlobal> + \internal + + In general, use of the Q_DECL_NOEXCEPT macro is preferred over + Q_DECL_NOTHROW, because it exhibits well-defined behavior and + supports the more powerful Q_DECL_NOEXCEPT_EXPR variant. However, + use of Q_DECL_NOTHROW has the advantage that Windows builds + benefit on a wide range or compiler versions that do not yet + support the C++11 noexcept feature. + + It may therefore be beneficial to use Q_DECL_NOTHROW and emulate + the C++11 behavior manually with an embedded try/catch. + + Qt provides the QT_TERMINATE_ON_EXCEPTION(expr) macro for this + purpose. It either expands to \c expr (if Qt is compiled without + exception support or the compiler supports C++11 noexcept + semantics) or to + \snippet code/src_corelib_global_qglobal.cpp qterminate + otherwise. + + Since this macro expands to just \c expr if the compiler supports + C++11 noexcept, expecting the compiler to take over responsibility + of calling std::terminate() in that case, it should not be used + outside Q_DECL_NOTHROW functions. + + \sa Q_DECL_NOEXCEPT, Q_DECL_NOTHROW, qTerminate() +*/ + +/*! + \macro void Q_UNREACHABLE() + \relates <QtAssert> + \since 5.0 + + Tells the compiler that the current point cannot be reached by any + execution, so it may optimize any code paths leading here as dead code, as + well as code continuing from here. + + This macro is useful to mark impossible conditions. For example, given the + following enum: + + \snippet code/src_corelib_global_qglobal.cpp qunreachable-enum + + One can write a switch table like so: + + \snippet code/src_corelib_global_qglobal.cpp qunreachable-switch + + The advantage of inserting Q_UNREACHABLE() at that point is that the + compiler is told not to generate code for a shape variable containing that + value. If the macro is missing, the compiler will still generate the + necessary comparisons for that value. If the case label were removed, some + compilers could produce a warning that some enum values were not checked. + + By using this macro in impossible conditions, code coverage may be improved + as dead code paths may be eliminated. + + In debug builds the condition is enforced by an assert to facilitate debugging. + + \note Use the macro Q_UNREACHABLE_RETURN() to insert return statements for + compilers that need them, without causing warnings for compilers that + complain about its presence. + + \sa Q_ASSERT(), qFatal(), Q_UNREACHABLE_RETURN() +*/ + +/*! + \macro void Q_UNREACHABLE_RETURN(...) + \relates <QtAssert> + \since 6.5 + + This is equivalent to + \code + Q_UNREACHABLE(); + return __VA_ARGS__; + \endcode + except it omits the return on compilers that would warn about it. + + \sa Q_UNREACHABLE() +*/ +QT_END_NAMESPACE |