Commit 0b308a0e authored by Daniel Cheng's avatar Daniel Cheng Committed by Commit Bot

Prevent UB if a WeakPtr to an already-destroyed object is dereferenced.

If a WeakPtr references an already-destroyed object, operator-> and
operator* end up simply dereferencing nullptr. However, dereferencing
nullptr is undefined behavior and can be optimized in surprising ways
by compilers. To prevent this from happening, add a defence of last
resort and CHECK that the WeakPtr is still valid.

Bug: 817982
Change-Id: Ib3a025c18fbd9d5db88770fced2063135086847b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2463857
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarWez <wez@chromium.org>
Reviewed-by: default avatarJan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#816701}
parent ff8d40ea
...@@ -248,11 +248,11 @@ class WeakPtr : public internal::WeakPtrBase { ...@@ -248,11 +248,11 @@ class WeakPtr : public internal::WeakPtrBase {
} }
T& operator*() const { T& operator*() const {
DCHECK(get() != nullptr); CHECK(ref_.IsValid());
return *get(); return *get();
} }
T* operator->() const { T* operator->() const {
DCHECK(get() != nullptr); CHECK(ref_.IsValid());
return get(); return get();
} }
......
...@@ -798,4 +798,26 @@ TEST(WeakPtrDeathTest, NonOwnerThreadReferencesObjectAfterDeletion) { ...@@ -798,4 +798,26 @@ TEST(WeakPtrDeathTest, NonOwnerThreadReferencesObjectAfterDeletion) {
ASSERT_DCHECK_DEATH(arrow.target.get()); ASSERT_DCHECK_DEATH(arrow.target.get());
} }
TEST(WeakPtrDeathTest, ArrowOperatorChecksOnBadDereference) {
// The default style "fast" does not support multi-threaded tests
// (introduces deadlock on Linux).
::testing::FLAGS_gtest_death_test_style = "threadsafe";
auto target = std::make_unique<Target>();
WeakPtr<Target> weak = target->AsWeakPtr();
target.reset();
EXPECT_CHECK_DEATH(weak->AsWeakPtr());
}
TEST(WeakPtrDeathTest, StarOperatorChecksOnBadDereference) {
// The default style "fast" does not support multi-threaded tests
// (introduces deadlock on Linux).
::testing::FLAGS_gtest_death_test_style = "threadsafe";
auto target = std::make_unique<Target>();
WeakPtr<Target> weak = target->AsWeakPtr();
target.reset();
EXPECT_CHECK_DEATH((*weak).AsWeakPtr());
}
} // namespace base } // namespace base
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment