Segfault on QTextStream in singleton destructor (static object, __tcf_0)
-
Hello,
I'm having a hard time figuring out what's causing this segfault. According to my research, it's related to some static variable in my code (see __tcf_0 in the stack trace below). The fact is, I have only one static variable in my code, which is the instance of a singleton class (see below).
This code seems correct to me, yet when the program terminates, a segfault is thrown in ~Logger() (line qDebug() << "Segfault";). The same thing happens when I try to delete a QTextStream* for example. However, printing out to the console using the standard cout works perfectly, as well as doing anything else using the standard library. It seems it only affects some Qt classes.
EDIT: it seems that the problem comes from the QTextStream class. Indeed, qDebug() uses it. Other classes which don't use it don't cause a segfault.
Here are the files and the stack trace:
main.cpp
@#include <QCoreApplication>
#include "Logger.h"int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);Logger::getInstance(); // Create Logger instance return a.exec();
}@
Singleton.h
@#ifndef SINGLETON_H
#define SINGLETON_Htemplate <class T>
class Singleton
{
protected:
Singleton() = default;
~Singleton() = default;public:
static T &getInstance()
{
static T instance; // <----- static variable here
return instance;
}
};#endif // SINGLETON_H@
Logger.h
@#ifndef LOGGER_H
#define LOGGER_H#include "Singleton.h"
class Logger : public Singleton<Logger>
{
friend class Singleton<Logger>;private:
Logger();
~Logger();
};#endif // LOGGER_H@
Logger.cpp
@#include "Logger.h"#include <QDebug>
#include <iostream>Logger::Logger() : Singleton<Logger>()
{
}Logger::~Logger()
{
std::cout << "It works" << std::endl;
qDebug() << "Segfault"; // <----- segfault here
}@Stack trace
@0 msvcrt!_msize C:\Windows\syswow64\msvcrt.dll 0x75cff4fc
1 ?? 0x20d0ea8
2 msvcrt!.dllonexit C:\Windows\syswow64\msvcrt.dll 0x75cff52c
3 (anonymous namespace)::Q_QGS_globalInstance::Holder::~Holder 47 0x6b971717
4 ?? 0xd8fc7add
5 mingw_onexit C:\Qt\Qt5.3.0\5.3\mingw482_32\bin\Qt5Cored.dll 0x6b9ae548
6 atexit C:\Qt\Qt5.3.0\5.3\mingw482_32\bin\Qt5Cored.dll 0x6b9ae5af
7 (anonymous namespace)::Q_QGS_globalInstance::innerFunction 47 0x6b971779
8 QGlobalStatic<QCoreGlobalData, (* (anonymous namespace)::Q_QGS_globalInstance::innerFunction), (* & (anonymous namespace)::Q_QGS_globalInstance::guard)>::operator()(void) 128 0x6b971917
9 QCoreGlobalData::instance 63 0x6b9718f2
10 QTextCodec::codecForLocale 680 0x6b97c475
11 QTextStreamPrivate::reset 399 0x6b8ba6be
12 QTextStreamPrivate::QTextStreamPrivate 330 0x6b8ba3ce
13 QTextStream::QTextStream 954 0x6b8bb69b
14 QDebug::Stream::Stream 66 0x6ba17d27
15 QDebug::QDebug 78 0x6ba17dfa
16 QMessageLogger::debug 359 0x6b78cd0e
17 Logger::~Logger Logger.cpp 13 0x401700
18 __tcf_0 Singleton.h 15 0x40168c
19 msvcrt!isspace C:\Windows\syswow64\msvcrt.dll 0x75cfc3e9
20 msvcrt!_cexit C:\Windows\syswow64\msvcrt.dll 0x75d037df
21 ?? @Thank you.
-
Hi, welcome to devnet,
QTextStream probably uses something that is destroyed when QApplication goes out of scope (at the end of main and before any static data is destroyed).
If you really need a singleton (do you?) make sure it's destroyed before the main finishes.
Some other comments:
- Always make the destructor of base classes virtual. You're leaking memory.
- class Logger : public Singleton<Logger> - this looks like a potential recursion problem. Do you really have to do it that way? Why is Logger inheriting a singleton at all?
- Why is the singleton destructor protected and what is that friend declaration there for?
-
Yes, you're right. QTextStream calls QTextCodec::codecForLocale() which returns NULL because it seems it needs an instance of QApplication, which has been destroyed by that point.
I don't know how I can delete the singleton and the static instance before main() returns: even if I manually call the singleton's destructor, the static instance won't get destroyed until main() has returned.
- I don't use polymorphism. There is no memory leak as long as you delete the object through the Derived* pointer and not the Base* pointer.
- There is no recursion problem in this particular case. Logger inherits Singleton because I want it to be a singleton: I want only one instance of Logger and it's easier to get it from anywhere in the program using a singleton. But it seems this approach has downsides too...
- ~Singleton() is protected so nobody can destroy the singleton, but the derived class (Logger here) can still call it when it gets destroyed. The friend declaration is there to enable the Singleton class to access to the constructor and destructor of the derived class, which are private to prevent anybody from creating an instance of the derived class.
To solve the problem, I may make a copy of the "locale codec" while the instance of QCoreApplication still exists and then set it back with QTextStream::setCodec() in ~Logger().
Or, I may avoid using QTextStream or even avoid using Qt in this case and use the standard library.