summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiago Marcos P. Santos <tmpsantos@gmail.com>2017-07-13 16:38:42 +0300
committerThiago Marcos P. Santos <tmpsantos@gmail.com>2017-07-13 17:39:25 +0300
commitb1caece80daeab2e05ac2e5c6b3550676022ed94 (patch)
treee0129cc6aff937e4b80f7d3725e3342648cb8ae3
parent6ca7b28e60afdc72d888b4c96fff509568ee3bd5 (diff)
downloadqtlocation-mapboxgl-upstream/tmpsantos-thread_local_leak.tar.gz
[core] Make sure ThreadLocal will not own the pointer it is managingupstream/tmpsantos-thread_local_leak
ThreadLocal should not own the pointer it is managing because the use case in Mapbox GL is to keep a pointer to a stack allocated object, like: ``` MyObject foo; threadLocal.set(&foo); ``` To keep consistency, it is required that we clear the managed object before ThreadLocal gets destroyed by setting it to `nullptr`.
-rw-r--r--platform/default/thread_local.cpp6
-rw-r--r--platform/qt/src/thread_local.cpp7
-rw-r--r--scripts/valgrind.sup8
-rw-r--r--test/util/thread_local.test.cpp19
4 files changed, 22 insertions, 18 deletions
diff --git a/platform/default/thread_local.cpp b/platform/default/thread_local.cpp
index b754a04b7d..6fdb1e6dc1 100644
--- a/platform/default/thread_local.cpp
+++ b/platform/default/thread_local.cpp
@@ -29,7 +29,11 @@ ThreadLocal<T>::ThreadLocal() : impl(std::make_unique<Impl>()) {
template <class T>
ThreadLocal<T>::~ThreadLocal() {
- delete get();
+ // ThreadLocal will not take ownership
+ // of the pointer it is managing. The pointer
+ // needs to be explicitly cleared before we
+ // destroy this object.
+ assert(!get());
if (pthread_key_delete(impl->key)) {
Log::Error(Event::General, "Failed to delete local storage key.");
diff --git a/platform/qt/src/thread_local.cpp b/platform/qt/src/thread_local.cpp
index e48a9d6e74..e835a680e2 100644
--- a/platform/qt/src/thread_local.cpp
+++ b/platform/qt/src/thread_local.cpp
@@ -4,6 +4,7 @@
#include <mbgl/map/backend_scope.hpp>
#include <array>
+#include <cassert>
#include <QThreadStorage>
@@ -23,7 +24,11 @@ ThreadLocal<T>::ThreadLocal() : impl(std::make_unique<Impl>()) {
template <class T>
ThreadLocal<T>::~ThreadLocal() {
- delete get();
+ // ThreadLocal will not take ownership
+ // of the pointer it is managing. The pointer
+ // needs to be explicitly cleared before we
+ // destroy this object.
+ assert(!get());
}
template <class T>
diff --git a/scripts/valgrind.sup b/scripts/valgrind.sup
index f659122dc1..09e2f6685c 100644
--- a/scripts/valgrind.sup
+++ b/scripts/valgrind.sup
@@ -76,11 +76,3 @@
fun:_ZN4mbgl4util10write_fileERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_
...
}
-{
- Qt5 ThreadStorage
- Memcheck:Leak
- match-leak-kinds: definite
- fun:_Znwm
- fun:_Z24qThreadStorage_localDataISt5arrayIPiLm1EEERT_R18QThreadStorageDataPS3_.isra.5
- ...
-}
diff --git a/test/util/thread_local.test.cpp b/test/util/thread_local.test.cpp
index 12a19ab59b..8016d49052 100644
--- a/test/util/thread_local.test.cpp
+++ b/test/util/thread_local.test.cpp
@@ -77,24 +77,27 @@ public:
data.set(data_);
}
+ ~TestThreadReclaim() {
+ data.set(nullptr);
+ }
+
private:
ThreadLocal<int> data;
};
} // namespace
-TEST(ThreadLocalStorage, AutoReclaim) {
+TEST(ThreadLocalStorage, ShouldNotTakeOwnership) {
RunLoop loop;
- auto data1 = new int;
- auto data2 = new int;
+ auto data1 = std::make_unique<int>(10);
+ auto data2 = std::make_unique<int>(20);
- auto thread1 = std::make_unique<Thread<TestThreadReclaim>>("Test", data1);
- auto thread2 = std::make_unique<Thread<TestThreadReclaim>>("Test", data2);
+ auto thread1 = std::make_unique<Thread<TestThreadReclaim>>("Test", data1.get());
+ auto thread2 = std::make_unique<Thread<TestThreadReclaim>>("Test", data2.get());
+ // Will crash if ThreadLocal destroys
+ // the pointer it is managing.
thread1.reset();
thread2.reset();
-
- // Should not leak, valgrind will
- // let us know.
}