Skip to content

Commit 493e97b

Browse files
amabluea-maurice
amablue
authored andcommitted
Fixed some potential race conditions in DatabaseReference's various
constructors. Because the database keeps its own bookkeeping regarding the memory addresses of the QueryInternals and DatabaseReferenceInternals, if they are created and added to the Database's registry in two steps, a situation could arise where the database shuts down with either stale or incomplete internal bookkeeping. To solve this, any place that we update Database's bookkeeping we need do so atomically. PiperOrigin-RevId: 265136296
1 parent 0793d9e commit 493e97b

File tree

8 files changed

+31
-3
lines changed

8 files changed

+31
-3
lines changed

database/src/android/database_android.cc

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ namespace firebase {
3434
namespace database {
3535
namespace internal {
3636

37+
Mutex g_database_reference_constructor_mutex; // NOLINT
38+
3739
const char kApiIdentifier[] = "Database";
3840

3941
// clang-format off

database/src/android/database_android.h

+3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ class ReferenceCountedFutureImpl;
3636
namespace database {
3737
namespace internal {
3838

39+
// For constructing, copying or moving DatabaseReferences atomically.
40+
extern Mutex g_database_reference_constructor_mutex;
41+
3942
// Used for registering global callbacks. See
4043
// firebase::util::RegisterCallbackOnTask for context.
4144
extern const char kApiIdentifier[];

database/src/common/database.cc

+5-2
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,11 @@ void Database::DeleteInternal() {
133133
app_notifier->UnregisterObject(this);
134134
}
135135

136-
// Force cleanup to happen first.
137-
internal_->cleanup().CleanupAll();
136+
{
137+
MutexLock db_ref_lock(internal::g_database_reference_constructor_mutex);
138+
// Force cleanup to happen first.
139+
internal_->cleanup().CleanupAll();
140+
}
138141
delete internal_;
139142
internal_ = nullptr;
140143
// If a Database is explicitly deleted, remove it from our cache.

database/src/common/database_reference.cc

+11-1
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,15 @@ void DatabaseReference::SwitchCleanupRegistrationBackToQuery() {
7777

7878
DatabaseReference::DatabaseReference(DatabaseReferenceInternal* internal)
7979
: Query(internal), internal_(internal) {
80+
MutexLock lock(internal::g_database_reference_constructor_mutex);
81+
8082
SwitchCleanupRegistrationToDatabaseReference();
8183
}
8284

8385
DatabaseReference::DatabaseReference(const DatabaseReference& reference)
8486
: Query(), internal_(nullptr) {
87+
MutexLock lock(internal::g_database_reference_constructor_mutex);
88+
8589
internal_ = reference.internal_
8690
? new DatabaseReferenceInternal(*reference.internal_)
8791
: nullptr;
@@ -91,6 +95,8 @@ DatabaseReference::DatabaseReference(const DatabaseReference& reference)
9195

9296
DatabaseReference& DatabaseReference::operator=(
9397
const DatabaseReference& reference) {
98+
MutexLock lock(internal::g_database_reference_constructor_mutex);
99+
94100
internal_ = reference.internal_
95101
? new DatabaseReferenceInternal(*reference.internal_)
96102
: nullptr;
@@ -103,12 +109,16 @@ DatabaseReference& DatabaseReference::operator=(
103109
#if defined(FIREBASE_USE_MOVE_OPERATORS) || defined(DOXYGEN)
104110
DatabaseReference::DatabaseReference(DatabaseReference&& reference)
105111
: Query(), internal_(reference.internal_) {
106-
Query::operator=(std::move(reference));
112+
MutexLock lock(internal::g_database_reference_constructor_mutex);
113+
107114
reference.internal_ = nullptr;
115+
Query::operator=(std::move(reference));
108116
SwitchCleanupRegistrationToDatabaseReference();
109117
}
110118

111119
DatabaseReference& DatabaseReference::operator=(DatabaseReference&& reference) {
120+
MutexLock lock(internal::g_database_reference_constructor_mutex);
121+
112122
internal_ = reference.internal_;
113123
reference.internal_ = nullptr;
114124
Query::operator=(std::move(reference));

database/src/desktop/database_desktop.cc

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ using callback::NewCallback;
3939
namespace database {
4040
namespace internal {
4141

42+
Mutex g_database_reference_constructor_mutex; // NOLINT
43+
4244
SingleValueListener::SingleValueListener(DatabaseInternal* database,
4345
ReferenceCountedFutureImpl* future,
4446
SafeFutureHandle<DataSnapshot> handle)

database/src/desktop/database_desktop.h

+3
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ namespace firebase {
4040
namespace database {
4141
namespace internal {
4242

43+
// For constructing, copying or moving DatabaseReferences atomically.
44+
extern Mutex g_database_reference_constructor_mutex;
45+
4346
typedef int64_t WriteId;
4447

4548
class SingleValueListener : public ValueListener {

database/src/ios/database_ios.h

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ class ReferenceCountedFutureImpl;
3737
namespace database {
3838
namespace internal {
3939

40+
// For constructing, copying or moving DatabaseReferences atomically.
41+
extern Mutex g_database_reference_constructor_mutex;
42+
4043
// This defines the class FIRDatabasePointer, which is a C++-compatible wrapper
4144
// around the FIRDatabase Obj-C class.
4245
OBJ_C_PTR_WRAPPER(FIRDatabase);

database/src/ios/database_ios.mm

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
namespace database {
2727
namespace internal {
2828

29+
Mutex g_database_reference_constructor_mutex; // NOLINT
30+
2931
DatabaseInternal::DatabaseInternal(App* app)
3032
: app_(app), log_level_(kLogLevelInfo) {
3133
@try {

0 commit comments

Comments
 (0)