1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
5 ** Copyright (C) 2018 Intel Corporation.
6 ** Contact: https://www.qt.io/licensing/
7 **
8 ** This file is part of the QtCore module of the Qt Toolkit.
9 **
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** Commercial License Usage
12 ** Licensees holding valid commercial Qt licenses may use this file in
13 ** accordance with the commercial license agreement provided with the
14 ** Software or, alternatively, in accordance with the terms contained in
15 ** a written agreement between you and The Qt Company. For licensing terms
16 ** and conditions see https://www.qt.io/terms-conditions. For further
17 ** information use the contact form at https://www.qt.io/contact-us.
18 **
19 ** GNU Lesser General Public License Usage
20 ** Alternatively, this file may be used under the terms of the GNU Lesser
21 ** General Public License version 3 as published by the Free Software
22 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
23 ** packaging of this file. Please review the following information to
24 ** ensure the GNU Lesser General Public License version 3 requirements
25 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
26 **
27 ** GNU General Public License Usage
28 ** Alternatively, this file may be used under the terms of the GNU
29 ** General Public License version 2.0 or (at your option) the GNU General
30 ** Public license version 3 or any later version approved by the KDE Free
31 ** Qt Foundation. The licenses are as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
33 ** included in the packaging of this file. Please review the following
34 ** information to ensure the GNU General Public License requirements will
35 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
36 ** https://www.gnu.org/licenses/gpl-3.0.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qglobal_p.h"
43 #include "qlogging.h"
44 #include "qlogging_p.h"
45 #include "qlist.h"
46 #include "qbytearray.h"
47 #include "qscopeguard.h"
48 #include "qstring.h"
49 #include "qvarlengtharray.h"
50 #include "qdebug.h"
51 #include "qmutex.h"
52 #include <QtCore/private/qlocking_p.h>
53 #include "qloggingcategory.h"
54 #ifndef QT_BOOTSTRAPPED
55 #include "qelapsedtimer.h"
56 #include "qdatetime.h"
57 #include "qcoreapplication.h"
58 #include "qthread.h"
59 #include "private/qloggingregistry_p.h"
60 #include "private/qcoreapplication_p.h"
61 #include "private/qsimd_p.h"
62 #include <qtcore_tracepoints_p.h>
63 #endif
64 #ifdef Q_OS_WIN
65 #include <qt_windows.h>
66 #endif
67 #ifdef Q_CC_MSVC
68 #include <intrin.h>
69 #endif
70 #if QT_CONFIG(slog2)
71 #include <sys/slog2.h>
72 #endif
73 #if __has_include(<paths.h>)
74 #include <paths.h>
75 #endif
76 
77 #ifdef Q_OS_ANDROID
78 #include <android/log.h>
79 #endif
80 
81 #ifdef Q_OS_DARWIN
82 #include <QtCore/private/qcore_mac_p.h>
83 #endif
84 
85 #if QT_CONFIG(journald)
86 # define SD_JOURNAL_SUPPRESS_LOCATION
87 # include <systemd/sd-journal.h>
88 # include <syslog.h>
89 #endif
90 #if QT_CONFIG(syslog)
91 # include <syslog.h>
92 #endif
93 #ifdef Q_OS_UNIX
94 # include <sys/types.h>
95 # include <sys/stat.h>
96 # include <unistd.h>
97 # include "private/qcore_unix_p.h"
98 #endif
99 
100 #ifdef Q_OS_WASM
101 #include <emscripten/emscripten.h>
102 #endif
103 
104 #if QT_CONFIG(regularexpression)
105 #  ifdef __UCLIBC__
106 #    if __UCLIBC_HAS_BACKTRACE__
107 #      define QLOGGING_HAVE_BACKTRACE
108 #    endif
109 #  elif (defined(__GLIBC__) && defined(__GLIBCXX__)) || (__has_include(<cxxabi.h>) && __has_include(<execinfo.h>))
110 #    define QLOGGING_HAVE_BACKTRACE
111 #  endif
112 #endif
113 
114 #if QT_CONFIG(slog2)
115 extern char *__progname;
116 #endif
117 
118 #ifndef QT_BOOTSTRAPPED
119 #if defined(Q_OS_LINUX) && (defined(__GLIBC__) || __has_include(<sys/syscall.h>))
120 #  include <sys/syscall.h>
121 
122 # if defined(Q_OS_ANDROID) && !defined(SYS_gettid)
123 #  define SYS_gettid __NR_gettid
124 # endif
125 
qt_gettid()126 static long qt_gettid()
127 {
128     // no error handling
129     // this syscall has existed since Linux 2.4.11 and cannot fail
130     return syscall(SYS_gettid);
131 }
132 #elif defined(Q_OS_DARWIN)
133 #  include <pthread.h>
qt_gettid()134 static int qt_gettid()
135 {
136     // no error handling: this call cannot fail
137     __uint64_t tid;
138     pthread_threadid_np(NULL, &tid);
139     return tid;
140 }
141 #elif defined(Q_OS_FREEBSD_KERNEL) && defined(__FreeBSD_version) && __FreeBSD_version >= 900031
142 #  include <pthread_np.h>
qt_gettid()143 static int qt_gettid()
144 {
145     return pthread_getthreadid_np();
146 }
147 #else
qt_gettid()148 static QT_PREPEND_NAMESPACE(qint64) qt_gettid()
149 {
150     QT_USE_NAMESPACE
151     return qintptr(QThread::currentThreadId());
152 }
153 #endif
154 
155 #ifdef QLOGGING_HAVE_BACKTRACE
156 #  include <qregularexpression.h>
157 #  include <cxxabi.h>
158 #  include <execinfo.h>
159 #endif
160 #endif // !QT_BOOTSTRAPPED
161 
162 #include <cstdlib>
163 #include <algorithm>
164 #include <memory>
165 #include <vector>
166 
167 #include <stdio.h>
168 
169 QT_BEGIN_NAMESPACE
170 
171 #if !defined(Q_CC_MSVC)
172 Q_NORETURN
173 #endif
174 static void qt_message_fatal(QtMsgType, const QMessageLogContext &context, const QString &message);
175 static void qt_message_print(QtMsgType, const QMessageLogContext &context, const QString &message);
176 static void qt_message_print(const QString &message);
177 
checked_var_value(const char * varname)178 static int checked_var_value(const char *varname)
179 {
180     // qEnvironmentVariableIntValue returns 0 on both parsing failure and on
181     // empty, but we need to distinguish between the two for backwards
182     // compatibility reasons.
183     QByteArray str = qgetenv(varname);
184     if (str.isEmpty())
185         return 0;
186 
187     bool ok;
188     int value = str.toInt(&ok, 0);
189     return ok ? value : 1;
190 }
191 
isFatal(QtMsgType msgType)192 static bool isFatal(QtMsgType msgType)
193 {
194     if (msgType == QtFatalMsg)
195         return true;
196 
197     if (msgType == QtCriticalMsg) {
198         static QAtomicInt fatalCriticals = checked_var_value("QT_FATAL_CRITICALS");
199 
200         // it's fatal if the current value is exactly 1,
201         // otherwise decrement if it's non-zero
202         return fatalCriticals.loadRelaxed() && fatalCriticals.fetchAndAddRelaxed(-1) == 1;
203     }
204 
205     if (msgType == QtWarningMsg || msgType == QtCriticalMsg) {
206         static QAtomicInt fatalWarnings = checked_var_value("QT_FATAL_WARNINGS");
207 
208         // it's fatal if the current value is exactly 1,
209         // otherwise decrement if it's non-zero
210         return fatalWarnings.loadRelaxed() && fatalWarnings.fetchAndAddRelaxed(-1) == 1;
211     }
212 
213     return false;
214 }
215 
isDefaultCategory(const char * category)216 static bool isDefaultCategory(const char *category)
217 {
218     return !category || strcmp(category, "default") == 0;
219 }
220 
221 /*!
222     Returns true if writing to \c stderr is supported.
223 
224     \internal
225     \sa stderrHasConsoleAttached()
226 */
systemHasStderr()227 static bool systemHasStderr()
228 {
229 #if defined(Q_OS_WINRT)
230     return false; // WinRT has no stderr
231 #endif
232 
233     return true;
234 }
235 
236 /*!
237     Returns true if writing to \c stderr will end up in a console/terminal visible to the user.
238 
239     This is typically the case if the application was started from the command line.
240 
241     If the application is started without a controlling console/terminal, but the parent
242     process reads \c stderr and presents it to the user in some other way, the parent process
243     may override the detection in this function by setting the QT_ASSUME_STDERR_HAS_CONSOLE
244     environment variable to \c 1.
245 
246     \note Qt Creator does not implement a pseudo TTY, nor does it launch apps with
247     the override environment variable set, but it will read stderr and print it to
248     the user, so in effect this function cannot be used to conclude that stderr
249     output will _not_ be visible to the user, as even if this function returns false,
250     the output might still end up visible to the user. For this reason, we don't guard
251     the stderr output in the default message handler with stderrHasConsoleAttached().
252 
253     \internal
254     \sa systemHasStderr()
255 */
stderrHasConsoleAttached()256 static bool stderrHasConsoleAttached()
257 {
258     static const bool stderrHasConsoleAttached = []() -> bool {
259         if (!systemHasStderr())
260             return false;
261 
262         if (qEnvironmentVariableIntValue("QT_LOGGING_TO_CONSOLE")) {
263             fprintf(stderr, "warning: Environment variable QT_LOGGING_TO_CONSOLE is deprecated, use\n"
264                             "QT_ASSUME_STDERR_HAS_CONSOLE and/or QT_FORCE_STDERR_LOGGING instead.\n");
265             return true;
266         }
267 
268         if (qEnvironmentVariableIntValue("QT_ASSUME_STDERR_HAS_CONSOLE"))
269             return true;
270 
271 #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
272         return GetConsoleWindow();
273 #elif defined(Q_OS_UNIX)
274 #       ifndef _PATH_TTY
275 #       define _PATH_TTY "/dev/tty"
276 #       endif
277 
278         // If we can open /dev/tty, we have a controlling TTY
279         int ttyDevice = -1;
280         if ((ttyDevice = qt_safe_open(_PATH_TTY, O_RDONLY)) >= 0) {
281             qt_safe_close(ttyDevice);
282             return true;
283         } else if (errno == ENOENT || errno == EPERM || errno == ENXIO) {
284             // Fall back to isatty for some non-critical errors
285             return isatty(STDERR_FILENO);
286         } else {
287             return false;
288         }
289 #else
290         return false; // No way to detect if stderr has a console attached
291 #endif
292     }();
293 
294     return stderrHasConsoleAttached;
295 }
296 
297 
298 namespace QtPrivate {
299 
300 /*!
301     Returns true if logging \c stderr should be ensured.
302 
303     This is normally the case if \c stderr has a console attached, but may be overridden
304     by the user by setting the QT_FORCE_STDERR_LOGGING environment variable to \c 1.
305 
306     \internal
307     \sa stderrHasConsoleAttached()
308 */
shouldLogToStderr()309 bool shouldLogToStderr()
310 {
311     static bool forceStderrLogging = qEnvironmentVariableIntValue("QT_FORCE_STDERR_LOGGING");
312     return forceStderrLogging || stderrHasConsoleAttached();
313 }
314 
315 
316 } // QtPrivate
317 
318 using namespace QtPrivate;
319 
320 /*!
321     \class QMessageLogContext
322     \inmodule QtCore
323     \brief The QMessageLogContext class provides additional information about a log message.
324     \since 5.0
325 
326     The class provides information about the source code location a qDebug(), qInfo(), qWarning(),
327     qCritical() or qFatal() message was generated.
328 
329     \note By default, this information is recorded only in debug builds. You can overwrite
330     this explicitly by defining \c QT_MESSAGELOGCONTEXT or \c{QT_NO_MESSAGELOGCONTEXT}.
331 
332     \sa QMessageLogger, QtMessageHandler, qInstallMessageHandler()
333 */
334 
335 /*!
336     \class QMessageLogger
337     \inmodule QtCore
338     \brief The QMessageLogger class generates log messages.
339     \since 5.0
340 
341     QMessageLogger is used to generate messages for the Qt logging framework. Usually one uses
342     it through qDebug(), qInfo(), qWarning(), qCritical, or qFatal() functions,
343     which are actually macros: For example qDebug() expands to
344     QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug()
345     for debug builds, and QMessageLogger(0, 0, 0).debug() for release builds.
346 
347     One example of direct use is to forward errors that stem from a scripting language, e.g. QML:
348 
349     \snippet code/qlogging/qlogging.cpp 1
350 
351     \sa QMessageLogContext, qDebug(), qInfo(), qWarning(), qCritical(), qFatal()
352 */
353 
354 #if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
convert_to_wchar_t_elided(wchar_t * d,size_t space,const char * s)355 static inline void convert_to_wchar_t_elided(wchar_t *d, size_t space, const char *s) noexcept
356 {
357     size_t len = qstrlen(s);
358     if (len + 1 > space) {
359         const size_t skip = len - space + 4; // 4 for "..." + '\0'
360         s += skip;
361         len -= skip;
362         for (int i = 0; i < 3; ++i)
363           *d++ = L'.';
364     }
365     while (len--)
366         *d++ = *s++;
367     *d++ = 0;
368 }
369 #endif
370 
371 /*!
372     \internal
373 */
374 Q_NEVER_INLINE
qt_message(QtMsgType msgType,const QMessageLogContext & context,const char * msg,va_list ap)375 static QString qt_message(QtMsgType msgType, const QMessageLogContext &context, const char *msg, va_list ap)
376 {
377     QString buf = QString::vasprintf(msg, ap);
378     qt_message_print(msgType, context, buf);
379     return buf;
380 }
381 
382 #undef qDebug
383 /*!
384     Logs a debug message specified with format \a msg. Additional
385     parameters, specified by \a msg, may be used.
386 
387     \sa qDebug()
388 */
debug(const char * msg,...) const389 void QMessageLogger::debug(const char *msg, ...) const
390 {
391     va_list ap;
392     va_start(ap, msg); // use variable arg list
393     const QString message = qt_message(QtDebugMsg, context, msg, ap);
394     va_end(ap);
395 
396     if (isFatal(QtDebugMsg))
397         qt_message_fatal(QtDebugMsg, context, message);
398 }
399 
400 
401 #undef qInfo
402 /*!
403     Logs an informational message specified with format \a msg. Additional
404     parameters, specified by \a msg, may be used.
405 
406     \sa qInfo()
407     \since 5.5
408 */
info(const char * msg,...) const409 void QMessageLogger::info(const char *msg, ...) const
410 {
411     va_list ap;
412     va_start(ap, msg); // use variable arg list
413     const QString message = qt_message(QtInfoMsg, context, msg, ap);
414     va_end(ap);
415 
416     if (isFatal(QtInfoMsg))
417         qt_message_fatal(QtInfoMsg, context, message);
418 }
419 
420 /*!
421     \typedef QMessageLogger::CategoryFunction
422 
423     This is a typedef for a pointer to a function with the following
424     signature:
425 
426     \snippet code/qlogging/qlogging.cpp 2
427 
428     A function which this signature is generated by Q_DECLARE_LOGGING_CATEGORY,
429     Q_LOGGING_CATEGORY.
430 
431     \since 5.3
432 */
433 
434 /*!
435     Logs a debug message specified with format \a msg for the context \a cat.
436     Additional parameters, specified by \a msg, may be used.
437 
438     \since 5.3
439     \sa qCDebug()
440 */
debug(const QLoggingCategory & cat,const char * msg,...) const441 void QMessageLogger::debug(const QLoggingCategory &cat, const char *msg, ...) const
442 {
443     if (!cat.isDebugEnabled())
444         return;
445 
446     QMessageLogContext ctxt;
447     ctxt.copyContextFrom(context);
448     ctxt.category = cat.categoryName();
449 
450     va_list ap;
451     va_start(ap, msg); // use variable arg list
452     const QString message = qt_message(QtDebugMsg, ctxt, msg, ap);
453     va_end(ap);
454 
455     if (isFatal(QtDebugMsg))
456         qt_message_fatal(QtDebugMsg, ctxt, message);
457 }
458 
459 /*!
460     Logs a debug message specified with format \a msg for the context returned
461     by \a catFunc. Additional parameters, specified by \a msg, may be used.
462 
463     \since 5.3
464     \sa qCDebug()
465 */
debug(QMessageLogger::CategoryFunction catFunc,const char * msg,...) const466 void QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc,
467                            const char *msg, ...) const
468 {
469     const QLoggingCategory &cat = (*catFunc)();
470     if (!cat.isDebugEnabled())
471         return;
472 
473     QMessageLogContext ctxt;
474     ctxt.copyContextFrom(context);
475     ctxt.category = cat.categoryName();
476 
477     va_list ap;
478     va_start(ap, msg); // use variable arg list
479     const QString message = qt_message(QtDebugMsg, ctxt, msg, ap);
480     va_end(ap);
481 
482     if (isFatal(QtDebugMsg))
483         qt_message_fatal(QtDebugMsg, ctxt, message);
484 }
485 
486 #ifndef QT_NO_DEBUG_STREAM
487 
488 /*!
489     Logs a debug message using a QDebug stream
490 
491     \sa qDebug(), QDebug
492 */
debug() const493 QDebug QMessageLogger::debug() const
494 {
495     QDebug dbg = QDebug(QtDebugMsg);
496     QMessageLogContext &ctxt = dbg.stream->context;
497     ctxt.copyContextFrom(context);
498     return dbg;
499 }
500 
501 /*!
502     Logs a debug message into category \a cat using a QDebug stream.
503 
504     \since 5.3
505     \sa qCDebug(), QDebug
506 */
debug(const QLoggingCategory & cat) const507 QDebug QMessageLogger::debug(const QLoggingCategory &cat) const
508 {
509     QDebug dbg = QDebug(QtDebugMsg);
510     if (!cat.isDebugEnabled())
511         dbg.stream->message_output = false;
512 
513     QMessageLogContext &ctxt = dbg.stream->context;
514     ctxt.copyContextFrom(context);
515     ctxt.category = cat.categoryName();
516 
517     return dbg;
518 }
519 
520 /*!
521     Logs a debug message into category returned by \a catFunc using a QDebug stream.
522 
523     \since 5.3
524     \sa qCDebug(), QDebug
525 */
debug(QMessageLogger::CategoryFunction catFunc) const526 QDebug QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc) const
527 {
528     return debug((*catFunc)());
529 }
530 
531 /*!
532     \internal
533 
534     Returns a QNoDebug object, which is used to ignore debugging output.
535 
536     \sa QNoDebug, qDebug()
537 */
noDebug() const538 QNoDebug QMessageLogger::noDebug() const noexcept
539 {
540     return QNoDebug();
541 }
542 
543 #endif
544 
545 /*!
546     Logs an informational message specified with format \a msg for the context \a cat.
547     Additional parameters, specified by \a msg, may be used.
548 
549     \since 5.5
550     \sa qCInfo()
551 */
info(const QLoggingCategory & cat,const char * msg,...) const552 void QMessageLogger::info(const QLoggingCategory &cat, const char *msg, ...) const
553 {
554     if (!cat.isInfoEnabled())
555         return;
556 
557     QMessageLogContext ctxt;
558     ctxt.copyContextFrom(context);
559     ctxt.category = cat.categoryName();
560 
561     va_list ap;
562     va_start(ap, msg); // use variable arg list
563     const QString message = qt_message(QtInfoMsg, ctxt, msg, ap);
564     va_end(ap);
565 
566     if (isFatal(QtInfoMsg))
567         qt_message_fatal(QtInfoMsg, ctxt, message);
568 }
569 
570 /*!
571     Logs an informational message specified with format \a msg for the context returned
572     by \a catFunc. Additional parameters, specified by \a msg, may be used.
573 
574     \since 5.5
575     \sa qCInfo()
576 */
info(QMessageLogger::CategoryFunction catFunc,const char * msg,...) const577 void QMessageLogger::info(QMessageLogger::CategoryFunction catFunc,
578                            const char *msg, ...) const
579 {
580     const QLoggingCategory &cat = (*catFunc)();
581     if (!cat.isInfoEnabled())
582         return;
583 
584     QMessageLogContext ctxt;
585     ctxt.copyContextFrom(context);
586     ctxt.category = cat.categoryName();
587 
588     va_list ap;
589     va_start(ap, msg); // use variable arg list
590     const QString message = qt_message(QtInfoMsg, ctxt, msg, ap);
591     va_end(ap);
592 
593     if (isFatal(QtInfoMsg))
594         qt_message_fatal(QtInfoMsg, ctxt, message);
595 }
596 
597 #ifndef QT_NO_DEBUG_STREAM
598 
599 /*!
600     Logs an informational message using a QDebug stream.
601 
602     \since 5.5
603     \sa qInfo(), QDebug
604 */
info() const605 QDebug QMessageLogger::info() const
606 {
607     QDebug dbg = QDebug(QtInfoMsg);
608     QMessageLogContext &ctxt = dbg.stream->context;
609     ctxt.copyContextFrom(context);
610     return dbg;
611 }
612 
613 /*!
614     Logs an informational message into the category \a cat using a QDebug stream.
615 
616     \since 5.5
617     \sa qCInfo(), QDebug
618 */
info(const QLoggingCategory & cat) const619 QDebug QMessageLogger::info(const QLoggingCategory &cat) const
620 {
621     QDebug dbg = QDebug(QtInfoMsg);
622     if (!cat.isInfoEnabled())
623         dbg.stream->message_output = false;
624 
625     QMessageLogContext &ctxt = dbg.stream->context;
626     ctxt.copyContextFrom(context);
627     ctxt.category = cat.categoryName();
628 
629     return dbg;
630 }
631 
632 /*!
633     Logs an informational message into category returned by \a catFunc using a QDebug stream.
634 
635     \since 5.5
636     \sa qCInfo(), QDebug
637 */
info(QMessageLogger::CategoryFunction catFunc) const638 QDebug QMessageLogger::info(QMessageLogger::CategoryFunction catFunc) const
639 {
640     return info((*catFunc)());
641 }
642 
643 #endif
644 
645 #undef qWarning
646 /*!
647     Logs a warning message specified with format \a msg. Additional
648     parameters, specified by \a msg, may be used.
649 
650     \sa qWarning()
651 */
warning(const char * msg,...) const652 void QMessageLogger::warning(const char *msg, ...) const
653 {
654     va_list ap;
655     va_start(ap, msg); // use variable arg list
656     const QString message = qt_message(QtWarningMsg, context, msg, ap);
657     va_end(ap);
658 
659     if (isFatal(QtWarningMsg))
660         qt_message_fatal(QtWarningMsg, context, message);
661 }
662 
663 /*!
664     Logs a warning message specified with format \a msg for the context \a cat.
665     Additional parameters, specified by \a msg, may be used.
666 
667     \since 5.3
668     \sa qCWarning()
669 */
warning(const QLoggingCategory & cat,const char * msg,...) const670 void QMessageLogger::warning(const QLoggingCategory &cat, const char *msg, ...) const
671 {
672     if (!cat.isWarningEnabled())
673         return;
674 
675     QMessageLogContext ctxt;
676     ctxt.copyContextFrom(context);
677     ctxt.category = cat.categoryName();
678 
679     va_list ap;
680     va_start(ap, msg); // use variable arg list
681     const QString message = qt_message(QtWarningMsg, ctxt, msg, ap);
682     va_end(ap);
683 
684     if (isFatal(QtWarningMsg))
685         qt_message_fatal(QtWarningMsg, ctxt, message);
686 }
687 
688 /*!
689     Logs a warning message specified with format \a msg for the context returned
690     by \a catFunc. Additional parameters, specified by \a msg, may be used.
691 
692     \since 5.3
693     \sa qCWarning()
694 */
warning(QMessageLogger::CategoryFunction catFunc,const char * msg,...) const695 void QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc,
696                              const char *msg, ...) const
697 {
698     const QLoggingCategory &cat = (*catFunc)();
699     if (!cat.isWarningEnabled())
700         return;
701 
702     QMessageLogContext ctxt;
703     ctxt.copyContextFrom(context);
704     ctxt.category = cat.categoryName();
705 
706     va_list ap;
707     va_start(ap, msg); // use variable arg list
708     const QString message = qt_message(QtWarningMsg, ctxt, msg, ap);
709     va_end(ap);
710 
711     if (isFatal(QtWarningMsg))
712         qt_message_fatal(QtWarningMsg, ctxt, message);
713 }
714 
715 #ifndef QT_NO_DEBUG_STREAM
716 /*!
717     Logs a warning message using a QDebug stream
718 
719     \sa qWarning(), QDebug
720 */
warning() const721 QDebug QMessageLogger::warning() const
722 {
723     QDebug dbg = QDebug(QtWarningMsg);
724     QMessageLogContext &ctxt = dbg.stream->context;
725     ctxt.copyContextFrom(context);
726     return dbg;
727 }
728 
729 /*!
730     Logs a warning message into category \a cat using a QDebug stream.
731 
732     \sa qCWarning(), QDebug
733 */
warning(const QLoggingCategory & cat) const734 QDebug QMessageLogger::warning(const QLoggingCategory &cat) const
735 {
736     QDebug dbg = QDebug(QtWarningMsg);
737     if (!cat.isWarningEnabled())
738         dbg.stream->message_output = false;
739 
740     QMessageLogContext &ctxt = dbg.stream->context;
741     ctxt.copyContextFrom(context);
742     ctxt.category = cat.categoryName();
743 
744     return dbg;
745 }
746 
747 /*!
748     Logs a warning message into category returned by \a catFunc using a QDebug stream.
749 
750     \since 5.3
751     \sa qCWarning(), QDebug
752 */
warning(QMessageLogger::CategoryFunction catFunc) const753 QDebug QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc) const
754 {
755     return warning((*catFunc)());
756 }
757 
758 #endif
759 
760 #undef qCritical
761 
762 /*!
763     Logs a critical message specified with format \a msg. Additional
764     parameters, specified by \a msg, may be used.
765 
766     \sa qCritical()
767 */
critical(const char * msg,...) const768 void QMessageLogger::critical(const char *msg, ...) const
769 {
770     va_list ap;
771     va_start(ap, msg); // use variable arg list
772     const QString message = qt_message(QtCriticalMsg, context, msg, ap);
773     va_end(ap);
774 
775     if (isFatal(QtCriticalMsg))
776         qt_message_fatal(QtCriticalMsg, context, message);
777 }
778 
779 /*!
780     Logs a critical message specified with format \a msg for the context \a cat.
781     Additional parameters, specified by \a msg, may be used.
782 
783     \since 5.3
784     \sa qCCritical()
785 */
critical(const QLoggingCategory & cat,const char * msg,...) const786 void QMessageLogger::critical(const QLoggingCategory &cat, const char *msg, ...) const
787 {
788     if (!cat.isCriticalEnabled())
789         return;
790 
791     QMessageLogContext ctxt;
792     ctxt.copyContextFrom(context);
793     ctxt.category = cat.categoryName();
794 
795     va_list ap;
796     va_start(ap, msg); // use variable arg list
797     const QString message = qt_message(QtCriticalMsg, ctxt, msg, ap);
798     va_end(ap);
799 
800     if (isFatal(QtCriticalMsg))
801         qt_message_fatal(QtCriticalMsg, ctxt, message);
802 }
803 
804 /*!
805     Logs a critical message specified with format \a msg for the context returned
806     by \a catFunc. Additional parameters, specified by \a msg, may be used.
807 
808     \since 5.3
809     \sa qCCritical()
810 */
critical(QMessageLogger::CategoryFunction catFunc,const char * msg,...) const811 void QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc,
812                               const char *msg, ...) const
813 {
814     const QLoggingCategory &cat = (*catFunc)();
815     if (!cat.isCriticalEnabled())
816         return;
817 
818     QMessageLogContext ctxt;
819     ctxt.copyContextFrom(context);
820     ctxt.category = cat.categoryName();
821 
822     va_list ap;
823     va_start(ap, msg); // use variable arg list
824     const QString message = qt_message(QtCriticalMsg, ctxt, msg, ap);
825     va_end(ap);
826 
827     if (isFatal(QtCriticalMsg))
828         qt_message_fatal(QtCriticalMsg, ctxt, message);
829 }
830 
831 #ifndef QT_NO_DEBUG_STREAM
832 /*!
833     Logs a critical message using a QDebug stream
834 
835     \sa qCritical(), QDebug
836 */
critical() const837 QDebug QMessageLogger::critical() const
838 {
839     QDebug dbg = QDebug(QtCriticalMsg);
840     QMessageLogContext &ctxt = dbg.stream->context;
841     ctxt.copyContextFrom(context);
842     return dbg;
843 }
844 
845 /*!
846     Logs a critical message into category \a cat using a QDebug stream.
847 
848     \since 5.3
849     \sa qCCritical(), QDebug
850 */
critical(const QLoggingCategory & cat) const851 QDebug QMessageLogger::critical(const QLoggingCategory &cat) const
852 {
853     QDebug dbg = QDebug(QtCriticalMsg);
854     if (!cat.isCriticalEnabled())
855         dbg.stream->message_output = false;
856 
857     QMessageLogContext &ctxt = dbg.stream->context;
858     ctxt.copyContextFrom(context);
859     ctxt.category = cat.categoryName();
860 
861     return dbg;
862 }
863 
864 /*!
865     Logs a critical message into category returned by \a catFunc using a QDebug stream.
866 
867     \since 5.3
868     \sa qCCritical(), QDebug
869 */
critical(QMessageLogger::CategoryFunction catFunc) const870 QDebug QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc) const
871 {
872     return critical((*catFunc)());
873 }
874 
875 #endif
876 
877 #undef qFatal
878 /*!
879     Logs a fatal message specified with format \a msg. Additional
880     parameters, specified by \a msg, may be used.
881 
882     \sa qFatal()
883 */
fatal(const char * msg,...) const884 void QMessageLogger::fatal(const char *msg, ...) const noexcept
885 {
886     QString message;
887 
888     va_list ap;
889     va_start(ap, msg); // use variable arg list
890     QT_TERMINATE_ON_EXCEPTION(message = qt_message(QtFatalMsg, context, msg, ap));
891     va_end(ap);
892 
893     qt_message_fatal(QtFatalMsg, context, message);
894 }
895 
896 /*!
897     \internal
898 */
qCleanupFuncinfo(QByteArray info)899 Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info)
900 {
901     // Strip the function info down to the base function name
902     // note that this throws away the template definitions,
903     // the parameter types (overloads) and any const/volatile qualifiers.
904 
905     if (info.isEmpty())
906         return info;
907 
908     int pos;
909 
910     // Skip trailing [with XXX] for templates (gcc), but make
911     // sure to not affect Objective-C message names.
912     pos = info.size() - 1;
913     if (info.endsWith(']') && !(info.startsWith('+') || info.startsWith('-'))) {
914         while (--pos) {
915             if (info.at(pos) == '[')
916                 info.truncate(pos);
917         }
918     }
919 
920     // operator names with '(', ')', '<', '>' in it
921     static const char operator_call[] = "operator()";
922     static const char operator_lessThan[] = "operator<";
923     static const char operator_greaterThan[] = "operator>";
924     static const char operator_lessThanEqual[] = "operator<=";
925     static const char operator_greaterThanEqual[] = "operator>=";
926 
927     // canonize operator names
928     info.replace("operator ", "operator");
929 
930     // remove argument list
931     forever {
932         int parencount = 0;
933         pos = info.lastIndexOf(')');
934         if (pos == -1) {
935             // Don't know how to parse this function name
936             return info;
937         }
938 
939         // find the beginning of the argument list
940         --pos;
941         ++parencount;
942         while (pos && parencount) {
943             if (info.at(pos) == ')')
944                 ++parencount;
945             else if (info.at(pos) == '(')
946                 --parencount;
947             --pos;
948         }
949         if (parencount != 0)
950             return info;
951 
952         info.truncate(++pos);
953 
954         if (info.at(pos - 1) == ')') {
955             if (info.indexOf(operator_call) == pos - (int)strlen(operator_call))
956                 break;
957 
958             // this function returns a pointer to a function
959             // and we matched the arguments of the return type's parameter list
960             // try again
961             info.remove(0, info.indexOf('('));
962             info.chop(1);
963             continue;
964         } else {
965             break;
966         }
967     }
968 
969     // find the beginning of the function name
970     int parencount = 0;
971     int templatecount = 0;
972     --pos;
973 
974     // make sure special characters in operator names are kept
975     if (pos > -1) {
976         switch (info.at(pos)) {
977         case ')':
978             if (info.indexOf(operator_call) == pos - (int)strlen(operator_call) + 1)
979                 pos -= 2;
980             break;
981         case '<':
982             if (info.indexOf(operator_lessThan) == pos - (int)strlen(operator_lessThan) + 1)
983                 --pos;
984             break;
985         case '>':
986             if (info.indexOf(operator_greaterThan) == pos - (int)strlen(operator_greaterThan) + 1)
987                 --pos;
988             break;
989         case '=': {
990             int operatorLength = (int)strlen(operator_lessThanEqual);
991             if (info.indexOf(operator_lessThanEqual) == pos - operatorLength + 1)
992                 pos -= 2;
993             else if (info.indexOf(operator_greaterThanEqual) == pos - operatorLength + 1)
994                 pos -= 2;
995             break;
996         }
997         default:
998             break;
999         }
1000     }
1001 
1002     while (pos > -1) {
1003         if (parencount < 0 || templatecount < 0)
1004             return info;
1005 
1006         char c = info.at(pos);
1007         if (c == ')')
1008             ++parencount;
1009         else if (c == '(')
1010             --parencount;
1011         else if (c == '>')
1012             ++templatecount;
1013         else if (c == '<')
1014             --templatecount;
1015         else if (c == ' ' && templatecount == 0 && parencount == 0)
1016             break;
1017 
1018         --pos;
1019     }
1020     info = info.mid(pos + 1);
1021 
1022     // remove trailing '*', '&' that are part of the return argument
1023     while ((info.at(0) == '*')
1024            || (info.at(0) == '&'))
1025         info = info.mid(1);
1026 
1027     // we have the full function name now.
1028     // clean up the templates
1029     while ((pos = info.lastIndexOf('>')) != -1) {
1030         if (!info.contains('<'))
1031             break;
1032 
1033         // find the matching close
1034         int end = pos;
1035         templatecount = 1;
1036         --pos;
1037         while (pos && templatecount) {
1038             char c = info.at(pos);
1039             if (c == '>')
1040                 ++templatecount;
1041             else if (c == '<')
1042                 --templatecount;
1043             --pos;
1044         }
1045         ++pos;
1046         info.remove(pos, end - pos + 1);
1047     }
1048 
1049     return info;
1050 }
1051 
1052 // tokens as recognized in QT_MESSAGE_PATTERN
1053 static const char categoryTokenC[] = "%{category}";
1054 static const char typeTokenC[] = "%{type}";
1055 static const char messageTokenC[] = "%{message}";
1056 static const char fileTokenC[] = "%{file}";
1057 static const char lineTokenC[] = "%{line}";
1058 static const char functionTokenC[] = "%{function}";
1059 static const char pidTokenC[] = "%{pid}";
1060 static const char appnameTokenC[] = "%{appname}";
1061 static const char threadidTokenC[] = "%{threadid}";
1062 static const char qthreadptrTokenC[] = "%{qthreadptr}";
1063 static const char timeTokenC[] = "%{time"; //not a typo: this command has arguments
1064 static const char backtraceTokenC[] = "%{backtrace"; //ditto
1065 static const char ifCategoryTokenC[] = "%{if-category}";
1066 static const char ifDebugTokenC[] = "%{if-debug}";
1067 static const char ifInfoTokenC[] = "%{if-info}";
1068 static const char ifWarningTokenC[] = "%{if-warning}";
1069 static const char ifCriticalTokenC[] = "%{if-critical}";
1070 static const char ifFatalTokenC[] = "%{if-fatal}";
1071 static const char endifTokenC[] = "%{endif}";
1072 static const char emptyTokenC[] = "";
1073 
1074 static const char defaultPattern[] = "%{if-category}%{category}: %{endif}%{message}";
1075 
1076 
1077 struct QMessagePattern {
1078     QMessagePattern();
1079     ~QMessagePattern();
1080 
1081     void setPattern(const QString &pattern);
1082 
1083     // 0 terminated arrays of literal tokens / literal or placeholder tokens
1084     std::unique_ptr<std::unique_ptr<const char[]>[]> literals;
1085     std::unique_ptr<const char*[]> tokens;
1086     QList<QString> timeArgs;   // timeFormats in sequence of %{time
1087 #ifndef QT_BOOTSTRAPPED
1088     QElapsedTimer timer;
1089 #endif
1090 #ifdef QLOGGING_HAVE_BACKTRACE
1091     struct BacktraceParams {
1092         QString backtraceSeparator;
1093         int backtraceDepth;
1094     };
1095     QVector<BacktraceParams> backtraceArgs; // backtrace argumens in sequence of %{backtrace
1096 #endif
1097 
1098     bool fromEnvironment;
1099     static QBasicMutex mutex;
1100 };
1101 #ifdef QLOGGING_HAVE_BACKTRACE
1102 Q_DECLARE_TYPEINFO(QMessagePattern::BacktraceParams, Q_MOVABLE_TYPE);
1103 #endif
1104 
1105 QBasicMutex QMessagePattern::mutex;
1106 
QMessagePattern()1107 QMessagePattern::QMessagePattern()
1108 {
1109 #ifndef QT_BOOTSTRAPPED
1110     timer.start();
1111 #endif
1112     const QString envPattern = QString::fromLocal8Bit(qgetenv("QT_MESSAGE_PATTERN"));
1113     if (envPattern.isEmpty()) {
1114         setPattern(QLatin1String(defaultPattern));
1115         fromEnvironment = false;
1116     } else {
1117         setPattern(envPattern);
1118         fromEnvironment = true;
1119     }
1120 }
1121 
1122 QMessagePattern::~QMessagePattern()
1123     = default;
1124 
setPattern(const QString & pattern)1125 void QMessagePattern::setPattern(const QString &pattern)
1126 {
1127     timeArgs.clear();
1128 #ifdef QLOGGING_HAVE_BACKTRACE
1129     backtraceArgs.clear();
1130 #endif
1131 
1132     // scanner
1133     QList<QString> lexemes;
1134     QString lexeme;
1135     bool inPlaceholder = false;
1136     for (int i = 0; i < pattern.size(); ++i) {
1137         const QChar c = pattern.at(i);
1138         if ((c == QLatin1Char('%'))
1139                 && !inPlaceholder) {
1140             if ((i + 1 < pattern.size())
1141                     && pattern.at(i + 1) == QLatin1Char('{')) {
1142                 // beginning of placeholder
1143                 if (!lexeme.isEmpty()) {
1144                     lexemes.append(lexeme);
1145                     lexeme.clear();
1146                 }
1147                 inPlaceholder = true;
1148             }
1149         }
1150 
1151         lexeme.append(c);
1152 
1153         if ((c == QLatin1Char('}') && inPlaceholder)) {
1154             // end of placeholder
1155             lexemes.append(lexeme);
1156             lexeme.clear();
1157             inPlaceholder = false;
1158         }
1159     }
1160     if (!lexeme.isEmpty())
1161         lexemes.append(lexeme);
1162 
1163     // tokenizer
1164     std::vector<std::unique_ptr<const char[]>> literalsVar;
1165     tokens.reset(new const char*[lexemes.size() + 1]);
1166     tokens[lexemes.size()] = nullptr;
1167 
1168     bool nestedIfError = false;
1169     bool inIf = false;
1170     QString error;
1171 
1172     for (int i = 0; i < lexemes.size(); ++i) {
1173         const QString lexeme = lexemes.at(i);
1174         if (lexeme.startsWith(QLatin1String("%{"))
1175                 && lexeme.endsWith(QLatin1Char('}'))) {
1176             // placeholder
1177             if (lexeme == QLatin1String(typeTokenC)) {
1178                 tokens[i] = typeTokenC;
1179             } else if (lexeme == QLatin1String(categoryTokenC))
1180                 tokens[i] = categoryTokenC;
1181             else if (lexeme == QLatin1String(messageTokenC))
1182                 tokens[i] = messageTokenC;
1183             else if (lexeme == QLatin1String(fileTokenC))
1184                 tokens[i] = fileTokenC;
1185             else if (lexeme == QLatin1String(lineTokenC))
1186                 tokens[i] = lineTokenC;
1187             else if (lexeme == QLatin1String(functionTokenC))
1188                 tokens[i] = functionTokenC;
1189             else if (lexeme == QLatin1String(pidTokenC))
1190                 tokens[i] = pidTokenC;
1191             else if (lexeme == QLatin1String(appnameTokenC))
1192                 tokens[i] = appnameTokenC;
1193             else if (lexeme == QLatin1String(threadidTokenC))
1194                 tokens[i] = threadidTokenC;
1195             else if (lexeme == QLatin1String(qthreadptrTokenC))
1196                 tokens[i] = qthreadptrTokenC;
1197             else if (lexeme.startsWith(QLatin1String(timeTokenC))) {
1198                 tokens[i] = timeTokenC;
1199                 int spaceIdx = lexeme.indexOf(QChar::fromLatin1(' '));
1200                 if (spaceIdx > 0)
1201                     timeArgs.append(lexeme.mid(spaceIdx + 1, lexeme.length() - spaceIdx - 2));
1202                 else
1203                     timeArgs.append(QString());
1204             } else if (lexeme.startsWith(QLatin1String(backtraceTokenC))) {
1205 #ifdef QLOGGING_HAVE_BACKTRACE
1206                 tokens[i] = backtraceTokenC;
1207                 QString backtraceSeparator = QStringLiteral("|");
1208                 int backtraceDepth = 5;
1209                 static const QRegularExpression depthRx(QStringLiteral(" depth=(?|\"([^\"]*)\"|([^ }]*))"));
1210                 static const QRegularExpression separatorRx(QStringLiteral(" separator=(?|\"([^\"]*)\"|([^ }]*))"));
1211                 QRegularExpressionMatch m = depthRx.match(lexeme);
1212                 if (m.hasMatch()) {
1213                     int depth = m.capturedRef(1).toInt();
1214                     if (depth <= 0)
1215                         error += QLatin1String("QT_MESSAGE_PATTERN: %{backtrace} depth must be a number greater than 0\n");
1216                     else
1217                         backtraceDepth = depth;
1218                 }
1219                 m = separatorRx.match(lexeme);
1220                 if (m.hasMatch())
1221                     backtraceSeparator = m.captured(1);
1222                 BacktraceParams backtraceParams;
1223                 backtraceParams.backtraceDepth = backtraceDepth;
1224                 backtraceParams.backtraceSeparator = backtraceSeparator;
1225                 backtraceArgs.append(backtraceParams);
1226 #else
1227                 error += QLatin1String("QT_MESSAGE_PATTERN: %{backtrace} is not supported by this Qt build\n");
1228                 tokens[i] = "";
1229 #endif
1230             }
1231 
1232 #define IF_TOKEN(LEVEL) \
1233             else if (lexeme == QLatin1String(LEVEL)) { \
1234                 if (inIf) \
1235                     nestedIfError = true; \
1236                 tokens[i] = LEVEL; \
1237                 inIf = true; \
1238             }
1239             IF_TOKEN(ifCategoryTokenC)
1240             IF_TOKEN(ifDebugTokenC)
1241             IF_TOKEN(ifInfoTokenC)
1242             IF_TOKEN(ifWarningTokenC)
1243             IF_TOKEN(ifCriticalTokenC)
1244             IF_TOKEN(ifFatalTokenC)
1245 #undef IF_TOKEN
1246             else if (lexeme == QLatin1String(endifTokenC)) {
1247                 tokens[i] = endifTokenC;
1248                 if (!inIf && !nestedIfError)
1249                     error += QLatin1String("QT_MESSAGE_PATTERN: %{endif} without an %{if-*}\n");
1250                 inIf = false;
1251             } else {
1252                 tokens[i] = emptyTokenC;
1253                 error += QStringLiteral("QT_MESSAGE_PATTERN: Unknown placeholder %1\n")
1254                         .arg(lexeme);
1255             }
1256         } else {
1257             char *literal = new char[lexeme.size() + 1];
1258             strncpy(literal, lexeme.toLatin1().constData(), lexeme.size());
1259             literal[lexeme.size()] = '\0';
1260             literalsVar.emplace_back(literal);
1261             tokens[i] = literal;
1262         }
1263     }
1264     if (nestedIfError)
1265         error += QLatin1String("QT_MESSAGE_PATTERN: %{if-*} cannot be nested\n");
1266     else if (inIf)
1267         error += QLatin1String("QT_MESSAGE_PATTERN: missing %{endif}\n");
1268 
1269     if (!error.isEmpty())
1270         qt_message_print(error);
1271 
1272     literals.reset(new std::unique_ptr<const char[]>[literalsVar.size() + 1]);
1273     std::move(literalsVar.begin(), literalsVar.end(), &literals[0]);
1274 }
1275 
1276 #if defined(QLOGGING_HAVE_BACKTRACE) && !defined(QT_BOOTSTRAPPED)
1277 // make sure the function has "Message" in the name so the function is removed
1278 
1279 #if ((defined(Q_CC_GNU) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)) || __has_attribute(optimize)) \
1280     && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG)
1281 // force skipping the frame pointer, to save the backtrace() function some work
1282 __attribute__((optimize("omit-frame-pointer")))
1283 #endif
backtraceFramesForLogMessage(int frameCount)1284 static QStringList backtraceFramesForLogMessage(int frameCount)
1285 {
1286     QStringList result;
1287     if (frameCount == 0)
1288         return result;
1289 
1290     // The results of backtrace_symbols looks like this:
1291     //    /lib/libc.so.6(__libc_start_main+0xf3) [0x4a937413]
1292     // The offset and function name are optional.
1293     // This regexp tries to extract the library name (without the path) and the function name.
1294     // This code is protected by QMessagePattern::mutex so it is thread safe on all compilers
1295     static const QRegularExpression rx(QStringLiteral("^(?:[^(]*/)?([^(/]+)\\(([^+]*)(?:[\\+[a-f0-9x]*)?\\) \\[[a-f0-9x]*\\]$"));
1296 
1297     QVarLengthArray<void*, 32> buffer(8 + frameCount);
1298     int n = backtrace(buffer.data(), buffer.size());
1299     if (n > 0) {
1300         int numberPrinted = 0;
1301         for (int i = 0; i < n && numberPrinted < frameCount; ++i) {
1302             QScopedPointer<char*, QScopedPointerPodDeleter> strings(backtrace_symbols(buffer.data() + i, 1));
1303             QString trace = QString::fromLatin1(strings.data()[0]);
1304             QRegularExpressionMatch m = rx.match(trace);
1305             if (m.hasMatch()) {
1306                 QString library = m.captured(1);
1307                 QString function = m.captured(2);
1308 
1309                 // skip the trace from QtCore that are because of the qDebug itself
1310                 if (!numberPrinted && library.contains(QLatin1String("Qt5Core"))
1311                         && (function.isEmpty() || function.contains(QLatin1String("Message"), Qt::CaseInsensitive)
1312                             || function.contains(QLatin1String("QDebug")))) {
1313                     continue;
1314                 }
1315 
1316                 if (function.startsWith(QLatin1String("_Z"))) {
1317                     QScopedPointer<char, QScopedPointerPodDeleter> demangled(
1318                                 abi::__cxa_demangle(function.toUtf8(), nullptr, nullptr, nullptr));
1319                     if (demangled)
1320                         function = QString::fromUtf8(qCleanupFuncinfo(demangled.data()));
1321                 }
1322 
1323                 if (function.isEmpty()) {
1324                     result.append(QLatin1Char('?') + library + QLatin1Char('?'));
1325                 } else {
1326                     result.append(function);
1327                 }
1328             } else {
1329                 if (numberPrinted == 0) {
1330                     // innermost, unknown frames are usually the logging framework itself
1331                     continue;
1332                 }
1333                 result.append(QStringLiteral("???"));
1334             }
1335             numberPrinted++;
1336         }
1337     }
1338     return result;
1339 }
1340 
formatBacktraceForLogMessage(const QMessagePattern::BacktraceParams backtraceParams,const char * function)1341 static QString formatBacktraceForLogMessage(const QMessagePattern::BacktraceParams backtraceParams,
1342                                             const char *function)
1343 {
1344     QString backtraceSeparator = backtraceParams.backtraceSeparator;
1345     int backtraceDepth = backtraceParams.backtraceDepth;
1346 
1347     QStringList frames = backtraceFramesForLogMessage(backtraceDepth);
1348     if (frames.isEmpty())
1349         return QString();
1350 
1351     // if the first frame is unknown, replace it with the context function
1352     if (function && frames.at(0).startsWith(QLatin1Char('?')))
1353         frames[0] = QString::fromUtf8(qCleanupFuncinfo(function));
1354 
1355     return frames.join(backtraceSeparator);
1356 }
1357 #endif // QLOGGING_HAVE_BACKTRACE && !QT_BOOTSTRAPPED
1358 
Q_GLOBAL_STATIC(QMessagePattern,qMessagePattern)1359 Q_GLOBAL_STATIC(QMessagePattern, qMessagePattern)
1360 
1361 /*!
1362     \relates <QtGlobal>
1363     \since 5.4
1364 
1365     Generates a formatted string out of the \a type, \a context, \a str arguments.
1366 
1367     qFormatLogMessage returns a QString that is formatted according to the current message pattern.
1368     It can be used by custom message handlers to format output similar to Qt's default message
1369     handler.
1370 
1371     The function is thread-safe.
1372 
1373     \sa qInstallMessageHandler(), qSetMessagePattern()
1374  */
1375 QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, const QString &str)
1376 {
1377     QString message;
1378 
1379     const auto locker = qt_scoped_lock(QMessagePattern::mutex);
1380 
1381     QMessagePattern *pattern = qMessagePattern();
1382     if (!pattern) {
1383         // after destruction of static QMessagePattern instance
1384         message.append(str);
1385         return message;
1386     }
1387 
1388     bool skip = false;
1389 
1390 #ifndef QT_BOOTSTRAPPED
1391     int timeArgsIdx = 0;
1392 #ifdef QLOGGING_HAVE_BACKTRACE
1393     int backtraceArgsIdx = 0;
1394 #endif
1395 #endif
1396 
1397     // we do not convert file, function, line literals to local encoding due to overhead
1398     for (int i = 0; pattern->tokens[i]; ++i) {
1399         const char *token = pattern->tokens[i];
1400         if (token == endifTokenC) {
1401             skip = false;
1402         } else if (skip) {
1403             // we skip adding messages, but we have to iterate over
1404             // timeArgsIdx and backtraceArgsIdx anyway
1405 #ifndef QT_BOOTSTRAPPED
1406             if (token == timeTokenC)
1407                 timeArgsIdx++;
1408 #ifdef QLOGGING_HAVE_BACKTRACE
1409             else if (token == backtraceTokenC)
1410                 backtraceArgsIdx++;
1411 #endif
1412 #endif
1413         } else if (token == messageTokenC) {
1414             message.append(str);
1415         } else if (token == categoryTokenC) {
1416             message.append(QLatin1String(context.category));
1417         } else if (token == typeTokenC) {
1418             switch (type) {
1419             case QtDebugMsg:   message.append(QLatin1String("debug")); break;
1420             case QtInfoMsg:    message.append(QLatin1String("info")); break;
1421             case QtWarningMsg: message.append(QLatin1String("warning")); break;
1422             case QtCriticalMsg:message.append(QLatin1String("critical")); break;
1423             case QtFatalMsg:   message.append(QLatin1String("fatal")); break;
1424             }
1425         } else if (token == fileTokenC) {
1426             if (context.file)
1427                 message.append(QLatin1String(context.file));
1428             else
1429                 message.append(QLatin1String("unknown"));
1430         } else if (token == lineTokenC) {
1431             message.append(QString::number(context.line));
1432         } else if (token == functionTokenC) {
1433             if (context.function)
1434                 message.append(QString::fromLatin1(qCleanupFuncinfo(context.function)));
1435             else
1436                 message.append(QLatin1String("unknown"));
1437 #ifndef QT_BOOTSTRAPPED
1438         } else if (token == pidTokenC) {
1439             message.append(QString::number(QCoreApplication::applicationPid()));
1440         } else if (token == appnameTokenC) {
1441             message.append(QCoreApplication::applicationName());
1442         } else if (token == threadidTokenC) {
1443             // print the TID as decimal
1444             message.append(QString::number(qt_gettid()));
1445         } else if (token == qthreadptrTokenC) {
1446             message.append(QLatin1String("0x"));
1447             message.append(QString::number(qlonglong(QThread::currentThread()->currentThread()), 16));
1448 #ifdef QLOGGING_HAVE_BACKTRACE
1449         } else if (token == backtraceTokenC) {
1450             QMessagePattern::BacktraceParams backtraceParams = pattern->backtraceArgs.at(backtraceArgsIdx);
1451             backtraceArgsIdx++;
1452             message.append(formatBacktraceForLogMessage(backtraceParams, context.function));
1453 #endif
1454         } else if (token == timeTokenC) {
1455             QString timeFormat = pattern->timeArgs.at(timeArgsIdx);
1456             timeArgsIdx++;
1457             if (timeFormat == QLatin1String("process")) {
1458                     quint64 ms = pattern->timer.elapsed();
1459                     message.append(QString::asprintf("%6d.%03d", uint(ms / 1000), uint(ms % 1000)));
1460             } else if (timeFormat ==  QLatin1String("boot")) {
1461                 // just print the milliseconds since the elapsed timer reference
1462                 // like the Linux kernel does
1463                 QElapsedTimer now;
1464                 now.start();
1465                 uint ms = now.msecsSinceReference();
1466                 message.append(QString::asprintf("%6d.%03d", uint(ms / 1000), uint(ms % 1000)));
1467 #if QT_CONFIG(datestring)
1468             } else if (timeFormat.isEmpty()) {
1469                     message.append(QDateTime::currentDateTime().toString(Qt::ISODate));
1470             } else {
1471                 message.append(QDateTime::currentDateTime().toString(timeFormat));
1472 #endif // QT_CONFIG(datestring)
1473             }
1474 #endif // !QT_BOOTSTRAPPED
1475         } else if (token == ifCategoryTokenC) {
1476             if (isDefaultCategory(context.category))
1477                 skip = true;
1478 #define HANDLE_IF_TOKEN(LEVEL)  \
1479         } else if (token == if##LEVEL##TokenC) { \
1480             skip = type != Qt##LEVEL##Msg;
1481         HANDLE_IF_TOKEN(Debug)
1482         HANDLE_IF_TOKEN(Info)
1483         HANDLE_IF_TOKEN(Warning)
1484         HANDLE_IF_TOKEN(Critical)
1485         HANDLE_IF_TOKEN(Fatal)
1486 #undef HANDLE_IF_TOKEN
1487         } else {
1488             message.append(QLatin1String(token));
1489         }
1490     }
1491     return message;
1492 }
1493 
1494 #if !QT_DEPRECATED_SINCE(5, 0)
1495 // make sure they're defined to be exported
1496 typedef void (*QtMsgHandler)(QtMsgType, const char *);
1497 Q_CORE_EXPORT QtMsgHandler qInstallMsgHandler(QtMsgHandler);
1498 #endif
1499 
1500 static void qDefaultMsgHandler(QtMsgType type, const char *buf);
1501 static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &buf);
1502 
1503 // pointer to QtMsgHandler debug handler (without context)
1504 static QBasicAtomicPointer<void (QtMsgType, const char*)> msgHandler = Q_BASIC_ATOMIC_INITIALIZER(nullptr);
1505 // pointer to QtMessageHandler debug handler (with context)
1506 static QBasicAtomicPointer<void (QtMsgType, const QMessageLogContext &, const QString &)> messageHandler = Q_BASIC_ATOMIC_INITIALIZER(nullptr);
1507 
1508 // ------------------------ Alternate logging sinks -------------------------
1509 
1510 #if defined(QT_BOOTSTRAPPED)
1511     // Boostrapped tools always print to stderr, so no need for alternate sinks
1512 #else
1513 
1514 #if QT_CONFIG(slog2)
1515 #ifndef QT_LOG_CODE
1516 #define QT_LOG_CODE 9000
1517 #endif
1518 
slog2_default_handler(QtMsgType type,const QMessageLogContext & context,const QString & message)1519 static bool slog2_default_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
1520 {
1521     if (shouldLogToStderr())
1522         return false; // Leave logging up to stderr handler
1523 
1524     QString formattedMessage = qFormatLogMessage(type, context, message);
1525     formattedMessage.append(QLatin1Char('\n'));
1526     if (slog2_set_default_buffer((slog2_buffer_t)-1) == 0) {
1527         slog2_buffer_set_config_t buffer_config;
1528         slog2_buffer_t buffer_handle;
1529 
1530         buffer_config.buffer_set_name = __progname;
1531         buffer_config.num_buffers = 1;
1532         buffer_config.verbosity_level = SLOG2_DEBUG1;
1533         buffer_config.buffer_config[0].buffer_name = "default";
1534         buffer_config.buffer_config[0].num_pages = 8;
1535 
1536         if (slog2_register(&buffer_config, &buffer_handle, 0) == -1) {
1537             fprintf(stderr, "Error registering slogger2 buffer!\n");
1538             fprintf(stderr, "%s", formattedMessage.toLocal8Bit().constData());
1539             fflush(stderr);
1540             return false;
1541         }
1542 
1543         // Set as the default buffer
1544         slog2_set_default_buffer(buffer_handle);
1545     }
1546     int severity;
1547     //Determines the severity level
1548     switch (type) {
1549     case QtDebugMsg:
1550         severity = SLOG2_DEBUG1;
1551         break;
1552     case QtInfoMsg:
1553         severity = SLOG2_INFO;
1554         break;
1555     case QtWarningMsg:
1556         severity = SLOG2_NOTICE;
1557         break;
1558     case QtCriticalMsg:
1559         severity = SLOG2_WARNING;
1560         break;
1561     case QtFatalMsg:
1562         severity = SLOG2_ERROR;
1563         break;
1564     }
1565     //writes to the slog2 buffer
1566     slog2c(NULL, QT_LOG_CODE, severity, formattedMessage.toLocal8Bit().constData());
1567 
1568     return true; // Prevent further output to stderr
1569 }
1570 #endif // slog2
1571 
1572 #if QT_CONFIG(journald)
systemd_default_message_handler(QtMsgType type,const QMessageLogContext & context,const QString & message)1573 static bool systemd_default_message_handler(QtMsgType type,
1574                                             const QMessageLogContext &context,
1575                                             const QString &message)
1576 {
1577     if (shouldLogToStderr())
1578         return false; // Leave logging up to stderr handler
1579 
1580     QString formattedMessage = qFormatLogMessage(type, context, message);
1581 
1582     int priority = LOG_INFO; // Informational
1583     switch (type) {
1584     case QtDebugMsg:
1585         priority = LOG_DEBUG; // Debug-level messages
1586         break;
1587     case QtInfoMsg:
1588         priority = LOG_INFO; // Informational conditions
1589         break;
1590     case QtWarningMsg:
1591         priority = LOG_WARNING; // Warning conditions
1592         break;
1593     case QtCriticalMsg:
1594         priority = LOG_CRIT; // Critical conditions
1595         break;
1596     case QtFatalMsg:
1597         priority = LOG_ALERT; // Action must be taken immediately
1598         break;
1599     }
1600 
1601     sd_journal_send("MESSAGE=%s",     formattedMessage.toUtf8().constData(),
1602                     "PRIORITY=%i",    priority,
1603                     "CODE_FUNC=%s",   context.function ? context.function : "unknown",
1604                     "CODE_LINE=%d",   context.line,
1605                     "CODE_FILE=%s",   context.file ? context.file : "unknown",
1606                     "QT_CATEGORY=%s", context.category ? context.category : "unknown",
1607                     NULL);
1608 
1609     return true; // Prevent further output to stderr
1610 }
1611 #endif
1612 
1613 #if QT_CONFIG(syslog)
syslog_default_message_handler(QtMsgType type,const QMessageLogContext & context,const QString & message)1614 static bool syslog_default_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
1615 {
1616     if (shouldLogToStderr())
1617         return false; // Leave logging up to stderr handler
1618 
1619     QString formattedMessage = qFormatLogMessage(type, context, message);
1620 
1621     int priority = LOG_INFO; // Informational
1622     switch (type) {
1623     case QtDebugMsg:
1624         priority = LOG_DEBUG; // Debug-level messages
1625         break;
1626     case QtInfoMsg:
1627         priority = LOG_INFO; // Informational conditions
1628         break;
1629     case QtWarningMsg:
1630         priority = LOG_WARNING; // Warning conditions
1631         break;
1632     case QtCriticalMsg:
1633         priority = LOG_CRIT; // Critical conditions
1634         break;
1635     case QtFatalMsg:
1636         priority = LOG_ALERT; // Action must be taken immediately
1637         break;
1638     }
1639 
1640     syslog(priority, "%s", formattedMessage.toUtf8().constData());
1641 
1642     return true; // Prevent further output to stderr
1643 }
1644 #endif
1645 
1646 #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
android_default_message_handler(QtMsgType type,const QMessageLogContext & context,const QString & message)1647 static bool android_default_message_handler(QtMsgType type,
1648                                   const QMessageLogContext &context,
1649                                   const QString &message)
1650 {
1651     if (shouldLogToStderr())
1652         return false; // Leave logging up to stderr handler
1653 
1654     QString formattedMessage = qFormatLogMessage(type, context, message);
1655 
1656     android_LogPriority priority = ANDROID_LOG_DEBUG;
1657     switch (type) {
1658     case QtDebugMsg: priority = ANDROID_LOG_DEBUG; break;
1659     case QtInfoMsg: priority = ANDROID_LOG_INFO; break;
1660     case QtWarningMsg: priority = ANDROID_LOG_WARN; break;
1661     case QtCriticalMsg: priority = ANDROID_LOG_ERROR; break;
1662     case QtFatalMsg: priority = ANDROID_LOG_FATAL; break;
1663     };
1664 
1665     __android_log_print(priority, qPrintable(QCoreApplication::applicationName()), "%s\n", qPrintable(formattedMessage));
1666 
1667     return true; // Prevent further output to stderr
1668 }
1669 #endif //Q_OS_ANDROID
1670 
1671 #ifdef Q_OS_WIN
win_outputDebugString_helper(QStringView message)1672 static void win_outputDebugString_helper(QStringView message)
1673 {
1674     const int maxOutputStringLength = 32766;
1675     static QBasicMutex m;
1676     auto locker = qt_unique_lock(m);
1677     // fast path: Avoid string copies if one output is enough
1678     if (message.length() <= maxOutputStringLength) {
1679         OutputDebugString(reinterpret_cast<const wchar_t *>(message.utf16()));
1680     } else {
1681         wchar_t *messagePart = new wchar_t[maxOutputStringLength + 1];
1682         for (int i = 0; i < message.length(); i += maxOutputStringLength ) {
1683             const int length = std::min(message.length() - i, maxOutputStringLength );
1684             const int len = message.mid(i, length).toWCharArray(messagePart);
1685             Q_ASSERT(len == length);
1686             messagePart[len] = 0;
1687             OutputDebugString(messagePart);
1688         }
1689         delete[] messagePart;
1690     }
1691 }
1692 
win_message_handler(QtMsgType type,const QMessageLogContext & context,const QString & message)1693 static bool win_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
1694 {
1695     if (shouldLogToStderr())
1696         return false; // Leave logging up to stderr handler
1697 
1698     const QString formattedMessage = qFormatLogMessage(type, context, message).append('\n');
1699     win_outputDebugString_helper(formattedMessage);
1700 
1701     return true; // Prevent further output to stderr
1702 }
1703 #endif
1704 
1705 #ifdef Q_OS_WASM
wasm_default_message_handler(QtMsgType type,const QMessageLogContext & context,const QString & message)1706 static bool wasm_default_message_handler(QtMsgType type,
1707                                   const QMessageLogContext &context,
1708                                   const QString &message)
1709 {
1710     if (shouldLogToStderr())
1711         return false; // Leave logging up to stderr handler
1712 
1713     QString formattedMessage = qFormatLogMessage(type, context, message);
1714     int emOutputFlags = (EM_LOG_CONSOLE | EM_LOG_DEMANGLE);
1715     QByteArray localMsg = message.toLocal8Bit();
1716     switch (type) {
1717     case QtDebugMsg:
1718         break;
1719     case QtInfoMsg:
1720         break;
1721     case QtWarningMsg:
1722         emOutputFlags |= EM_LOG_WARN;
1723         break;
1724     case QtCriticalMsg:
1725         emOutputFlags |= EM_LOG_ERROR;
1726         break;
1727     case QtFatalMsg:
1728         emOutputFlags |= EM_LOG_ERROR;
1729     }
1730     emscripten_log(emOutputFlags, "%s\n", qPrintable(formattedMessage));
1731 
1732     return true; // Prevent further output to stderr
1733 }
1734 #endif
1735 
1736 #endif // Bootstrap check
1737 
1738 // --------------------------------------------------------------------------
1739 
stderr_message_handler(QtMsgType type,const QMessageLogContext & context,const QString & message)1740 static void stderr_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
1741 {
1742     QString formattedMessage = qFormatLogMessage(type, context, message);
1743 
1744     // print nothing if message pattern didn't apply / was empty.
1745     // (still print empty lines, e.g. because message itself was empty)
1746     if (formattedMessage.isNull())
1747         return;
1748 
1749     fprintf(stderr, "%s\n", formattedMessage.toLocal8Bit().constData());
1750     fflush(stderr);
1751 }
1752 
1753 /*!
1754     \internal
1755 */
qDefaultMessageHandler(QtMsgType type,const QMessageLogContext & context,const QString & message)1756 static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &context,
1757                                    const QString &message)
1758 {
1759     bool handledStderr = false;
1760 
1761     // A message sink logs the message to a structured or unstructured destination,
1762     // optionally formatting the message if the latter, and returns true if the sink
1763     // handled stderr output as well, which will shortcut our default stderr output.
1764     // In the future, if we allow multiple/dynamic sinks, this will be iterating
1765     // a list of sinks.
1766 
1767 #if !defined(QT_BOOTSTRAPPED)
1768 # if defined(Q_OS_WIN)
1769     handledStderr |= win_message_handler(type, context, message);
1770 # elif QT_CONFIG(slog2)
1771     handledStderr |= slog2_default_handler(type, context, message);
1772 # elif QT_CONFIG(journald)
1773     handledStderr |= systemd_default_message_handler(type, context, message);
1774 # elif QT_CONFIG(syslog)
1775     handledStderr |= syslog_default_message_handler(type, context, message);
1776 # elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
1777     handledStderr |= android_default_message_handler(type, context, message);
1778 # elif defined(QT_USE_APPLE_UNIFIED_LOGGING)
1779     handledStderr |= AppleUnifiedLogger::messageHandler(type, context, message);
1780 # elif defined Q_OS_WASM
1781     handledStderr |= wasm_default_message_handler(type, context, message);
1782 # endif
1783 #endif
1784 
1785     if (!handledStderr)
1786         stderr_message_handler(type, context, message);
1787 }
1788 
1789 /*!
1790     \internal
1791 */
qDefaultMsgHandler(QtMsgType type,const char * buf)1792 static void qDefaultMsgHandler(QtMsgType type, const char *buf)
1793 {
1794     QMessageLogContext emptyContext;
1795     qDefaultMessageHandler(type, emptyContext, QString::fromLocal8Bit(buf));
1796 }
1797 
1798 #if defined(Q_COMPILER_THREAD_LOCAL)
1799 
1800 static thread_local bool msgHandlerGrabbed = false;
1801 
grabMessageHandler()1802 static bool grabMessageHandler()
1803 {
1804     if (msgHandlerGrabbed)
1805         return false;
1806 
1807     msgHandlerGrabbed = true;
1808     return true;
1809 }
1810 
ungrabMessageHandler()1811 static void ungrabMessageHandler()
1812 {
1813     msgHandlerGrabbed = false;
1814 }
1815 
1816 #else
grabMessageHandler()1817 static bool grabMessageHandler() { return true; }
ungrabMessageHandler()1818 static void ungrabMessageHandler() { }
1819 #endif // (Q_COMPILER_THREAD_LOCAL)
1820 
qt_message_print(QtMsgType msgType,const QMessageLogContext & context,const QString & message)1821 static void qt_message_print(QtMsgType msgType, const QMessageLogContext &context, const QString &message)
1822 {
1823 #ifndef QT_BOOTSTRAPPED
1824     Q_TRACE(qt_message_print, msgType, context.category, context.function, context.file, context.line, message);
1825 
1826     // qDebug, qWarning, ... macros do not check whether category is enabledgc
1827     if (msgType != QtFatalMsg && isDefaultCategory(context.category)) {
1828         if (QLoggingCategory *defaultCategory = QLoggingCategory::defaultCategory()) {
1829             if (!defaultCategory->isEnabled(msgType))
1830                 return;
1831         }
1832     }
1833 #endif
1834 
1835     // prevent recursion in case the message handler generates messages
1836     // itself, e.g. by using Qt API
1837     if (grabMessageHandler()) {
1838         const auto ungrab = qScopeGuard([]{ ungrabMessageHandler(); });
1839         auto oldStyle = msgHandler.loadAcquire();
1840         auto newStye = messageHandler.loadAcquire();
1841         // prefer new message handler over the old one
1842         if (newStye || !oldStyle) {
1843             (newStye ? newStye : qDefaultMessageHandler)(msgType, context, message);
1844         } else {
1845             (oldStyle ? oldStyle : qDefaultMsgHandler)(msgType, message.toLocal8Bit().constData());
1846         }
1847     } else {
1848         fprintf(stderr, "%s\n", message.toLocal8Bit().constData());
1849     }
1850 }
1851 
qt_message_print(const QString & message)1852 static void qt_message_print(const QString &message)
1853 {
1854 #if defined(Q_OS_WINRT)
1855     win_outputDebugString_helper(message);
1856     return;
1857 #elif defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
1858     if (!shouldLogToStderr()) {
1859         win_outputDebugString_helper(message);
1860         return;
1861     }
1862 #endif
1863     fprintf(stderr, "%s", message.toLocal8Bit().constData());
1864     fflush(stderr);
1865 }
1866 
qt_message_fatal(QtMsgType,const QMessageLogContext & context,const QString & message)1867 static void qt_message_fatal(QtMsgType, const QMessageLogContext &context, const QString &message)
1868 {
1869 #if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
1870     wchar_t contextFileL[256];
1871     // we probably should let the compiler do this for us, by declaring QMessageLogContext::file to
1872     // be const wchar_t * in the first place, but the #ifdefery above is very complex  and we
1873     // wouldn't be able to change it later on...
1874     convert_to_wchar_t_elided(contextFileL, sizeof contextFileL / sizeof *contextFileL,
1875                               context.file);
1876     // get the current report mode
1877     int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW);
1878     _CrtSetReportMode(_CRT_ERROR, reportMode);
1879 
1880     int ret = _CrtDbgReportW(_CRT_ERROR, contextFileL, context.line, _CRT_WIDE(QT_VERSION_STR),
1881                              reinterpret_cast<const wchar_t *>(message.utf16()));
1882     if ((ret == 0) && (reportMode & _CRTDBG_MODE_WNDW))
1883         return; // ignore
1884     else if (ret == 1)
1885         _CrtDbgBreak();
1886 #else
1887     Q_UNUSED(context);
1888     Q_UNUSED(message);
1889 #endif
1890 
1891 #ifdef Q_OS_WIN
1892     // std::abort() in the MSVC runtime will call _exit(3) if the abort
1893     // behavior is _WRITE_ABORT_MSG - see also _set_abort_behavior(). This is
1894     // the default for a debug-mode build of the runtime. Worse, MinGW's
1895     // std::abort() implementation (in msvcrt.dll) is basically a call to
1896     // _exit(3) too. Unfortunately, _exit() and _Exit() *do* run the static
1897     // destructors of objects in DLLs, a violation of the C++ standard (see
1898     // [support.start.term]). So we bypass std::abort() and directly
1899     // terminate the application.
1900 
1901 #  if defined(Q_CC_MSVC) && !defined(Q_CC_INTEL)
1902     if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))
1903         __fastfail(FAST_FAIL_FATAL_APP_EXIT);
1904 #  else
1905     RaiseFailFastException(nullptr, nullptr, 0);
1906 #  endif
1907 
1908     // Fallback
1909     TerminateProcess(GetCurrentProcess(), STATUS_FATAL_APP_EXIT);
1910 
1911     // Tell the compiler the application has stopped.
1912     Q_UNREACHABLE_IMPL();
1913 #else // !Q_OS_WIN
1914     std::abort();
1915 #endif
1916 }
1917 
1918 
1919 /*!
1920     \internal
1921 */
qt_message_output(QtMsgType msgType,const QMessageLogContext & context,const QString & message)1922 void qt_message_output(QtMsgType msgType, const QMessageLogContext &context, const QString &message)
1923 {
1924     qt_message_print(msgType, context, message);
1925     if (isFatal(msgType))
1926         qt_message_fatal(msgType, context, message);
1927 }
1928 
qErrnoWarning(const char * msg,...)1929 void qErrnoWarning(const char *msg, ...)
1930 {
1931     // qt_error_string() will allocate anyway, so we don't have
1932     // to be careful here (like we do in plain qWarning())
1933     QString error_string = qt_error_string(-1);  // before vasprintf changes errno/GetLastError()
1934 
1935     va_list ap;
1936     va_start(ap, msg);
1937     QString buf = QString::vasprintf(msg, ap);
1938     va_end(ap);
1939 
1940     buf += QLatin1String(" (") + error_string + QLatin1Char(')');
1941     QMessageLogContext context;
1942     qt_message_output(QtCriticalMsg, context, buf);
1943 }
1944 
qErrnoWarning(int code,const char * msg,...)1945 void qErrnoWarning(int code, const char *msg, ...)
1946 {
1947     // qt_error_string() will allocate anyway, so we don't have
1948     // to be careful here (like we do in plain qWarning())
1949     va_list ap;
1950     va_start(ap, msg);
1951     QString buf = QString::vasprintf(msg, ap);
1952     va_end(ap);
1953 
1954     buf += QLatin1String(" (") + qt_error_string(code) + QLatin1Char(')');
1955     QMessageLogContext context;
1956     qt_message_output(QtCriticalMsg, context, buf);
1957 }
1958 
1959 /*!
1960     \typedef QtMsgHandler
1961     \relates <QtGlobal>
1962     \deprecated
1963 
1964     This is a typedef for a pointer to a function with the following
1965     signature:
1966 
1967     \snippet code/src_corelib_global_qglobal.cpp 7
1968 
1969     This typedef is deprecated, you should use QtMessageHandler instead.
1970     \sa QtMsgType, QtMessageHandler, qInstallMsgHandler(), qInstallMessageHandler()
1971 */
1972 
1973 /*!
1974     \typedef QtMessageHandler
1975     \relates <QtGlobal>
1976     \since 5.0
1977 
1978     This is a typedef for a pointer to a function with the following
1979     signature:
1980 
1981     \snippet code/src_corelib_global_qglobal.cpp 49
1982 
1983     \sa QtMsgType, qInstallMessageHandler()
1984 */
1985 
1986 /*!
1987     \fn QtMessageHandler qInstallMessageHandler(QtMessageHandler handler)
1988     \relates <QtGlobal>
1989     \since 5.0
1990 
1991     Installs a Qt message \a handler which has been defined
1992     previously. Returns a pointer to the previous message handler.
1993 
1994     The message handler is a function that prints out debug messages,
1995     warnings, critical and fatal error messages. The Qt library (debug
1996     mode) contains hundreds of warning messages that are printed
1997     when internal errors (usually invalid function arguments)
1998     occur. Qt built in release mode also contains such warnings unless
1999     QT_NO_WARNING_OUTPUT and/or QT_NO_DEBUG_OUTPUT have been set during
2000     compilation. If you implement your own message handler, you get total
2001     control of these messages.
2002 
2003     The default message handler prints the message to the standard
2004     output under X11 or to the debugger under Windows. If it is a
2005     fatal message, the application aborts immediately.
2006 
2007     Only one message handler can be defined, since this is usually
2008     done on an application-wide basis to control debug output.
2009 
2010     To restore the message handler, call \c qInstallMessageHandler(0).
2011 
2012     Example:
2013 
2014     \snippet code/src_corelib_global_qglobal.cpp 23
2015 
2016     \sa QtMessageHandler, QtMsgType, qDebug(), qInfo(), qWarning(), qCritical(), qFatal(),
2017     {Debugging Techniques}
2018 */
2019 
2020 /*!
2021     \fn QtMsgHandler qInstallMsgHandler(QtMsgHandler handler)
2022     \relates <QtGlobal>
2023     \deprecated
2024 
2025     Installs a Qt message \a handler which has been defined
2026     previously. This method is deprecated, use qInstallMessageHandler
2027     instead.
2028     \sa QtMsgHandler, qInstallMessageHandler()
2029 */
2030 /*!
2031     \fn void qSetMessagePattern(const QString &pattern)
2032     \relates <QtGlobal>
2033     \since 5.0
2034 
2035     \brief Changes the output of the default message handler.
2036 
2037     Allows to tweak the output of qDebug(), qInfo(), qWarning(), qCritical(),
2038     and qFatal(). The category logging output of qCDebug(), qCInfo(),
2039     qCWarning(), and qCCritical() is formatted, too.
2040 
2041     Following placeholders are supported:
2042 
2043     \table
2044     \header \li Placeholder \li Description
2045     \row \li \c %{appname} \li QCoreApplication::applicationName()
2046     \row \li \c %{category} \li Logging category
2047     \row \li \c %{file} \li Path to source file
2048     \row \li \c %{function} \li Function
2049     \row \li \c %{line} \li Line in source file
2050     \row \li \c %{message} \li The actual message
2051     \row \li \c %{pid} \li QCoreApplication::applicationPid()
2052     \row \li \c %{threadid} \li The system-wide ID of current thread (if it can be obtained)
2053     \row \li \c %{qthreadptr} \li A pointer to the current QThread (result of QThread::currentThread())
2054     \row \li \c %{type} \li "debug", "warning", "critical" or "fatal"
2055     \row \li \c %{time process} \li time of the message, in seconds since the process started (the token "process" is literal)
2056     \row \li \c %{time boot} \li the time of the message, in seconds since the system boot if that
2057         can be determined (the token "boot" is literal). If the time since boot could not be obtained,
2058         the output is indeterminate (see QElapsedTimer::msecsSinceReference()).
2059     \row \li \c %{time [format]} \li system time when the message occurred, formatted by
2060         passing the \c format to \l QDateTime::toString(). If the format is
2061         not specified, the format of Qt::ISODate is used.
2062     \row \li \c{%{backtrace [depth=N] [separator="..."]}} \li A backtrace with the number of frames
2063         specified by the optional \c depth parameter (defaults to 5), and separated by the optional
2064         \c separator parameter (defaults to "|").
2065         This expansion is available only on some platforms (currently only platfoms using glibc).
2066         Names are only known for exported functions. If you want to see the name of every function
2067         in your application, use \c{QMAKE_LFLAGS += -rdynamic}.
2068         When reading backtraces, take into account that frames might be missing due to inlining or
2069         tail call optimization.
2070     \endtable
2071 
2072     You can also use conditionals on the type of the message using \c %{if-debug}, \c %{if-info}
2073     \c %{if-warning}, \c %{if-critical} or \c %{if-fatal} followed by an \c %{endif}.
2074     What is inside the \c %{if-*} and \c %{endif} will only be printed if the type matches.
2075 
2076     Finally, text inside \c %{if-category} ... \c %{endif} is only printed if the category
2077     is not the default one.
2078 
2079     Example:
2080     \snippet code/src_corelib_global_qlogging.cpp 0
2081 
2082     The default \a pattern is "%{if-category}%{category}: %{endif}%{message}".
2083 
2084     The \a pattern can also be changed at runtime by setting the QT_MESSAGE_PATTERN
2085     environment variable; if both \l qSetMessagePattern() is called and QT_MESSAGE_PATTERN is
2086     set, the environment variable takes precedence.
2087 
2088     \note The message pattern only applies to unstructured logging, such as the default
2089     \c stderr output. Structured logging such as systemd will record the message as is,
2090     along with as much structured information as can be captured.
2091 
2092     Custom message handlers can use qFormatLogMessage() to take \a pattern into account.
2093 
2094     \sa qInstallMessageHandler(), {Debugging Techniques}, {QLoggingCategory}
2095  */
2096 
qInstallMessageHandler(QtMessageHandler h)2097 QtMessageHandler qInstallMessageHandler(QtMessageHandler h)
2098 {
2099     const auto old = messageHandler.fetchAndStoreOrdered(h);
2100     if (old)
2101         return old;
2102     else
2103         return qDefaultMessageHandler;
2104 }
2105 
qInstallMsgHandler(QtMsgHandler h)2106 QtMsgHandler qInstallMsgHandler(QtMsgHandler h)
2107 {
2108     const auto old = msgHandler.fetchAndStoreOrdered(h);
2109     if (old)
2110         return old;
2111     else
2112         return qDefaultMsgHandler;
2113 }
2114 
qSetMessagePattern(const QString & pattern)2115 void qSetMessagePattern(const QString &pattern)
2116 {
2117     const auto locker = qt_scoped_lock(QMessagePattern::mutex);
2118 
2119     if (!qMessagePattern()->fromEnvironment)
2120         qMessagePattern()->setPattern(pattern);
2121 }
2122 
2123 
2124 /*!
2125     Copies context information from \a logContext into this QMessageLogContext.
2126     Returns a reference to this object.
2127 
2128     Note that the version is \b not copied, only the context information.
2129 
2130     \internal
2131 */
copyContextFrom(const QMessageLogContext & logContext)2132 QMessageLogContext &QMessageLogContext::copyContextFrom(const QMessageLogContext &logContext) noexcept
2133 {
2134     this->category = logContext.category;
2135     this->file = logContext.file;
2136     this->line = logContext.line;
2137     this->function = logContext.function;
2138     return *this;
2139 }
2140 
2141 /*!
2142     \fn QMessageLogger::QMessageLogger()
2143 
2144     Constructs a default QMessageLogger. See the other constructors to specify
2145     context information.
2146 */
2147 
2148 /*!
2149     \fn QMessageLogger::QMessageLogger(const char *file, int line, const char *function)
2150 
2151     Constructs a QMessageLogger to record log messages for \a file at \a line
2152     in \a function. The is equivalent to QMessageLogger(file, line, function, "default")
2153 */
2154 /*!
2155     \fn QMessageLogger::QMessageLogger(const char *file, int line, const char *function, const char *category)
2156 
2157     Constructs a QMessageLogger to record \a category messages for \a file at \a line
2158     in \a function.
2159 */
2160 
2161 /*!
2162     \fn void QMessageLogger::noDebug(const char *, ...) const
2163     \internal
2164 
2165     Ignores logging output
2166 
2167     \sa QNoDebug, qDebug()
2168 */
2169 
2170 /*!
2171     \fn QMessageLogContext::QMessageLogContext()
2172     \internal
2173 
2174     Constructs a QMessageLogContext
2175 */
2176 
2177 /*!
2178     \fn QMessageLogContext::QMessageLogContext(const char *fileName, int lineNumber, const char *functionName, const char *categoryName)
2179     \internal
2180 
2181     Constructs a QMessageLogContext with for file \a fileName at line
2182     \a lineNumber, in function \a functionName, and category \a categoryName.
2183 */
2184 
2185 QT_END_NAMESPACE
2186