aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Gao <jmgao@google.com>2021-05-20 19:15:15 -0700
committerJosh Gao <jmgao@google.com>2021-07-02 11:50:28 -0700
commit85407e35b880fcae9fd54639a527966963a51fe1 (patch)
treee0892d423302d50908ff0743620baab35da4959a
parent1ca6bba2815a04f6f222f2479dab80bae0fac659 (diff)
downloadadb-85407e35b880fcae9fd54639a527966963a51fe1.tar.gz
weak_ptr: add test, fix bug.
Add a test that uncovers a bug in weak_ptr where we don't call T's destructor in enable_weak_from_this<T>::schedule_deletion. Test: treehugger Change-Id: I31d755cb2a240fa092acfa4cf627e67f3c8cd23f
-rw-r--r--types.h4
-rw-r--r--types_test.cpp49
2 files changed, 50 insertions, 3 deletions
diff --git a/types.h b/types.h
index 620aa8eb..cd08ed8b 100644
--- a/types.h
+++ b/types.h
@@ -306,7 +306,7 @@ struct weak_ptr {
return *this;
}
- T* get() {
+ T* get() const {
check_main_thread();
return ptr_;
}
@@ -349,7 +349,7 @@ struct enable_weak_from_this {
weak_ptr<T> weak() { return weak_ptr<T>(static_cast<T*>(this)); }
void schedule_deletion() {
- fdevent_run_on_main_thread([this]() { delete this; });
+ fdevent_run_on_main_thread([this]() { delete static_cast<T*>(this); });
}
private:
diff --git a/types_test.cpp b/types_test.cpp
index 564ae0bd..086a35dd 100644
--- a/types_test.cpp
+++ b/types_test.cpp
@@ -14,10 +14,14 @@
* limitations under the License.
*/
+#include "types.h"
+
#include <gtest/gtest.h>
#include <memory>
-#include "types.h"
+#include <utility>
+
+#include "fdevent/fdevent_test.h"
static IOVector::block_type create_block(const std::string& string) {
return IOVector::block_type(string.begin(), string.end());
@@ -158,3 +162,46 @@ TEST(IOVector, trim_front) {
vec.trim_front();
ASSERT_EQ(1ULL, vec.size());
}
+
+class weak_ptr_test : public FdeventTest {};
+
+struct Destructor : public enable_weak_from_this<Destructor> {
+ Destructor(bool* destroyed) : destroyed_(destroyed) {}
+ ~Destructor() { *destroyed_ = true; }
+
+ bool* destroyed_;
+};
+
+TEST_F(weak_ptr_test, smoke) {
+ PrepareThread();
+
+ Destructor* destructor = nullptr;
+ bool destroyed = false;
+ std::optional<weak_ptr<Destructor>> p;
+
+ fdevent_run_on_main_thread([&p, &destructor, &destroyed]() {
+ destructor = new Destructor(&destroyed);
+ p = destructor->weak();
+ ASSERT_TRUE(p->get());
+
+ p->reset();
+ ASSERT_FALSE(p->get());
+
+ p->reset(destructor);
+ ASSERT_TRUE(p->get());
+ });
+ WaitForFdeventLoop();
+ ASSERT_TRUE(destructor);
+ ASSERT_FALSE(destroyed);
+
+ destructor->schedule_deletion();
+ WaitForFdeventLoop();
+
+ ASSERT_TRUE(destroyed);
+ fdevent_run_on_main_thread([&p]() {
+ ASSERT_FALSE(p->get());
+ p.reset();
+ });
+
+ TerminateThread();
+}