Skip to content

Commit 64d10d1

Browse files
committed
Avoid deeply nested timestamps that can cause stack overflow.
1 parent c0e6ac1 commit 64d10d1

File tree

3 files changed

+31
-3
lines changed

3 files changed

+31
-3
lines changed

Firestore/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Unreleased
22
- [feature] Add support for disjunctions in queries (`OR` queries).
3+
- [fixed] Fixed stack overflow caused by deeply nested server timestamps.
34

45
# 10.6.0
56
- [fixed] Fix a potential high memory usage issue.

Firestore/core/src/model/server_timestamp_util.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ const char kServerTimestampSentinel[] = "server_timestamp";
3535
Message<google_firestore_v1_Value> EncodeServerTimestamp(
3636
const Timestamp& local_write_time,
3737
absl::optional<google_firestore_v1_Value> previous_value) {
38-
pb_size_t count = previous_value ? 3 : 2;
38+
absl::optional<google_firestore_v1_Value> actual_previous_value =
39+
previous_value.has_value() ? GetPreviousValue(*previous_value)
40+
: absl::nullopt;
41+
pb_size_t count = actual_previous_value ? 3 : 2;
3942

4043
Message<google_firestore_v1_Value> result;
4144
result->which_value_type = google_firestore_v1_Value_map_value_tag;
@@ -54,10 +57,10 @@ Message<google_firestore_v1_Value> EncodeServerTimestamp(
5457
field->value.timestamp_value.seconds = local_write_time.seconds();
5558
field->value.timestamp_value.nanos = local_write_time.nanoseconds();
5659

57-
if (previous_value) {
60+
if (actual_previous_value) {
5861
++field;
5962
field->key = nanopb::MakeBytesArray(kPreviousValueKey);
60-
field->value = *DeepClone(*previous_value).release();
63+
field->value = *DeepClone(*actual_previous_value).release();
6164
}
6265

6366
return result;

Firestore/core/test/unit/local/local_store_test.cc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "Firestore/core/test/unit/local/local_store_test.h"
1818

19+
#include <thread>
1920
#include <unordered_map>
2021
#include <utility>
2122
#include <vector>
@@ -34,10 +35,14 @@
3435
#include "Firestore/core/src/model/document.h"
3536
#include "Firestore/core/src/model/document_key.h"
3637
#include "Firestore/core/src/model/field_index.h"
38+
#include "Firestore/core/src/model/field_mask.h"
39+
#include "Firestore/core/src/model/field_path.h"
40+
#include "Firestore/core/src/model/field_transform.h"
3741
#include "Firestore/core/src/model/mutable_document.h"
3842
#include "Firestore/core/src/model/mutation.h"
3943
#include "Firestore/core/src/model/mutation_batch_result.h"
4044
#include "Firestore/core/src/model/patch_mutation.h"
45+
#include "Firestore/core/src/model/server_timestamp_util.h"
4146
#include "Firestore/core/src/model/set_mutation.h"
4247
#include "Firestore/core/src/model/transform_operation.h"
4348
#include "Firestore/core/src/remote/existence_filter.h"
@@ -92,6 +97,7 @@ using testutil::Key;
9297
using testutil::Map;
9398
using testutil::OverlayTypeMap;
9499
using testutil::Query;
100+
using testutil::ServerTimestamp;
95101
using testutil::UnknownDoc;
96102
using testutil::UpdateRemoteEvent;
97103
using testutil::UpdateRemoteEventWithLimboTargets;
@@ -1684,6 +1690,24 @@ TEST_P(LocalStoreTest, PatchMutationLeadsToPatchOverlay) {
16841690
OverlayTypeMap({{Key("foo/baz"), model::Mutation::Type::Patch}}));
16851691
}
16861692

1693+
TEST_P(LocalStoreTest, DeeplyNestedTimestampDoesNotCauseStackOverflow) {
1694+
Timestamp timestamp = Timestamp::Now();
1695+
Message<_google_firestore_v1_Value> initialServerTimestamp =
1696+
model::EncodeServerTimestamp(timestamp, absl::nullopt);
1697+
model::FieldPath path = model::FieldPath::FromDotSeparatedString("timestamp");
1698+
auto makeDeeplyNestedTimestamp = [&]() {
1699+
for (int i = 0; i < 1000; ++i) {
1700+
WriteMutation(testutil::MergeMutation(
1701+
"foo/bar",
1702+
Map("timestamp",
1703+
model::EncodeServerTimestamp(timestamp, *initialServerTimestamp)),
1704+
{path}, {ServerTimestamp("timestamp")}));
1705+
}
1706+
};
1707+
std::thread t(makeDeeplyNestedTimestamp);
1708+
EXPECT_NO_FATAL_FAILURE(t.join());
1709+
}
1710+
16871711
} // namespace local
16881712
} // namespace firestore
16891713
} // namespace firebase

0 commit comments

Comments
 (0)