diff --git a/libutils/Android.bp b/libutils/Android.bp index 2b98fef98..2b7412b4c 100644 --- a/libutils/Android.bp +++ b/libutils/Android.bp @@ -45,6 +45,7 @@ cc_library { "StopWatch.cpp", "String8.cpp", "String16.cpp", + "StrongPointer.cpp", "SystemClock.cpp", "Threads.cpp", "Timers.cpp", diff --git a/libutils/StrongPointer.cpp b/libutils/StrongPointer.cpp new file mode 100644 index 000000000..ba52502ec --- /dev/null +++ b/libutils/StrongPointer.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "sp" + +#include + +namespace android { + +void sp_report_race() { LOG_ALWAYS_FATAL("sp<> assignment detected data race"); } +} 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::~sp() { template sp& sp::operator =(const sp& other) { + // Force m_ptr to be read twice, to heuristically check for data races. + T* oldPtr(*const_cast(&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(&m_ptr)) sp_report_race(); m_ptr = otherPtr; return *this; } template sp& sp::operator =(sp&& other) { - if (m_ptr) - m_ptr->decStrong(this); + T* oldPtr(*const_cast(&m_ptr)); + if (oldPtr) oldPtr->decStrong(this); + if (oldPtr != *const_cast(&m_ptr)) sp_report_race(); m_ptr = other.m_ptr; other.m_ptr = nullptr; return *this; @@ -181,29 +186,30 @@ sp& sp::operator =(sp&& other) { template sp& sp::operator =(T* other) { - if (other) - other->incStrong(this); - if (m_ptr) - m_ptr->decStrong(this); + T* oldPtr(*const_cast(&m_ptr)); + if (other) other->incStrong(this); + if (oldPtr) oldPtr->decStrong(this); + if (oldPtr != *const_cast(&m_ptr)) sp_report_race(); m_ptr = other; return *this; } template template sp& sp::operator =(const sp& other) { + T* oldPtr(*const_cast(&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(&m_ptr)) sp_report_race(); m_ptr = otherPtr; return *this; } template template sp& sp::operator =(sp&& other) { - if (m_ptr) - m_ptr->decStrong(this); + T* oldPtr(*const_cast(&m_ptr)); + if (m_ptr) m_ptr->decStrong(this); + if (oldPtr != *const_cast(&m_ptr)) sp_report_race(); m_ptr = other.m_ptr; other.m_ptr = nullptr; return *this; @@ -211,10 +217,10 @@ sp& sp::operator =(sp&& other) { template template sp& sp::operator =(U* other) { - if (other) - (static_cast(other))->incStrong(this); - if (m_ptr) - m_ptr->decStrong(this); + T* oldPtr(*const_cast(&m_ptr)); + if (other) (static_cast(other))->incStrong(this); + if (oldPtr) oldPtr->decStrong(this); + if (oldPtr != *const_cast(&m_ptr)) sp_report_race(); m_ptr = other; return *this; }