Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Segfault with custom new/delete and Qt in C++

So I wanted to play around with custom new/delete a bit and followed this answer. I have a MWE that works nicely, but once I include a Qt header (even without using it), all I get is a segmentation fault. The segfault occurs before entering main() and I don't know whats going on. Here is the code:

/* main.cpp */
#include <iostream>
//#include <QString> // uncommenting this line causes the segfault

int main() {
    int* ref = new int(42);
    std::cout << ref << ", " << *ref << std::endl;
    delete ref;
}
/* custom_new.cpp */
#include <iostream>

void* operator new(size_t n) {
    void* result = malloc(n);
    std::cout << "Allocating " << n << " bytes at position " << result << std::endl;
    return result;
}

void operator delete(void* p) {
    std::cout << "Deleting memory at position " << p << std::endl;
    free(p);
}
# CMakeLists.txt
find_package(Qt5Core CONFIG REQUIRED)
add_library(custom_new custom_new.cpp)
add_executable(mwe main.cpp)
target_link_libraries(mwe Qt5::Core custom_new)

like image 888
staxyz Avatar asked Jan 21 '26 09:01

staxyz


1 Answers

It's a bad idea to access cout from inside a global operator new, since cout may not be initialized yet.

libQt5Core has many static initializers that run before main(), and some of them allocate memory using operator new. Indeed it seems QMutex is initialized before cout, and so it crashes on cout <<.

$ gdb ./a.out
(gdb) r
Program received signal SIGSEGV, Segmentation fault.
0x00007fffff22d426 in std::ostream::sentry::sentry(std::ostream&) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
(gdb) bt
#0  0x00007fffff22d426 in std::ostream::sentry::sentry(std::ostream&) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1  0x00007fffff22da38 in std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#2  0x00007fffff22de47 in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00000000080013cd in operator new (n=32) at a.cpp:17
#4  0x00007fffff3658d2 in QMutex::QMutex(QMutex::RecursionMode) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#5  0x00007fffff47699f in qRegisterResourceData(int, unsigned char const*, unsigned char const*, unsigned char const*) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#6  0x00007fffff34baa3 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#7  0x00007fffff7cf37a in call_init (l=<optimized out>, argc=argc@entry=1, argv=argv@entry=0x7ffffffee678, env=env@entry=0x7ffffffee688) at dl-init.c:72
#8  0x00007fffff7cf476 in call_init (env=0x7ffffffee688, argv=0x7ffffffee678, argc=1, l=<optimized out>) at dl-init.c:30
#9  _dl_init (main_map=0x7fffff7e9190, argc=1, argv=0x7ffffffee678, env=0x7ffffffee688) at dl-init.c:119
#10 0x00007fffff7c10ca in _dl_start_user () from /lib64/ld-linux-x86-64.so.2

If you really want to use cout inside operator new, use a global flag and set it to true inside main() so as to skip output for calls before main().

like image 103
rustyx Avatar answered Jan 22 '26 21:01

rustyx