3

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)

staxyz
  • 167
  • 5
  • before entering the main the C++ runtime initialises static and global variables. Instead of running and waiting on a breakpoint you can try start in paused mode and step from there. – Teivaz Jun 07 '20 at 20:58
  • I do not see any global or subroutine static objects, whose constructors might tun before main(). C++ usually does not require you to write new and delete or call malloc or free, as new and delete are already there for objects, and your job is writing constructors and destructors. Maybe QT really dislikes your new and delete overload. I'm not a QT guru! CLion said CONFIG REQUIRED Not a CMake guru, either. – David G. Pickett Jun 07 '20 at 21:07
  • You can set breakpoints in both your new and delete functions. Possibly they're getting called before the global `cout` object has been constructed. – 1201ProgramAlarm Jun 07 '20 at 21:28

1 Answers1

1

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().

rustyx
  • 80,671
  • 25
  • 200
  • 267