There is a class with one signal and slot:
#ifndef SOME_CLASS_H
#define SOME_CLASS_H
#include <QObject>
class SomeClass : public QObject
{
Q_OBJECT
public:
explicit SomeClass(QObject *parent = 0) : QObject(parent) {
connect(this, &SomeClass::valueChanged, this, &SomeClass::setValue);
}
void emitSignal() {
emit valueChanged();
}
signals:
void valueChanged();
public slots:
void setValue() {}
};
#endif // SOME_CLASS_H
Here is main file of program defining a singleton which creates instance of above defined class and puts it into separate thread:
#include <QCoreApplication>
#include <QThread>
#include <someclass.h>
class Singleton {
public:
QThread t;
SomeClass someClassObject;
Singleton() {
someClassObject.moveToThread(&t);
t.start();
}
static SomeClass& getInstance() {
static Singleton st;
return st.someClassObject;
}
~Singleton() {
t.quit();
t.wait();
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
SomeClass& b = Singleton::getInstance();
b.emitSignal();
QThread::msleep(100);
return a.exec();
}
The problem is that when I evaluate this program using some thread checking tools like ThreadSanitizer or Helgrind then several warnings are reported about data race conditions. Example output from ThreadSanitizer:
==================
WARNING: ThreadSanitizer: data race (pid=3827)
Read of size 8 at 0x7d040000f6a0 by thread T1:
#0 void QtPrivate::FunctionPointer<void (SomeClass::*)()>::call<void, void>(void (SomeClass::*)(), SomeClass*, void**) /usr/include/qt5/QtCore/qobjectdefs_impl.h:142 (exe+0x0000000a2d1c)
#1 QtPrivate::QSlotObject<void (SomeClass::*)(), void, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) /usr/include/qt5/QtCore/qobject_impl.h:149 (exe+0x0000000a29b4)
#2 QObject::event(QEvent*) ??:0 (libQt5Core.so.5+0x00000029022d)
Previous write of size 8 at 0x7d040000f6a0 by main thread:
#0 malloc ??:0 (exe+0x0000000426e9)
#1 QMetaObject::activate(QObject*, int, int, void**) ??:0 (libQt5Core.so.5+0x00000028ef1c)
#2 main /tmp/project/main.cpp:31 (exe+0x0000000a19f2)
Location is heap block of size 8 at 0x7d040000f6a0 allocated by main thread:
#0 malloc ??:0 (exe+0x0000000426e9)
#1 QMetaObject::activate(QObject*, int, int, void**) ??:0 (libQt5Core.so.5+0x00000028ef1c)
#2 main /tmp/project/main.cpp:31 (exe+0x0000000a19f2)
Thread T1 'QThread' (tid=3829, running) created by main thread at:
#0 pthread_create ??:0 (exe+0x000000046f6b)
#1 QThread::start(QThread::Priority) ??:0 (libQt5Core.so.5+0x0000000928b7)
#2 Singleton::getInstance() /tmp/project/main.cpp:16 (exe+0x0000000a1b3c)
#3 main /tmp/project/main.cpp:30 (exe+0x0000000a19bf)
SUMMARY: ThreadSanitizer: data race /usr/include/qt5/QtCore/qobjectdefs_impl.h:142 void QtPrivate::FunctionPointer<void (SomeClass::*)()>::call<void, void>(void (SomeClass::*)(), SomeClass*, void**)
==================
==================
WARNING: ThreadSanitizer: data race (pid=3827)
Write of size 1 at 0x7d040000f6b0 by thread T1:
#0 free ??:0 (exe+0x000000042dfb)
#1 QMetaCallEvent::~QMetaCallEvent() ??:0 (libQt5Core.so.5+0x00000028d3a4)
Previous write of size 8 at 0x7d040000f6b0 by main thread:
#0 malloc ??:0 (exe+0x0000000426e9)
#1 QMetaObject::activate(QObject*, int, int, void**) ??:0 (libQt5Core.so.5+0x00000028eefe)
#2 main /tmp/project/main.cpp:31 (exe+0x0000000a19f2)
Location is heap block of size 4 at 0x7d040000f6b0 allocated by main thread:
#0 malloc ??:0 (exe+0x0000000426e9)
#1 QMetaObject::activate(QObject*, int, int, void**) ??:0 (libQt5Core.so.5+0x00000028eefe)
#2 main /tmp/project/main.cpp:31 (exe+0x0000000a19f2)
Thread T1 'QThread' (tid=3829, running) created by main thread at:
#0 pthread_create ??:0 (exe+0x000000046f6b)
#1 QThread::start(QThread::Priority) ??:0 (libQt5Core.so.5+0x0000000928b7)
#2 Singleton::getInstance() /tmp/project/main.cpp:16 (exe+0x0000000a1b3c)
#3 main /tmp/project/main.cpp:30 (exe+0x0000000a19bf)
SUMMARY: ThreadSanitizer: data race ??:0 free
==================
==================
WARNING: ThreadSanitizer: data race (pid=3827)
Write of size 8 at 0x7d180000edc0 by thread T1:
#0 operator delete(void*) ??:0 (exe+0x00000004392b)
#1 QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) ??:0 (libQt5Core.so.5+0x000000269e0f)
Previous write of size 8 at 0x7d180000edc0 by main thread:
#0 operator new(unsigned long) ??:0 (exe+0x0000000432b9)
#1 QMetaObject::activate(QObject*, int, int, void**) ??:0 (libQt5Core.so.5+0x00000028ef94)
#2 main /tmp/project/main.cpp:31 (exe+0x0000000a19f2)
Location is heap block of size 88 at 0x7d180000edc0 allocated by main thread:
#0 operator new(unsigned long) ??:0 (exe+0x0000000432b9)
#1 QMetaObject::activate(QObject*, int, int, void**) ??:0 (libQt5Core.so.5+0x00000028ef94)
#2 main /tmp/project/main.cpp:31 (exe+0x0000000a19f2)
Thread T1 'QThread' (tid=3829, running) created by main thread at:
#0 pthread_create ??:0 (exe+0x000000046f6b)
#1 QThread::start(QThread::Priority) ??:0 (libQt5Core.so.5+0x0000000928b7)
#2 Singleton::getInstance() /tmp/project/main.cpp:16 (exe+0x0000000a1b3c)
#3 main /tmp/project/main.cpp:30 (exe+0x0000000a19bf)
SUMMARY: ThreadSanitizer: data race ??:0 operator delete(void*)
==================
What does cause these race conditions?
Since the warnings are all originating in Qt internals related to signals, slots, and event loops, I think that the race conditions detected are false positives. Does Helgrind detect the same race conditions? Helgrind bugs with Qt are reported by some, (http://www.kdab.com/~dfaure/helgrind.html) and seem to be addressed recently.
Related
We are getting false positive ThreadSanitizer (tsan) data race warnings on a frequent but inconsistent basis. Though it is well-known that tsan can give false positive warnings, some of which may be suppressed via the TSAN_OPTIONS environment variable, there is a particular class of warnings that we are encountering that appear specifically related to Intel's Thread Building Block's (tbb) use of tbb::detail::r1::rml::private_server that appears preventable if we could somehow have more control over the stopping of this private_server for instance. Here is one such false positive tsan data race warning encountered during a Google Test run:
WARNING: ThreadSanitizer: data race (pid=5244)
Write of size 1 at 0x7ffda4d64fd8 by main thread:
#0 std::shared_lock<std::shared_mutex>::shared_lock(std::shared_mutex&, std::defer_lock_t) /usr/local/foo-deps/20220316/include/c++/9.4.0/shared_mutex:639 (FooTest+0x68d162)
#1 FooProxy::buildTranslationMapToOtherProxy(FooProxy*, std::vector<foo::StringOpInfo, std::allocator<foo::StringOpInfo> > const&) const /home/jenkins-slave/workspace/core-tsan-gcc/Foo/FooProxy.cpp:323 (FooTest+0x68d162)
#2 FooProxy_BuildTranslationMapToPartialOverlapProxy_Test::TestBody() /home/jenkins-slave/workspace/core-tsan-gcc/Tests/FooTest.cpp:798 (FooTest+0x5c5284)
#3 void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:3968 (FooTest+0x62d798)
#4 void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:4004 (FooTest+0x62d798)
#5 testing::Test::Run() /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:4043 (FooTest+0x618586)
#6 testing::TestInfo::Run() /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:4219 (FooTest+0x6187d4)
#7 testing::TestSuite::Run() /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:4351 (FooTest+0x618959)
#8 testing::internal::UnitTestImpl::RunAllTests() /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:6892 (FooTest+0x618e7e)
#9 bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:3968 (FooTest+0x62de38)
#10 bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:4004 (FooTest+0x62de38)
#11 testing::UnitTest::Run() /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:6479 (FooTest+0x619440)
#12 RUN_ALL_TESTS() /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gtest/gtest.h:11696 (FooTest+0x5b401a)
#13 main /home/jenkins-slave/workspace/core-tsan-gcc/Tests/FooTest.cpp:974 (FooTest+0x5b401a)
Previous read of size 8 at 0x7ffda4d64fd8 by thread T18:
[failed to restore the stack]
Location is stack of main thread.
Location is global '<null>' at 0x000000000000 ([stack]+0x00000001efd8)
Thread T18 (tid=5264, running) created by main thread at:
#0 pthread_create ../../.././libsanitizer/tsan/tsan_interceptors.cc:964 (libtsan.so.0+0x2cd6b)
#1 tbb::detail::r1::rml::private_server::wake_some(int) <null> (FooTest+0x8828ce)
#2 tbb::detail::d1::task* tbb::detail::r1::task_dispatcher::local_wait_for_all<false, tbb::detail::r1::external_waiter>(tbb::detail::d1::task*, tbb::detail::r1::external_waiter&) <null> (FooTest+0x88b1c2)
#3 tbb::detail::r1::task_arena_impl::execute(tbb::detail::d1::task_arena_base&, tbb::detail::d1::delegate_base&) <null> (FooTest+0x86e74c)
#4 Foo::getStringViews() const /home/jenkins-slave/workspace/core-tsan-gcc/Foo/Foo.cpp:1869 (FooTest+0x63612c)
#5 Foo_GetStringViews_Test::TestBody() /home/jenkins-slave/workspace/core-tsan-gcc/Tests/FooTest.cpp:141 (FooTest+0x5c625c)
#6 void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:3968 (FooTest+0x62d798)
#7 void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:4004 (FooTest+0x62d798)
#8 testing::Test::Run() /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:4043 (FooTest+0x618586)
#9 testing::TestInfo::Run() /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:4219 (FooTest+0x6187d4)
#10 testing::TestSuite::Run() /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:4351 (FooTest+0x618959)
#11 testing::internal::UnitTestImpl::RunAllTests() /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:6892 (FooTest+0x618e7e)
#12 bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:3968 (FooTest+0x62de38)
#13 bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:4004 (FooTest+0x62de38)
#14 testing::UnitTest::Run() /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gmock-gtest-all.cc:6479 (FooTest+0x619440)
#15 RUN_ALL_TESTS() /home/jenkins-slave/workspace/core-tsan-gcc/ThirdParty/googletest/gtest/gtest.h:11696 (FooTest+0x5b401a)
#16 main /home/jenkins-slave/workspace/core-tsan-gcc/Tests/FooTest.cpp:974 (FooTest+0x5b401a)
SUMMARY: ThreadSanitizer: data race /usr/local/foo-deps/20220316/include/c++/9.4.0/shared_mutex:639 in std::shared_lock<std::shared_mutex>::shared_lock(std::shared_mutex&, std::defer_lock_t)
(Some names have been altered for anonymity.)
Summary of events in chronological order:
Google test Foo.GetStringViews is run (Thread T18 frame #5)
During this test, an instance ta of tbb::task_arena calls ta.execute([&] { tbb::parallel_for(...); });.
This appears to run tbb::detail::r1::rml::private_server::wake_some(int) which spawns a thread that survives in between Google tests.
Google test FooProxy.BuildTranslationMapToPartialOverlapProxy is run (main thread frame #2)
This test writes to address 0x7ffda4d64fd8 that was read by the previous test.
Our TSAN_OPTIONS environment variable is set to
suppressions=/path/to/tsan.suppressions, history_size=7, second_deadlock_stack=1, halt_on_error=1
We surmise that the false positive data race warning is due to 3 primary ingredients:
Two independent tests are run synchronously one after the other in which no data race is possible, but happen to read/write or write/write to/from the same memory address.
One of the thread's stack exceeds the maximum history_size=7 and reports [failed to restore the stack].
The first thread spawns a tbb::detail::r1::rml::private_server that survives through to the second test.
It is because the tbb::detail::r1::rml::private_server from the first test remains concurrent with the second test that confuses tsan to flag this as a data race.
Question(s)
How can the tbb::detail::r1::rml::private_server thread be killed at the beginning or end of each test?
Alternatively, if that's not possible, is there something that we can add to our tsan.suppressions file or TSAN_OPTIONS environment variable that specifically suppresses this false warning without hiding real data races that may occur?
To kill the tbb::detail::r1::rml::private_server after each Google Test, we overrode the Test Fixture TearDown() method:
void TearDown() override {
// Expected to kill tbb::detail::r1::rml::private_server after each test,
// which can otherwise trigger false positive tsan data race warnings.
auto handle = tbb::task_scheduler_handle::get();
tbb::finalize(handle, std::nothrow_t{});
}
In our version of TBB we also had to #define TBB_PREVIEW_WAITING_FOR_WORKERS and #include <tbb/global_control.h>.
Credit: Pavel Kumbrasev for the suggestion.
You can replace the Mach semaphore with a dispatch semaphore to suppress the warnings.
Refer to the below link:
https://developer.apple.com/documentation/dispatch/dispatch_semaphore
You can also create a suppression file to specify the suppressions runtime flag
https://github.com/google/sanitizers/wiki/ThreadSanitizerSuppressions
If this helps, you can apply the settings at compile time:
-fsanitize=thread -fsanitize-blacklist=sanitizer-thread-suppressions.txt
Here is a simple example for using std::condition_variable. When using clang+tsan for building the following code,
#include <cassert>
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
class WaitSignalLock {
private:
std::condition_variable conditionVariable;
std::mutex mtx;
bool condition = false;
public:
bool wait(const std::chrono::milliseconds& timeout);
void signal();
private:
bool conditionMet() const;
bool waitForConditionVariableSignal(std::unique_lock<std::mutex>& lck, const std::chrono::milliseconds& timeout);
};
bool WaitSignalLock::wait(const std::chrono::milliseconds& timeout) {
std::unique_lock<std::mutex> lck(this->mtx);
const auto result = waitForConditionVariableSignal(lck, timeout);
condition = false;
return result;
}
void WaitSignalLock::signal() {
// the variable used for checking the condition has to be modified under a lock (even if the variable is atomic),
// and the condition variable should not be notified under a lock
{
std::lock_guard<std::mutex> lck(this->mtx);
condition = true;
}
conditionVariable.notify_one();
}
bool WaitSignalLock::conditionMet() const {
// do not lock, method will be called under the lock already
return condition;
}
bool WaitSignalLock::waitForConditionVariableSignal(std::unique_lock<std::mutex>& lck, const std::chrono::milliseconds& timeout) {
assert(lck.owns_lock());
if(this->conditionVariable.wait_for(lck, timeout, [this]() {
return this->conditionMet();
})) {
return true;
}
else {
return false;
}
}
int main(int, char**) {
WaitSignalLock waitSignalLock;
std::thread sendSignal([&waitSignalLock]() {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
waitSignalLock.signal();
});
const auto result = waitSignalLock.wait(std::chrono::seconds(1));
sendSignal.join();
return !result;
}
tsan reports the following two issues:
WARNING: ThreadSanitizer: double lock of a mutex (pid=16421)
#0 pthread_mutex_lock <null> (a.out+0x7e358)
#1 __gthread_mutex_lock(pthread_mutex_t*) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/x86_64-pc-linux-gnu/bits/gthr-default.h:749:12 (a.out+0xd39a6)
#2 std::mutex::lock() /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/bits/std_mutex.h:100:17 (a.out+0xd45e9)
#3 std::lock_guard<std::mutex>::lock_guard(std::mutex&) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/bits/std_mutex.h:159:19 (a.out+0xd4148)
#4 WaitSignalLock::signal() /home/jae/projects/condition_variable/main.cpp:38:37 (a.out+0xd367e)
#5 main::$_1::operator()() const /home/jae/projects/condition_variable/main.cpp:67:24 (a.out+0xd3f2f)
#6 void std::__invoke_impl<void, main::$_1>(std::__invoke_other, main::$_1&&) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/bits/invoke.h:60:14 (a.out+0xd3eb1)
#7 std::__invoke_result<main::$_1>::type std::__invoke<main::$_1>(main::$_1&&) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/bits/invoke.h:95:14 (a.out+0xd3e01)
#8 void std::thread::_Invoker<std::tuple<main::$_1> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/thread:264:13 (a.out+0xd3db9)
#9 std::thread::_Invoker<std::tuple<main::$_1> >::operator()() /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/thread:271:11 (a.out+0xd3d69)
#10 std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::$_1> > >::_M_run() /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/thread:215:13 (a.out+0xd3c9d)
#11 execute_native_thread_routine /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:80:18 (libstdc++.so.6+0xcfb73)
Location is stack of main thread.
Location is global '??' at 0x7ffd19818000 ([stack]+0x00000001ec48)
Mutex M12 (0x7ffd19836c48) created at:
#0 pthread_mutex_lock <null> (a.out+0x7e358)
#1 __gthread_mutex_lock(pthread_mutex_t*) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/x86_64-pc-linux-gnu/bits/gthr-default.h:749:12 (a.out+0xd39a6)
#2 std::mutex::lock() /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/bits/std_mutex.h:100:17 (a.out+0xd45e9)
#3 std::unique_lock<std::mutex>::lock() /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/bits/unique_lock.h:138:17 (a.out+0xd46df)
#4 std::unique_lock<std::mutex>::unique_lock(std::mutex&) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/bits/unique_lock.h:68:2 (a.out+0xd40b3)
#5 WaitSignalLock::wait(std::chrono::duration<long, std::ratio<1l, 1000l> > const&) /home/jae/projects/condition_variable/main.cpp:28:34 (a.out+0xd3563)
#6 main /home/jae/projects/condition_variable/main.cpp:70:40 (a.out+0xd3860)
SUMMARY: ThreadSanitizer: double lock of a mutex (/home/jae/projects/condition_variable/a.out+0x7e358) in pthread_mutex_lock
==================
==================
WARNING: ThreadSanitizer: data race (pid=16421)
Write of size 1 at 0x7ffd19836c70 by thread T1 (mutexes: write M12):
#0 WaitSignalLock::signal() /home/jae/projects/condition_variable/main.cpp:39:19 (a.out+0xd3687)
#1 main::$_1::operator()() const /home/jae/projects/condition_variable/main.cpp:67:24 (a.out+0xd3f2f)
#2 void std::__invoke_impl<void, main::$_1>(std::__invoke_other, main::$_1&&) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/bits/invoke.h:60:14 (a.out+0xd3eb1)
#3 std::__invoke_result<main::$_1>::type std::__invoke<main::$_1>(main::$_1&&) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/bits/invoke.h:95:14 (a.out+0xd3e01)
#4 void std::thread::_Invoker<std::tuple<main::$_1> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/thread:264:13 (a.out+0xd3db9)
#5 std::thread::_Invoker<std::tuple<main::$_1> >::operator()() /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/thread:271:11 (a.out+0xd3d69)
#6 std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::$_1> > >::_M_run() /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/thread:215:13 (a.out+0xd3c9d)
#7 execute_native_thread_routine /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:80:18 (libstdc++.so.6+0xcfb73)
Previous read of size 1 at 0x7ffd19836c70 by main thread (mutexes: write M12):
#0 WaitSignalLock::conditionMet() const /home/jae/projects/condition_variable/main.cpp:46:12 (a.out+0xd36ea)
#1 WaitSignalLock::waitForConditionVariableSignal(std::unique_lock<std::mutex>&, std::chrono::duration<long, std::ratio<1l, 1000l> > const&)::$_0::operator()() const /home/jae/projects/condition_variable/main.cpp:52:18 (a.out+0xd3af1)
#2 bool std::condition_variable::wait_until<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> >, WaitSignalLock::waitForConditionVariableSignal(std::unique_lock<std::mutex>&, std::chrono::duration<long, std::ratio<1l, 1000l> > const&)::$_0>(std::unique_lock<std::mutex>&, std::chrono::time_point<std::chrono::_V2::steady_clock, std::chrono::duration<long, std::ratio<1l, 1000000000l> > > const&, WaitSignalLock::waitForConditionVariableSignal(std::unique_lock<std::mutex>&, std::chrono::duration<long, std::ratio<1l, 1000l> > const&)::$_0) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/condition_variable:157:10 (a.out+0xd3a37)
#3 bool std::condition_variable::wait_for<long, std::ratio<1l, 1000l>, WaitSignalLock::waitForConditionVariableSignal(std::unique_lock<std::mutex>&, std::chrono::duration<long, std::ratio<1l, 1000l> > const&)::$_0>(std::unique_lock<std::mutex>&, std::chrono::duration<long, std::ratio<1l, 1000l> > const&, WaitSignalLock::waitForConditionVariableSignal(std::unique_lock<std::mutex>&, std::chrono::duration<long, std::ratio<1l, 1000l> > const&)::$_0) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/condition_variable:185:9 (a.out+0xd378e)
#4 WaitSignalLock::waitForConditionVariableSignal(std::unique_lock<std::mutex>&, std::chrono::duration<long, std::ratio<1l, 1000l> > const&) /home/jae/projects/condition_variable/main.cpp:51:32 (a.out+0xd3608)
#5 WaitSignalLock::wait(std::chrono::duration<long, std::ratio<1l, 1000l> > const&) /home/jae/projects/condition_variable/main.cpp:29:25 (a.out+0xd3572)
#6 main /home/jae/projects/condition_variable/main.cpp:70:40 (a.out+0xd3860)
As if synchronized via sleep:
#0 nanosleep <null> (a.out+0x6aadc)
#1 void std::this_thread::sleep_for<long, std::ratio<1l, 1000l> >(std::chrono::duration<long, std::ratio<1l, 1000l> > const&) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/thread:405:9 (a.out+0xd556a)
#2 main::$_1::operator()() const /home/jae/projects/condition_variable/main.cpp:66:9 (a.out+0xd3f1f)
#3 void std::__invoke_impl<void, main::$_1>(std::__invoke_other, main::$_1&&) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/bits/invoke.h:60:14 (a.out+0xd3eb1)
#4 std::__invoke_result<main::$_1>::type std::__invoke<main::$_1>(main::$_1&&) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/bits/invoke.h:95:14 (a.out+0xd3e01)
#5 void std::thread::_Invoker<std::tuple<main::$_1> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/thread:264:13 (a.out+0xd3db9)
#6 std::thread::_Invoker<std::tuple<main::$_1> >::operator()() /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/thread:271:11 (a.out+0xd3d69)
#7 std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::$_1> > >::_M_run() /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/thread:215:13 (a.out+0xd3c9d)
#8 execute_native_thread_routine /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:80:18 (libstdc++.so.6+0xcfb73)
Location is stack of main thread.
Location is global '??' at 0x7ffd19818000 ([stack]+0x00000001ec70)
Mutex M12 (0x7ffd19836c48) created at:
#0 pthread_mutex_lock <null> (a.out+0x7e358)
#1 __gthread_mutex_lock(pthread_mutex_t*) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/x86_64-pc-linux-gnu/bits/gthr-default.h:749:12 (a.out+0xd39a6)
#2 std::mutex::lock() /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/bits/std_mutex.h:100:17 (a.out+0xd45e9)
#3 std::unique_lock<std::mutex>::lock() /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/bits/unique_lock.h:138:17 (a.out+0xd46df)
#4 std::unique_lock<std::mutex>::unique_lock(std::mutex&) /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/10.1.0/../../../../include/c++/10.1.0/bits/unique_lock.h:68:2 (a.out+0xd40b3)
#5 WaitSignalLock::wait(std::chrono::duration<long, std::ratio<1l, 1000l> > const&) /home/jae/projects/condition_variable/main.cpp:28:34 (a.out+0xd3563)
#6 main /home/jae/projects/condition_variable/main.cpp:70:40 (a.out+0xd3860)
Thread T1 (tid=16423, running) created by main thread at:
#0 pthread_create <null> (a.out+0x8dbce)
#1 __gthread_create /build/gcc/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/gthr-default.h:663:35 (libstdc++.so.6+0xcfe49)
#2 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:135:37 (libstdc++.so.6+0xcfe49)
#3 main /home/jae/projects/condition_variable/main.cpp:65:17 (a.out+0xd3816)
SUMMARY: ThreadSanitizer: data race /home/jae/projects/condition_variable/main.cpp:39:19 in WaitSignalLock::signal()
==================
ThreadSanitizer: reported 2 warnings
I neither understand why the first nor the second warning is reported.
The first warning claims that the mutex is locked twice, but how is this even possible? The mutex is not locked by the same thread while holding it, which is, as far as I understand, what tsan is claiming.
The second warning indicates that the variable 'condition' is not read/written in a thread-safe manner. However, it is only read and written when the mutex is locked. Or is the lock not locked after condition_variable::wait_for returns? According to https://en.cppreference.com/w/cpp/thread/condition_variable/wait_for, the lock should be locked.
Is it possible that this is a bug in clang/tsan? I couldn't find a bug report for this issue, and have a hard time believing that this is the case. But I simply don't see what's wrong with the code above.
I used the following command for compiling the source:
clang++ -O1 -g -fsanitize=thread -fno-omit-frame-pointer -lpthread main.cpp
The clang version is
$ clang --version
clang version 10.0.0
In below code, I am calling make_shared<MyClass>, and the constructor of MyClass throws exception. If the core file is available, is it possible to find out the origin of crash [e.g: whether crash was from foo() or fun()] with the help of gdb?
#include <iostream>
#include <memory>
using namespace std;
class MyClass
{
public:
MyClass()
{
foo();
fun();
}
~MyClass() { }
void foo()
{
throw("error 1");
}
void fun()
{
throw("error 2");
}
};
shared_ptr<MyClass> createMyClass()
{
return make_shared<MyClass>();
}
int main()
{
shared_ptr<MyClass> c = createMyClass();
return 0;
}
backtrace just points to this line:
29 return make_shared<MyClass>();
backtrace:
Program received signal SIGABRT, Aborted.
0x00007ffff722d5f7 in raise () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.17-106.el7_2.6.x86_64 libgcc-4.8.5-4.el7.x86_64 libstdc++-4.8.5-4.el7.x86_64
(gdb) bt
#0 0x00007ffff722d5f7 in raise () from /lib64/libc.so.6
#1 0x00007ffff722ece8 in abort () from /lib64/libc.so.6
#2 0x00007ffff7b329d5 in __gnu_cxx::__verbose_terminate_handler() () from /lib64/libstdc++.so.6
#3 0x00007ffff7b30946 in ?? () from /lib64/libstdc++.so.6
#4 0x00007ffff7b30973 in std::terminate() () from /lib64/libstdc++.so.6
#5 0x00007ffff7b30be9 in __cxa_rethrow () from /lib64/libstdc++.so.6
#6 0x000000000040121e in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<MyClass, std::allocator<MyClass>>(std::_Sp_make_shared_tag, MyClass*, std::allocator<MyClass> const&) (this=0x7fffffffe178, __a=...) at /usr/include/c++/4.8.2/bits/shared_ptr_base.h:509
#7 0x00000000004010ba in std::__shared_ptr<MyClass, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<std::allocator<MyClass>>(std::_Sp_make_shared_tag, std::allocator<MyClass> const&) (this=0x7fffffffe170, __tag=..., __a=...) at /usr/include/c++/4.8.2/bits/shared_ptr_base.h:957
#8 0x0000000000401052 in std::shared_ptr<MyClass>::shared_ptr<std::allocator<MyClass>>(std::_Sp_make_shared_tag, std::allocator<MyClass> const&) (this=0x7fffffffe170,
__tag=..., __a=...) at /usr/include/c++/4.8.2/bits/shared_ptr.h:316
#9 0x0000000000400f98 in std::allocate_shared<MyClass, std::allocator<MyClass>>(std::allocator<MyClass> const&) (__a=...) at /usr/include/c++/4.8.2/bits/shared_ptr.h:598
#10 0x0000000000400ee0 in std::make_shared<MyClass<> > () at /usr/include/c++/4.8.2/bits/shared_ptr.h:614
#11 0x0000000000400ce3 in createMyClass () at abrt.cpp:29
#12 0x0000000000400cfe in main () at abrt.cpp:34
(gdb) q
That information is lost by the time the core file is generated. The reason is that the shared_ptr constructor has to catch any exceptions from the object constructor in order to be able to deallocate the memory it allocated earlier (to prevent leaks induced by constructors that throw). By the time it catches the exception to deallocate the memory it no longer knows where in the constructor the exception was thrown.
Clang has the -fsanitize-blacklist compile switch to suppress warnings from the ThreadSanitizer. Unfortunately, I cannot get it to work.
Here is an example that I want to suppress:
WARNING: ThreadSanitizer: data race (pid=21502)
Read of size 8 at 0x7f0dcf5b31a8 by thread T6:
#0 tbb::interface6::internal::auto_partition_type_base<tbb::interface6::internal::auto_partition_type>::check_being_stolen(tbb::task&) /usr/include/tbb/partitioner.h:305 (exe+0x000000388b38)
#1 <null> <null>:0 (libtbb.so.2+0x0000000224d9)
Previous write of size 8 at 0x7f0dcf5b31a8 by thread T1:
#0 auto_partition_type_base /usr/include/tbb/partitioner.h:299 (exe+0x000000388d9a)
#1 <null> <null>:0 (libtbb.so.2+0x0000000224d9)
#2 GhostSearch::Ghost3Search::SearchTask::execute_impl() /home/phil/ghost/search/ghost3/ghost3_search_alg.cpp:1456 (exe+0x000000387a8a)
#3 <null> <null>:0 (libtbb.so.2+0x0000000224d9)
#4 GhostSearch::Ghost3Search::Ghost3SearchAlg::NullWindowSearch(int, MOVE, int, std::vector<MOVE, std::allocator<MOVE> >&) /home/phil/ghost/search/ghost3/ghost3_search_alg.cpp:1640 (exe+0x000000388310)
#5 GhostSearch::PureMTDSearchAlg::FullWindowSearch(GhostSearch::SearchWindow, GhostSearch::SearchWindow, MOVE, int, std::vector<MOVE, std::allocator<MOVE> >&) /home/phil/ghost/search/pure_mtd_search_alg.cpp:41 (exe+0x000000370e3f)
#6 GhostSearch::PureSearchAlgWrapper::RequestHandlerThread::EnterHandlerMainLoop() /home/phil/ghost/search/pure_search_alg_wrapper.cpp:124 (exe+0x000000372d1b)
#7 operator() /home/phil/ghost/search/pure_search_alg_wrapper.cpp:94 (exe+0x000000374683)
#8 execute_native_thread_routine /home/phil/tmp/gcc/src/gcc-4.8-20130725/libstdc++-v3/src/c++11/thread.cc:84 (libstdc++.so.6+0x0000000b26cf)
Thread T6 (tid=21518, running) created by thread T3 at:
#0 pthread_create ??:0 (exe+0x0000002378e1)
#1 <null> <null>:0 (libtbb.so.2+0x0000000198c0)
Thread T1 (tid=21513, running) created by main thread at:
#0 pthread_create ??:0 (exe+0x0000002378e1)
#1 __gthread_create /home/phil/tmp/gcc/src/gcc-build/x86_64-unknown-linux-gnu/libstdc++-v3/include/x86_64-unknown-linux-gnu/bits/gthr-default.h:662 (libstdc++.so.6+0x0000000b291e)
#2 GhostSearch::PureSearchAlgWrapper::StartRequestHandlerThread() /home/phil/ghost/search/pure_search_alg_wrapper.cpp:77 (exe+0x0000003715c3)
#3 GhostSearch::Search::ExecuteSearch(GhostSearch::SEARCH_SETTINGS const&) /home/phil/ghost/search.cpp:243 (exe+0x00000033063f)
#4 GhostSearch::Search::StartSearch(GhostSearch::SEARCH_SETTINGS const&, UserBoard const&, GhostInterfaces::UserInterface*) /home/phil/ghost/search.cpp:176 (exe+0x00000033037a)
#5 GhostInterfaces::UserInterface::StartSearch(GhostSearch::SEARCH_SETTINGS const&, UserBoard const&) /home/phil/ghost/interface.cpp:1072 (exe+0x0000002ea220)
#6 GhostInterfaces::UserInterface::MainLoop() /home/phil/ghost/interface.cpp:576 (exe+0x0000002e9464)
#7 GhostInterfaces::Command_Analyze::Execute(GhostInterfaces::UserInterfaceData&) /home/phil/ghost/commands.cpp:1005 (exe+0x00000028756c)
#8 GhostInterfaces::UserInterface::FinishNextCommand() /home/phil/ghost/interface.cpp:1161 (exe+0x0000002e9ed0)
#9 GhostInterfaces::UserInterface::MainLoop() /home/phil/ghost/interface.cpp:571 (exe+0x0000002e9447)
#10 main /home/phil/ghost/ghost.cpp:54 (exe+0x000000274efd)
SUMMARY: ThreadSanitizer: data race /usr/include/tbb/partitioner.h:305 tbb::interface6::internal::auto_partition_type_base<tbb::interface6::internal::auto_partition_type>::check_being_stolen(tbb::task&)
My tries for the suppression file so far (but it does not work):
# TBB
fun:tbb::*
src:/usr/include/tbb/partitioner.h
Do you know why it does not work?
(By the way, I would be happy to suppress all warnings from the TBB library.)
Finally, I got it working.
According to the documentation, each line must start with a valid "suppression_type" (race, thread, mutex, signal, deadlock, or called_from_lib).
In my example, the correct suppression_type is race.
Here is an example file called "sanitizer-thread-suppressions.txt", which suppresses two functions, which are known to contain data races:
race:Function1
race:MyNamespace::Function2
To test the suppress file, set the TSAN_OPTIONS environment variable and call the application (compiled with -fsanitize=thread):
$ TSAN_OPTIONS="suppressions=sanitizer-thread-suppressions.txt" ./myapp
If that works, you can apply the settings at compile time:
-fsanitize=thread -fsanitize-blacklist=sanitizer-thread-suppressions.txt
Using iOS 5.X
Cpp 11
Xcode
I am trying to identify what is causing this error.
It may be caused from destructor being called prior to a thread completing.
// default_delete
template <class _Tp>
struct _LIBCPP_VISIBLE default_delete
{
_LIBCPP_INLINE_VISIBILITY default_delete() _NOEXCEPT {}
template <class _Up>
_LIBCPP_INLINE_VISIBILITY default_delete(const default_delete<_Up>&,
typename enable_if<is_convertible<_Up*, _Tp*>::value>::type* = 0) _NOEXCEPT {}
_LIBCPP_INLINE_VISIBILITY void operator() (_Tp* __ptr) const _NOEXCEPT
{
static_assert(sizeof(_Tp) > 0, "default_delete can not delete incomplete type");
delete __ptr;
}
};
The stack trace is as follows:
stack trace
2013-01-28 13:50:33.704 CPP11AudioRecoClient[4633:5107] A task has completed. Map now contains 0 entries.
terminate called without an active exception(gdb) bt
#0 0x316e932c in __pthread_kill
#1 0x33de620e in pthread_kill
#2 0x33ddf29e in abort
#3 0x36c6cf6a in abort_message
#4 0x36c6a35a in default_terminate
#5 0x35237324 in _objc_terminate
#6 0x31997c96 in std::terminate
#7 0x319d3d18 in std::__1::thread::~thread ()
#8 0x00076cce in std::__1::default_delete<std::__1::thread>::operator() () at /Volumes/Xcode/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/c++/v1/memory:2512
#9 0x319d3d18 in std::__1::thread::~thread ()
#10 0x319d3d18 in std::__1::thread::~thread ()
#11 0x319c94cc in std::__1::__shared_weak_count::__release_shared ()
#12 0x00077606 in std::__1::shared_ptr<std::__1::thread>::~shared_ptr (this=0x2d64c4) at memory:4441
#13 0x0007676c in std::__1::shared_ptr<std::__1::thread>::~shared_ptr (this=0x2d64c4) at memory:4439
#14 0x00076038 in Microsoft::BingMobile::MusicReco::ClientSDK::Cpp11Thread::~Cpp11Thread (this=0x2d64c0) at /Users/v-mattkn/Desktop/CPP11AudioRecoClient/Cpp11ThreadFactory.cpp:125
#15 0x00075ffc in Microsoft::BingMobile::MusicReco::ClientSDK::Cpp11Thread::~Cpp11Thread (this=0x2d64c0) at /Users/v-mattkn/Desktop/CPP11AudioRecoClient/Cpp11ThreadFactory.cpp:123
#16 0x00075fdc in Microsoft::BingMobile::MusicReco::ClientSDK::Cpp11Thread::~Cpp11Thread (this=0x2d64c0) at /Users/v-mattkn/Desktop/CPP11AudioRecoClient/Cpp11ThreadFactory.cpp:123
#17 0x00077f68 in std::__1::default_delete<Microsoft::BingMobile::MusicReco::ClientSDK::Cpp11Thread>::operator() () at /Volumes/Xcode/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/c++/v1/memory:2512
#18 0x00077f68 in std::__1::__shared_ptr_pointer<Microsoft::BingMobile::MusicReco::ClientSDK::Cpp11Thread*, std::__1::default_delete<Microsoft::BingMobile::MusicReco::ClientSDK::Cpp11Thread>, std::__1::allocator<Microsoft::BingMobile::MusicReco::ClientSDK::Cpp11Thread> >::__on_zero_shared (this=0x2d5280) at memory:3668
#19 0x319c94cc in std::__1::__shared_weak_count::__release_shared ()
#20 0x0006a86e in std::__1::shared_ptr<Microsoft::BingMobile::MusicReco::ClientSDK::IThread>::~shared_ptr (this=0x2d6478) at memory:4441
#21 0x00069d94 in std::__1::shared_ptr<Microsoft::BingMobile::MusicReco::ClientSDK::IThread>::~shared_ptr (this=0x2d6478) at memory:4439
#22 0x00068d56 in Microsoft::BingMobile::MusicReco::ClientSDK::AsyncTask::~AsyncTask (this=0x2d6460) at /Users/v-mattkn/Desktop/CPP11AudioRecoClient/AsyncTask.cpp:34
#23 0x00068ce8 in Microsoft::BingMobile::MusicReco::ClientSDK::AsyncTask::~AsyncTask (this=0x2d6460) at /Users/v-mattkn/Desktop/CPP11AudioRecoClient/AsyncTask.cpp:33
#24 0x00068cc8 in Microsoft::BingMobile::MusicReco::ClientSDK::AsyncTask::~AsyncTask (this=0x2d6460) at /Users/v-mattkn/Desktop/CPP11AudioRecoClient/AsyncTask.cpp:33
#25 0x0006ad08 in std::__1::default_delete<Microsoft::BingMobile::MusicReco::ClientSDK::AsyncTask>::operator() () at /Volumes/Xcode/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/c++/v1/memory:2512
#26 0x0006ad08 in std::__1::__shared_ptr_pointer<Microsoft::BingMobile::MusicReco::ClientSDK::AsyncTask*, std::__1::default_delete<Microsoft::BingMobile::MusicReco::ClientSDK::AsyncTask>, std::__1::allocator<Microsoft::BingMobile::MusicReco::ClientSDK::AsyncTask> >::__on_zero_shared (this=0x2d6090) at memory:3668
#27 0x319c94cc in std::__1::__shared_weak_count::__release_shared ()
#28 0x00069fca in std::__1::shared_ptr<Microsoft::BingMobile::MusicReco::ClientSDK::ITaskObserver>::~shared_ptr (this=0x44fb4fc) at memory:4441
#29 0x00069e6c in std::__1::shared_ptr<Microsoft::BingMobile::MusicReco::ClientSDK::ITaskObserver>::~shared_ptr (this=0x44fb4fc) at memory:4439
#30 0x00099c22 in Microsoft::BingMobile::MusicReco::ClientSDK::RunnableTaskBase::notifyObserver (this=0x2d6350, observerWeak=<value temporarily unavailable, due to optimizations>, sharedReferenceToSelf=#0x44fb638) at /Users/v-mattkn/Desktop/CPP11AudioRecoClient/RunnableTaskBase.cpp:100
#31 0x00099930 in Microsoft::BingMobile::MusicReco::ClientSDK::RunnableTaskBase::notifyObservers (this=0x2d6350, sharedReferenceToSelf=<value temporarily unavailable, due to optimizations>) at /Users/v-mattkn/Desktop/CPP11AudioRecoClient/RunnableTaskBase.cpp:79
#32 0x000996e0 in Microsoft::BingMobile::MusicReco::ClientSDK::RunnableTaskBase::setStatus (this=0x2d6350, targetStatus=Microsoft::BingMobile::MusicReco::ClientSDK::Completed, sharedReferenceToSelf=#0x44fbd20) at /Users/v-mattkn/Desktop/CPP11AudioRecoClient/RunnableTaskBase.cpp:107
#33 0x00087168 in Microsoft::BingMobile::MusicReco::ClientSDK::PingWebServiceTask::runTaskChecked (this=0x2d6350, sharedReferenceToSelf=<value temporarily unavailable, due to optimizations>) at /Users/v-mattkn/Desktop/CPP11AudioRecoClient/PingWebServiceTask.cpp:120
#34 0x00099356 in Microsoft::BingMobile::MusicReco::ClientSDK::RunnableTaskBase::runTask (this=0x2d6350) at /Users/v-mattkn/Desktop/CPP11AudioRecoClient/RunnableTaskBase.cpp:60
#35 0x000991d2 in Microsoft::BingMobile::MusicReco::ClientSDK::RunnableTaskBase::run (this=0x2d6350, sharedReferenceToSelf=<value temporarily unavailable, due to optimizations>) at /Users/v-mattkn/Desktop/CPP11AudioRecoClient/RunnableTaskBase.cpp:48
#36 0x00099250 in non-virtual thunk to Microsoft::BingMobile::MusicReco::ClientSDK::RunnableTaskBase::run(std::__1::shared_ptr<Microsoft::BingMobile::MusicReco::ClientSDK::IRunnable>) () at memory:4023
#37 0x000759ca in Microsoft::BingMobile::MusicReco::ClientSDK::RunHookedRunnable::run (this=0x2d64a0, sharedReferenceToSelf=#0x44fcea8) at /Users/v-mattkn/Desktop/CPP11AudioRecoClient/Cpp11ThreadFactory.cpp:75
#38 0x0007736e in _ZNKSt3__110unique_ptrINS_5tupleIJMN9Microsoft10BingMobile9MusicReco9ClientSDK9IRunnableEFvNS_10shared_ptrIS6_EEES8_S8_EEENS_14default_deleteISB_EEEdeEv [inlined] () at /Volumes/Xcode/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/c++/v1/memory:309
#39 0x0007736e in _ZNSt3__114__thread_proxyINS_5tupleIJMN9Microsoft10BingMobile9MusicReco9ClientSDK9IRunnableEFvNS_10shared_ptrIS6_EEES8_S8_EEEEEPvSC_ (__vp=0x2d6230) at __functional_base:340
40 0x33da7734 in _pthread_start ()
That thread::~thread() in the backtrace suggests that the thread is still running when it's object gets destroyed. That's an error; you have to call join() or detach() on the thread object before destroying it.