diff options
author | Hans Boehm <hboehm@google.com> | 2017-03-15 11:01:03 -0700 |
---|---|---|
committer | Hans Boehm <hboehm@google.com> | 2017-03-17 17:47:28 -0700 |
commit | 7f0b2601d37e758e007f53f776889ae362fc246e (patch) | |
tree | f06ee23f679d817c0f6767d5c791b009c9d254ff /libutils/include | |
parent | 1d1de8e282106910bcb67c9750a2df6e830b39be (diff) | |
download | system_core-7f0b2601d37e758e007f53f776889ae362fc246e.tar.gz system_core-7f0b2601d37e758e007f53f776889ae362fc246e.tar.bz2 system_core-7f0b2601d37e758e007f53f776889ae362fc246e.zip |
Add heuristic data race detection to sp<>
Force assignment to read the old pointer value twice, and check
that it didn't change in the interim. Previous experience with
Skia suggests that this has a high probability of correctly detecting
a data race when it occurs, instead of potentially letting the
count associated with the old pointer value get decremented twice,
and corrupting the heap.
This does increase the size of sp assignments, which seem to
commonly get inlined. For the general case, we add a third
comparison and function call.
Some code reformatting to make this consistent with modern conventions
and pass automated checks.
Test: Booted aosp build. Ran libutils tests. Looked at generated code.
Bug: 31227650
Change-Id: Id93a05c6bf10f01ee15ff1bb409611f2058f988f
Diffstat (limited to 'libutils/include')
-rw-r--r-- | libutils/include/utils/StrongPointer.h | 46 |
1 files changed, 26 insertions, 20 deletions
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h index 294e6b6f4..c2f772222 100644 --- a/libutils/include/utils/StrongPointer.h +++ b/libutils/include/utils/StrongPointer.h @@ -108,6 +108,9 @@ private: T* m_ptr; }; +// For code size reasons, we do not want this inlined or templated. +void sp_report_race(); + #undef COMPARE // --------------------------------------------------------------------------- @@ -161,19 +164,21 @@ sp<T>::~sp() { template<typename T> sp<T>& sp<T>::operator =(const sp<T>& other) { + // Force m_ptr to be read twice, to heuristically check for data races. + T* oldPtr(*const_cast<T* volatile*>(&m_ptr)); T* otherPtr(other.m_ptr); - if (otherPtr) - otherPtr->incStrong(this); - if (m_ptr) - m_ptr->decStrong(this); + if (otherPtr) otherPtr->incStrong(this); + if (oldPtr) oldPtr->decStrong(this); + if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race(); m_ptr = otherPtr; return *this; } template<typename T> sp<T>& sp<T>::operator =(sp<T>&& other) { - if (m_ptr) - m_ptr->decStrong(this); + T* oldPtr(*const_cast<T* volatile*>(&m_ptr)); + if (oldPtr) oldPtr->decStrong(this); + if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race(); m_ptr = other.m_ptr; other.m_ptr = nullptr; return *this; @@ -181,29 +186,30 @@ sp<T>& sp<T>::operator =(sp<T>&& other) { template<typename T> sp<T>& sp<T>::operator =(T* other) { - if (other) - other->incStrong(this); - if (m_ptr) - m_ptr->decStrong(this); + T* oldPtr(*const_cast<T* volatile*>(&m_ptr)); + if (other) other->incStrong(this); + if (oldPtr) oldPtr->decStrong(this); + if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race(); m_ptr = other; return *this; } template<typename T> template<typename U> sp<T>& sp<T>::operator =(const sp<U>& other) { + T* oldPtr(*const_cast<T* volatile*>(&m_ptr)); T* otherPtr(other.m_ptr); - if (otherPtr) - otherPtr->incStrong(this); - if (m_ptr) - m_ptr->decStrong(this); + if (otherPtr) otherPtr->incStrong(this); + if (oldPtr) oldPtr->decStrong(this); + if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race(); m_ptr = otherPtr; return *this; } template<typename T> template<typename U> sp<T>& sp<T>::operator =(sp<U>&& other) { - if (m_ptr) - m_ptr->decStrong(this); + T* oldPtr(*const_cast<T* volatile*>(&m_ptr)); + if (m_ptr) m_ptr->decStrong(this); + if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race(); m_ptr = other.m_ptr; other.m_ptr = nullptr; return *this; @@ -211,10 +217,10 @@ sp<T>& sp<T>::operator =(sp<U>&& other) { template<typename T> template<typename U> sp<T>& sp<T>::operator =(U* other) { - if (other) - (static_cast<T*>(other))->incStrong(this); - if (m_ptr) - m_ptr->decStrong(this); + T* oldPtr(*const_cast<T* volatile*>(&m_ptr)); + if (other) (static_cast<T*>(other))->incStrong(this); + if (oldPtr) oldPtr->decStrong(this); + if (oldPtr != *const_cast<T* volatile*>(&m_ptr)) sp_report_race(); m_ptr = other; return *this; } |