I have a multi threaded program where I forgot to use a mutex. Once, the program aborted with the following stack trace:
T abort
T __libc_message
t malloc_printerr
T free
T operator delete(void*)
W std::basic_string<char, std::char_traits<char>, std::allocator<char>>::~basic_string()`
I used the gnu c++ compiler 4.4.3 (on Ubuntu 10.04). Is it true, that this behaviour could be because of the usage of the string like the following example. In real it is much more complicated but I want to know if the following simple code could cause such an abort.
Thread which aborts when the destructor of the copy string is called:
void f()
{
std::string s = someglobalstring;
}
Thread which modifies string:
void g()
{
someglobalstring = newcontent;
}
Questions:
Are newer C++ implementations thread safe with reading and writing of std::string?
Is it expected that the destructor aborts here?
Strings are not thread safe. If you want to do this, use a std::mutex when accessing your string.
void g()
{
std::lock_guard<std::mutex> lock(m);
someglobalstring = newcontent;
}
Same for f, and define m (type std::mutex) with the string.
Related
I'm using a lock free stack (via tagged pointers) to manage a pool of small blocks of memory. The list nodes are created and destroyed in-place when the blocks are inserted into, and removed from, the pool.
This is a very simplified test program, which only pops from the stack. So, no ABA problem and no tagged pointers. It is sufficient to demonstrate the race I'm running into:
#include <atomic>
#include <list>
#include <thread>
#include <type_traits>
struct Node {
Node() = default;
Node(Node *n) { next.store(n); }
std::atomic<Node *> next;
};
using Memory = std::aligned_storage_t<sizeof(Node)>;
struct Stack {
bool pop_and_use() {
for (Node *current_head = head.load(); current_head;) {
Node *next = current_head->next.load(); // READ RACE
if (head.compare_exchange_weak(current_head, next, std::memory_order_seq_cst)) {
current_head->~Node();
Memory *mem = reinterpret_cast<Memory *>(current_head);
new (mem) int{0}; // use memory with non-atomic write (WRITE RACE)
return true;
}
}
return false;
}
void populate(Memory *mem, int count) {
for (int i = 0; i < count; ++i) {
head = new (mem + i) Node(head.load());
}
}
std::atomic<Node *> head{};
};
int main() {
Memory storage[10000];
Stack test_list;
test_list.populate(storage, 10000);
std::thread worker([&test_list]() {
while (test_list.pop_and_use()) {
};
});
while (test_list.pop_and_use()) {};
worker.join();
return 0;
}
Thread sanitizer reports the following error:
clang++-10 -fsanitize=thread tsan_test_2.cpp -o tsan_test_2 -O2 -g2 -Wall -Wextra && ./tsan_test_2
LLVMSymbolizer: error reading file: No such file or directory
==================
WARNING: ThreadSanitizer: data race (pid=35998)
Atomic read of size 8 at 0x7fff48bd57b0 by thread T1:
#0 __tsan_atomic64_load <null> (tsan_test_2+0x46d88e)
#1 std::__atomic_base<Node*>::load(std::memory_order) const /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/atomic_base.h:713:9 (tsan_test_2+0x4b3e6c)
#2 std::atomic<Node*>::load(std::memory_order) const /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/atomic:452:21 (tsan_test_2+0x4b3e6c)
#3 Stack::pop_and_use() /home/BOSDYN/akhripin/tmp/tsan_test_2.cpp:17:39 (tsan_test_2+0x4b3e6c)
#4 main::$_0::operator()() const /home/BOSDYN/akhripin/tmp/tsan_test_2.cpp:40:22 (tsan_test_2+0x4b3e6c)
#5 void std::__invoke_impl<void, main::$_0>(std::__invoke_other, main::$_0&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/invoke.h:60:14 (tsan_test_2+0x4b3e6c)
#6 std::__invoke_result<main::$_0>::type std::__invoke<main::$_0>(main::$_0&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/invoke.h:95:14 (tsan_test_2+0x4b3e6c)
#7 decltype(std::__invoke(_S_declval<0ul>())) std::thread::_Invoker<std::tuple<main::$_0> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/thread:244:13 (tsan_test_2+0x4b3e6c)
#8 std::thread::_Invoker<std::tuple<main::$_0> >::operator()() /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/thread:253:11 (tsan_test_2+0x4b3e6c)
#9 std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::$_0> > >::_M_run() /usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/thread:196:13 (tsan_test_2+0x4b3e6c)
#10 <null> <null> (libstdc++.so.6+0xbd6de)
Previous write of size 4 at 0x7fff48bd57b0 by main thread:
#0 Stack::pop_and_use() /home/BOSDYN/akhripin/tmp/tsan_test_2.cpp:21:9 (tsan_test_2+0x4b3d5d)
#1 main /home/BOSDYN/akhripin/tmp/tsan_test_2.cpp:43:20 (tsan_test_2+0x4b3d5d)
Location is stack of main thread.
Location is global '??' at 0x7fff48bad000 ([stack]+0x0000000287b0)
Thread T1 (tid=36000, running) created by main thread at:
#0 pthread_create <null> (tsan_test_2+0x4246bb)
#1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xbd994)
#2 __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310 (libc.so.6+0x21b96)
SUMMARY: ThreadSanitizer: data race (/home/BOSDYN/akhripin/tmp/tsan_test_2+0x46d88e) in __tsan_atomic64_load
==================
ThreadSanitizer: reported 1 warnings
The problem arises when the two threads read the same value of current_head, but one of them completes the pop and overwrites the node before the other has a chance to read current_head->next.
This is similar to the problem discussed here: Why would 'deleting' nodes in this lock-free stack class would cause race condition? except the memory is not actually being deallocated.
I know that from the machine's perspective, this race is benign -- if the read race occurs, the compare-and-swap will not succeed -- but I think this is still getting into undefined behavior territory in C++.
Is there any way to write this code without getting a race condition?
Is there any way to annotate the code to make thread sanitizer ignore it? I experimented with __tsan_acquire and __tsan_release but could not find something that consistently worked.
Update I'm pretty convinced that there is no way to perform the atomic read safely in standard C++ -- the object just doesn't exist any more. But -- can I go from relying on undefined behavior to relying on implementation-defined behavior? What's the best I could do, given typical architectures and toolchains (x86/ARM, gcc/clang)?
Update 2 One implementation-specific approach that seems to work is to replace the load with inline assembly:
inline Node *load_next_wrapper(Node *h) {
Node *ret;
asm volatile("movq (%1), %0" : "=r"(ret) : "r"(&h->next));
return ret;
}
This is both architecture and compiler specific -- but I think this does replace "undefined" behavior with "implementation-defined" behavior.
Tagged pointers are fine if you simply want to reuse the same nodes in the data structure, i.e., you don't destroy it, but simply put it on a free-list so it can be reused when you need a new node in the next push operation. In this case tagged pointers are sufficient to prevent the ABA problem, but they are no solution to the _ memory reclamation problem_ that you face here.
Another object of some type will be constructed in the same location. Eventually, it will be destroyed and the memory would return to the pool.
This is the real issue - you are destroying the object and reusing the memory for something else. As many others have already explained in the comments this causes undefined behavior. I am not sure what you mean by "return to the pool" - return to the memory manager? Ignoring the UB for a moment - you are right that this race is usually benign (from the hardware perspective), but if you do release the memory at some point, you could actually run into a segmentation fault (e.g. in case the memory manager decides to return the memory to the OS).
How to avoid undefined behavior in this scenario
If you want to reuse the memory for something else, you have to use a memory reclamation scheme like lock-free reference counting, hazard pointers, epoch based reclamation or DEBRA. These can ensure that an object is only destroyed once it is guaranteed that all references to it have been dropped, so it can no longer be accessed by any thread.
My xenium library provides C++ implementations of various reclamation schemes (including all those previously mentioned) that you could use in this situation.
I am currently learning multithreading in c++11 and I am confused with the way to terminate a thread safely.
In c++, I know the way to create threads and use thread.join() to safely ensure main() to wait for all threads to finish before quitting itself.
However, I found that some multithread codes implemented via pointers are able to run even without using thread.join().
class Greating
{
public:
Greating(const int& _i):i_(_i){}
~Greating(){}
int i_;
void say()
{
std::cout << "Hello World" << i_ << std::endl;
}
};
int main(){
Greating greating1(1);
Greating greating2(2);
std::thread t1(&Greating::say, greating1);
std::thread t2(&Greating::say, greating2);
return 0;
}
The code shown above will absolutely report the error "terminate called without an active exception
Aborted (core dumped)", because I did not use t1.join() and t2.join().
However, I found in some codes when they use the pointer to manage the thread, this does not become a problem, as shown below.
class Greating
{
public:
Greating(const int& _i):i_(_i){}
~Greating(){}
int i_;
void say()
{
std::cout << "Hello World" << i_ << std::endl;
}
};
int main(){
Greating greating1(1);
Greating greating2(2);
std::thread* tt1 = new std::thread(&Greating::say, greating1);
std::thread* tt2 = new std::thread(&Greating::say, greating2);
return 0;
}
The output is:
Hello WorldHello World12
Hello World12
There is no error reported. This made me very confused.
So my question is:
Why when we use pointer to manage the thread, we could not use the function thread.join()?
How to correctly terminate a thread? (probably wait for the callable function to finish?)
Thanks very much!
When creating objects with dynamic allocation, you have to deallocate the memory with operator delete so it calls appropriate destructor.
In the first example, two std::thread objects are created. At the end of main function, the destructor std::thread::~thread is called. Since the threads are not joined, the destructor reports an error.
On the other hand, in the second example, you called operator new so you create objects with dynamic allocation. But, you didn't call operator delete, so the destructor is not called. That is, the program didn't check whether the threads are joined.
Therefore, the only way to correctly terminate a thread is to call std::thread::join. If you want to use pointers, you have to do as following:
std::thread *th = new std::thread(foo);
...
th->join();
delete th;
The code below throws a segmentation fault inside the .join() of the std::thread class. However, that is happen only I use cv::fastMalloc to allocate a data array. If I use the 'new' keyword or the std::malloc function no error happens.
I need understand why this error happens because in fact I need a cv::Mat that uses this function.
int main() {
uchar* data = (uchar*) cv::fastMalloc(640);
std::atomic<bool> running(true);
std::thread thread([&] () {
while(running) {
// I'll perform some process with data here
// for now, just to illustrate, I put thread to sleep
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
});
std::this_thread::sleep_for(std::chrono::seconds(1));
running = false;
// segfault is thrown here
thread.join();
cv::fastFree(data);
return 0;
}
The GDB callstack follows below
#0 00429B26 _pthread_cleanup_dest () (??:??)
#1 003E32A0 ?? () (??:??)
Does anyone know what might be happening? I really think it is too crazy :S.
Thanks.
I solved this issue reinstalling the opencv. Apparently the problem was the different versions of compilers that I had compiled the opencv and I'm using in this example.
For the record, I had compiled the opencv some time ago with a MinGW version that not support std::thread (I think 4.7.x).
I'm attempting to access a shared std::queue using a std::mutex and a std::lock_guard. The mutex (pending_md_mtx_) is a member variable of another object (whose address is valid). My code seems to be segfault'ing on the construction of the lock_guard.
Any ideas? Should I be using a std::unique_lock (or some other object) instead? Running GCC 4.6 (--std=c++0x) under Ubuntu Linux. I can't post the entire class, but the only accesses to the mutex and queue listed below.
template <typename ListenerT>
class Driver
{
public:
template <typename... Args>
Driver(Args&&... args) :
listener_(std::forward<Args>(args)...) {}
void enqueue_md(netw::Packet* packet)
{
std::lock_guard<std::mutex> lock(pending_md_mtx_);
pending_md_.push(packet);
}
void process_md()
{
std::lock_guard<std::mutex> lock(pending_md_mtx_);
while (pending_md_.size())
{
netw::Packet* pkt=pending_md_.front();
pending_md_.pop();
process_md(*pkt);
}
}
//... Other code which I can't post...
private:
ListenerT listener_;
std::mutex pending_md_mtx_;
std::queue<netw::Packet*> pending_md_;
};
GDB Stacktrace:
(gdb) bt
#0 __pthread_mutex_lock (mutex=0x2f20aa75e6f4000) at pthread_mutex_lock.c:50
#1 0x000000000041a2dc in __gthread_mutex_lock (__mutex=0xff282ceacb40) at /usr/include/c++/4.6/x86_64-linux-gnu/./bits/gthr-default.h:742
#2 lock (this=0xff282ceacb40) at /usr/include/c++/4.6/mutex:90
#3 lock_guard (__m=..., this=0x7f2874fc4db0) at /usr/include/c++/4.6/mutex:445
#4 driver::Driver<Listener, false>::enqueue_md (this=0xff282ceac8a0, packet=...) at exec/../../driver/Driver.hpp:95
I was getting a segfault on constructing the std::lock_guard, turns out my code was using an uninitialized std::shared_ptr<my_object_with_mutex>. Using a properly constructed my_object_with_mutex resolves the problem.
I recently encountered this problem. It was caused by line of code causing a buffer overrun after acquiring the lock. It would seem odd for a line of code below the lock to be causing a problem a few lines earlier, but I suppose the buffer overrun would cause some corruption that causes a problem on a second call to the function.
The issue rootcause in my case:
An object A references object B
On call to object B.func() I see a SegFault on lock_guard
Object B has never been set for object A (not initialized, a NULL pointer), leading to a SegFault on accessing a field (mutex, in my case).
The error could be diagnosed from GDB by noticing this=0x0:
...
#4 0x000055e3a9e14a3c in B<C>::write (this=0x4e2280, msg=0x55e3aac03be0) at /proj/B.hpp:35
#5 0x000055e3a9e206e6 in A::write (this=0x0, msg=0x55e3aac03be0) at /proj/A.cpp:286
#6 0x000055e3a9e2069a in A::write (this=0x7f21eae64010, msg=0x55e3aac03be0) at /proj/A.cpp:277
...
In my case the root cause was the same (object with mutex uninitialized), but the reason was not.
The object that had the mutex had a function reset. Guess what, shared_ptr has also a function named reset, and I called that instead!
Avoid using reset as a name, or double-check if you're not using obj.reset() instead of obj->reset()!
My program crashes before main() function. I determine this using "cerr":
int main(int argc, char **argv)
{
cerr << " MAAIN " << endl;
The message from gdb:
Reading symbols for shared libraries ...........+++............................ done
CA(34652) malloc: *** error for object 0x7fff76694860: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Program received signal SIGABRT, Aborted.
0x00007fff88e1782a in __kill ()
(gdb) bt
#0 0x00007fff88e1782a in __kill ()
#1 0x00007fff8c4d2a9c in abort ()
#2 0x00007fff8c53184c in free ()
#3 0x00000001026a1db0 in std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::overflow ()
(gdb)
I have checked the code for "delete" and "free" functions. All deletes are done with check like this:
if (x) delete x;
Please help me with answering two questions:
1. What can be the possible problem?
2. How to find it? (I have a big code with a lot of files and cmake for compilation).
P.S. I read Is there any way a C/C++ program can crash before main()? but looking at gdb massage I suppose libraries are ok.
cout is not a good way to check where your program is crashing because cout does not immediately flush its buffer and it is possible that you programs crashes after cout but before flushing buffer. it's better to check it with cerr instead of cout
And before main function, constructors of global variables will call. so take look at them if you think it crashes before start.
an other possibility is allocating memory for arrays in you main function that happens before calling of main function. if they are huge. you must use new to allocate memory for them.
std::basic_stringbuf<char, std::char_traits<char>... tells me that it's std::string that is going wrong. One quite possible scenario is that you have something that is trying to "free" a string, that hasn't been constructed correctly or that has been overwritten by uncareful use of arrays.
Or you are relying on some global variables in different source files, so you have something like this:
// main.cpp:
...
extern string str; // str lives in another .cpp file
....
myclass x(str); // Construction using str.
// otherfile.cpp
string str("foobar");
In this case, str may not be constructed by the time x is being constructed, and the string is "invalid".
There are oodles of other possibilities along similar lines.
The address here: 0x7fff76694860 is on the stack. If it's always the same value, you could try to track down where it is.