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)
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().
Related
I have had to switch from C++11 to C++14 in my project to use the Catch testing framework, written for C++14 (it doesn't compile with anything less). Everything compiles fine. However, while running the program, the following function causes a series of errors which seem linked to a mismatch between C++11 and C++14 shared standard library files:
//it is called as such:
string p = "...";
handle_file(p);
//...
int handle_file (string p) {
if (is_valid(p)) {
return 0;
}
else return -1;
}
The error trace in gdb reads:
Program received signal SIGABRT, Aborted.
0x00007ffff7299ef5 in raise () from /usr/lib/libc.so.6
(gdb) bt
#0 0x00007ffff7299ef5 in raise () from /usr/lib/libc.so.6
#1 0x00007ffff7283862 in abort () from /usr/lib/libc.so.6
#2 0x00007ffff72dbf38 in __libc_message () from /usr/lib/libc.so.6
#3 0x00007ffff72e3bea in malloc_printerr () from /usr/lib/libc.so.6
#4 0x00007ffff72e5113 in _int_free () from /usr/lib/libc.so.6
#5 0x00007ffff72e8ca8 in free () from /usr/lib/libc.so.6
#6 0x00007ffff76b76ea in operator delete (ptr=<optimized out>) at /build/gcc/src/gcc/libstdc++-v3/libsupc++/del_op.cc:49
#7 0x00007ffff76b76fa in operator delete (ptr=<optimized out>) at /build/gcc/src/gcc/libstdc++-v3/libsupc++/del_ops.cc:33
#8 0x000055555556c893 in __gnu_cxx::new_allocator<char>::deallocate (__t=<optimized out>, __p=<optimized out>, this=0x7fffffffd910)
at /usr/include/c++/10.2.0/ext/new_allocator.h:133
#9 std::allocator_traits<std::allocator<char> >::deallocate (__n=<optimized out>, __p=<optimized out>, __a=...)
at /usr/include/c++/10.2.0/bits/alloc_traits.h:492
#10 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_destroy (__size=<optimized out>, this=0x7fffffffd910)
at /usr/include/c++/10.2.0/bits/basic_string.h:237
#11 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_dispose (this=0x7fffffffd910)
at /usr/include/c++/10.2.0/bits/basic_string.h:232
#12 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string (this=0x7fffffffd910, __in_chrg=<optimized out>)
at /usr/include/c++/10.2.0/bits/basic_string.h:658
#13 Manager::handle_file (p ="./data/20pix", this=0x5555556c6d20)
at src/manager.hpp:149
Does anyone know how to solve this?
The error is inside malloc, after it has printed some error message (usually double-free or something similar) indicating heap corruption.
While it is possible that you have some kind of library mismatch, it is much more likely that you have a plain heap corruption bug in your own code (overflowing heap buffer, double delete, delete of non-allocated, etc. etc.), and that bug is simply getting exposed now, while it remained hidden before.
Your first step should be to run the program under Valgrind or with Address Sanitizer, and fix any errors these tools report.
I'm experimenting with coroutines in C++ using cppcoro. But Address Sanitizer seems always unhappy that I'm leaking memory. Why? I've never allocated anything using raw new/delete and have never cause a circular dependency with shared_ptr.
#include <cppcoro/task.hpp>
#include <cppcoro/sync_wait.hpp>
#include <iostream>
class A {
public:
A() { std::cerr << "A ctor\n"; }
~A() { std::cerr << "A dtor\n"; }
};
int main()
{
auto getACoro = []() -> cppcoro::task<std::shared_ptr<A>> {
co_return std::make_shared<A>();
};
auto foo = [getACoro]() -> cppcoro::task<> {
co_await getACoro();
co_return;
};
auto coro = [&foo]() -> cppcoro::task<> {
co_await foo();
};
cppcoro::sync_wait(coro());
}
Compile with: g++ -std=c++20 -focorutines main.cpp -o main -lcppcoro -g -O -fsanitize=address
Then address sanitizer complains with:
=================================================================
==274677==ERROR: LeakSanitizer: detected memory leaks
Indirect leak of 88 byte(s) in 1 object(s) allocated from:
#0 0x7ff558d7af41 in operator new(unsigned long) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cpp:99
#1 0x560128e69267 in operator() /home/marty/Documents/experiments/cpp/main.cpp:47
#2 0x560128e69267 in main::{lambda()#3}::operator()() const [clone .actor] /home/marty/Documents/experiments/cpp/main.cpp:50
Indirect leak of 80 byte(s) in 1 object(s) allocated from:
#0 0x7ff558d7af41 in operator new(unsigned long) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cpp:99
#1 0x560128e6878e in operator() /home/marty/Documents/experiments/cpp/main.cpp:43
#2 0x560128e6878e in main::{lambda()#2}::operator()() const [clone .actor] /home/marty/Documents/experiments/cpp/main.cpp:45
#3 0x560128f7b997 (/home/marty/Documents/experiments/cpp/main+0x145997)
Indirect leak of 24 byte(s) in 1 object(s) allocated from:
#0 0x7ff558d7af41 in operator new(unsigned long) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cpp:99
#1 0x560128e71168 in __gnu_cxx::new_allocator<std::_Sp_counted_ptr_inplace<A, std::allocator<A>, (__gnu_cxx::_Lock_policy)2> >::allocate(unsigned long, void const*) /usr/include/c++/10.2.0/ext/new_allocator.h:115
#2 0x560128e71168 in std::allocator<std::_Sp_counted_ptr_inplace<A, std::allocator<A>, (__gnu_cxx::_Lock_policy)2> >::allocate(unsigned long) /usr/include/c++/10.2.0/bits/allocator.h:173
#3 0x560128e71168 in std::allocator_traits<std::allocator<std::_Sp_counted_ptr_inplace<A, std::allocator<A>, (__gnu_cxx::_Lock_policy)2> > >::allocate(std::allocator<std::_Sp_counted_ptr_inplace<A, std::allocator<A>, (__gnu_cxx::_Lock_policy)2> >&, unsigned long) /usr/include/c++/10.2.0/bits/alloc_traits.h:460
#4 0x560128e71168 in std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<A, std::allocator<A>, (__gnu_cxx::_Lock_policy)2> > > std::__allocate_guarded<std::allocator<std::_Sp_counted_ptr_inplace<A, std::allocator<A>, (__gnu_cxx::_Lock_policy)2> > >(std::allocator<std::_Sp_counted_ptr_inplace<A, std::allocator<A>, (__gnu_cxx::_Lock_policy)2> >&) /usr/include/c++/10.2.0/bits/allocated_ptr.h:97
#5 0xbe0b47d5ffffffff (<unknown module>)
SUMMARY: AddressSanitizer: 192 byte(s) leaked in 3 allocation(s).
As far I can tell. The shared_ptr should have destructed right after co_await getACoro();. Why is it considered leaked? And why are the coroutine frames leaking?
Compiler: GCC 10.2
OS: Linux
gRPC v1.30.0
I created a grpc service and tried to run it. The execution goes smooth till the last return statement at server side.
Status theService(ServerContext *context, const Request* req, Response* res)
{
Status status = actualLogic(req,res);
//execution goes fine till here
return status;
}
Status actualLogic(req,res)
{
Response_NestedMsg msg;
msg.set_something(...);
res->mutable_nestedmsg()->CopyFrom(msg);
return Status::OK
}
//server startup code
ServerBuilder builder;
builder.AddListeningPort((address),grpc::InsecureServerCredentials());
builder.RegisterService(&serviceClassObj);
std::unique_ptr<Server> server(builder.BuildAndStart());
server->Wait();
Running this code, I get following runtime error
==14394==ERROR: AddressSanitizer: attempting free on address which was not malloc()-ed: 0x61b00000fcc8 in thread T5 (grpcpp_sync_ser)
#0 0x7fe9d35602c0 in operator delete(void*) (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xe12c0)
#1 0x55cb87299afd in __gnu_cxx::new_allocator<std::_List_node<grpc_impl::Server const*> >::deallocate(std::_List_node<grpc_impl::Server const*>*, unsigned long) (/home/john/Desktop/my_executable+0xd0afd)
#2 0x55cb87297ba1 in std::allocator_traits<std::allocator<std::_List_node<grpc_impl::Server const*> > >::deallocate(std::allocator<std::_List_node<grpc_impl::Server const*> >&, std::_List_node<grpc_impl::Server const*>*, unsigned long) (/home/john/Desktop/my_executable+0xceba1)
#3 0x55cb8729448d in std::__cxx11::_List_base<grpc_impl::Server const*, std::allocator<grpc_impl::Server const*> >::_M_put_node(std::_List_node<grpc_impl::Server const*>*) (/home/john/Desktop/my_executable+0xcb48d)
#4 0x55cb8728bb5a in std::__cxx11::_List_base<grpc_impl::Server const*, std::allocator<grpc_impl::Server const*> >::_M_clear() (/home/john/Desktop/my_executable+0xc2b5a)
#5 0x55cb87287307 in std::__cxx11::_List_base<grpc_impl::Server const*, std::allocator<grpc_impl::Server const*> >::~_List_base() (/home/john/Desktop/my_executable+0xbe307)
#6 0x55cb87278d29 in std::__cxx11::list<grpc_impl::Server const*, std::allocator<grpc_impl::Server const*> >::~list() (/home/john/Desktop/my_executable+0xafd29)
#7 0x55cb87278e2c in grpc_impl::CompletionQueue::~CompletionQueue() (/home/john/Desktop/my_executable+0xafe2c)
#8 0x7fe9d1826998 in grpc_impl::Server::SyncRequest::CallData::ContinueRunAfterInterception() (/usr/local/lib/libgrpc++.so.1+0x6f998)
#9 0x7fe9d18278ee in grpc_impl::Server::SyncRequestThreadManager::DoWork(void*, bool, bool) (/usr/local/lib/libgrpc++.so.1+0x708ee)
#10 0x7fe9d182c4ca in grpc::ThreadManager::MainWorkLoop() (/usr/local/lib/libgrpc++.so.1+0x754ca)
#11 0x7fe9d182c68b in grpc::ThreadManager::WorkerThread::Run() (/usr/local/lib/libgrpc++.so.1+0x7568b)
#12 0x7fe9cf5a78d2 in grpc_core::(anonymous namespace)::ThreadInternalsPosix::ThreadInternalsPosix(char const*, void (*)(void*), void*, bool*, grpc_core::Thread::Options const&)::{lambda(void*)#1}::_FUN(void*) (/usr/local/lib/libgpr.so.10+0x118d2)
#13 0x7fe9d1eef6da in start_thread (/lib/x86_64-linux-gnu/libpthread.so.0+0x76da)
#14 0x7fe9d0ba8a3e in __clone (/lib/x86_64-linux-gnu/libc.so.6+0x121a3e)
0x61b00000fcc8 is located 72 bytes inside of 1448-byte region [0x61b00000fc80,0x61b000010228)
allocated by thread T5 (grpcpp_sync_ser) here:
#0 0x7fe9d355f448 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xe0448)
#1 0x7fe9d18274f2 in grpc_impl::Server::SyncRequestThreadManager::DoWork(void*, bool, bool) (/usr/local/lib/libgrpc++.so.1+0x704f2)
Thread T5 (grpcpp_sync_ser) created by T0 here:
#0 0x7fe9d34b6d2f in __interceptor_pthread_create (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x37d2f)
#1 0x7fe9cf5a7a92 in grpc_core::Thread::Thread(char const*, void (*)(void*), void*, bool*, grpc_core::Thread::Options const&) (/usr/local/lib/libgpr.so.10+0x11a92)
SUMMARY: AddressSanitizer: bad-free (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xe12c0) in operator delete(void*)
==14394==ABORTING
None of my code tries to free any pointer and error seems to be coming from some auto generated file only. Please suggest if some more code/details needed.
I briefly checked the error message and code but it looks strange to me because both allocation and destruction were done by C++ new & delete. This is also consistent with your error message.
### Destruction (with operator delete)
#0 0x7fe9d35602c0 in operator delete(void*) (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xe12c0)
### Allocation (with operator new)
#0 0x7fe9d355f448 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xe0448)
This might be caused by other issues like buggy ASAN or customized memory allocator.
From some time I am trying to catch a problem with my product hanging. This is the call stack I got after coredumping the process with gcore:
/lib64/libc.so.6
#1 0x00007f36fb339ba6 in _L_lock_12192 () from /lib64/libc.so.6
#2 0x00007f36fb337121 in malloc () from /lib64/libc.so.6
#3 0x00007f36fbbef0cd in operator new(unsigned long) () from /lib64/libstdc++.so.6
#4 0x00007f36fbc4d7e9 in std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) () from /lib64/libstdc++.so.6
#5 0x00007f36fbc4e42b in std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned long) () from /lib64/libstdc++.so.6
#6 0x00007f36fbc4e4d4 in std::string::reserve(unsigned long) () from /lib64/libstdc++.so.6
#7 0x00007f36fbc2b3c6 in std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::overflow(int) () from /lib64/libstdc++.so.6
#8 0x00007f36fbc2fb36 in std::basic_streambuf<char, std::char_traits<char> >::xsputn(char const*, long) () from /lib64/libstdc++.so.6
#9 0x00007f36fbc26885 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 /lib64/libstdc++.so.6
#10 0x00007f36fe85c83a in ?? ()
#11 0x00007f36fb2ffdff in vfprintf () from /lib64/libc.so.6
#12 0x000000000055c110 in fgetc#plt ()
#13 0xffffffffffffffa8 in ?? ()
#14 0xffffffffffffffa8 in ?? ()
#15 0x0000000000bc42a0 in ?? ()
#16 0x000000000055b8b0 in setsockopt#plt ()
#17 0x000000000055bf30 in log4cxx::NDC::push ()
This is multithreaded code executed after forking a process in log4cxx ndc push seemingly. All the other threads sleep on condition variables and this is the only one deadlocked. What could possibly make malloc deadlock?
You shouldn't fork processes that use threading.
If one of the other threads has a lock acquired (let's say, the lock in malloc) during the fork, the lock is cloned in locked state, but the thread that locked it isn't running in the forked process. This means that the lock will never be released.
I encounter a coredump when read file content to std::string. Code is list below:
bool readContentFromFile(const char* fileName, std::string& content)
{
std::ifstream t(fileName);
if(!t) {
return false;
}
t.seekg(0, std::ios::end);
content.reserve(t.tellg());
t.seekg(0, std::ios::beg);
content.assign((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
return true;
}
But occasionally the code cause coredump as below:
...
#4 <signal handler called>
#5 0x00007f347a0f3945 in raise () from /lib64/libc.so.6
#6 0x00007f347a0f4f21 in abort () from /lib64/libc.so.6
#7 0x00007f347a953504 in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib64/libstdc++.so.6
#8 0x00007f347a951946 in ?? () from /usr/lib64/libstdc++.so.6
#9 0x00007f347a951973 in std::terminate() () from /usr/lib64/libstdc++.so.6
#10 0x00007f347a951a5a in __cxa_throw () from /usr/lib64/libstdc++.so.6
#11 0x00007f347a8ef2ba in std::__throw_ios_failure(char const*) () from /usr/lib64/libstdc++.so.6
#12 0x00007f347a901317 in std::basic_filebuf<char, std::char_traits<char> >::underflow() () from /usr/lib64/libstdc++.so.6
#13 0x00000000004c2751 in char* std::string::_S_construct<std::istreambuf_iterator<char, std::char_traits<char> > >(std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> >, std::allocator<char> const&, std::input_iterator_tag) ()
#14 0x00000000004c281b in std::string& std::string::_M_replace_dispatch<std::istreambuf_iterator<char, std::char_traits<char> > >(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> >, std::__false_type) ()
#15 0x00000000004bf225 in readContentFromFile(char const*, std::string&) ()
From the above code snippets, exception is throwed in underflow function. But I have no idea why throw exception. The file maybe removed when reading, but which statment in code maybe cause throwing exception?
Pretty clear from the stack trace that the exception is being thrown from content.assign. Looks like string::assign is an inline function which calls std::string::_M_replace_dispatch. You could check this by looking at the header files, or using a debugger. Does that answer the question?