Skip to content

Commit a959f27

Browse files
Fix mishandling on JSON serialization of Timestamp with invalid negative and too-large nanos value.
PiperOrigin-RevId: 791784040
1 parent 5e80ff1 commit a959f27

File tree

2 files changed

+44
-36
lines changed

2 files changed

+44
-36
lines changed

‎conformance/failure_list_cpp.txt‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ Recommended.*.FieldMaskNumbersDontRoundTrip.JsonOutput
3333
Recommended.*.FieldMaskPathsDontRoundTrip.JsonOutput # Should have failed to serialize, but didn't.
3434
Recommended.*.FieldMaskTooManyUnderscore.JsonOutput # Should have failed to serialize, but didn't.
3535
Recommended.*.JsonInput.FieldMaskInvalidCharacter # Should have failed to parse, but didn't.
36-
Required.*.TimestampProtoNanoTooLarge.JsonOutput # Should have failed to serialize, but didn't.
37-
Required.*.TimestampProtoNegativeNanos.JsonOutput # Should have failed to serialize, but didn't.
3836
Required.*.JsonInput.SingleValueForRepeatedFieldInt32 # Should have failed to parse, but didn't.
3937
Required.*.JsonInput.SingleValueForRepeatedFieldMessage # Should have failed to parse, but didn't.
38+

‎src/google/protobuf/json/internal/unparser.cc‎

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -576,34 +576,41 @@ template <typename Traits>
576576
absl::Status WriteTimestamp(JsonWriter& writer, const Msg<Traits>& msg,
577577
const Desc<Traits>& desc) {
578578
auto secs_field = Traits::MustHaveField(desc, 1);
579-
auto secs = Traits::GetSize(secs_field, msg) > 0
580-
? Traits::GetInt64(secs_field, msg)
581-
: 0;
582-
RETURN_IF_ERROR(secs.status());
579+
auto status_or_secs = Traits::GetSize(secs_field, msg) > 0
580+
? Traits::GetInt64(secs_field, msg)
581+
: 0;
582+
RETURN_IF_ERROR(status_or_secs.status());
583+
int64_t secs = *status_or_secs;
583584

584-
if (*secs < -62135596800) {
585+
if (secs < -62135596800) {
585586
return absl::InvalidArgumentError(
586587
"minimum acceptable time value is 0001-01-01T00:00:00Z");
587-
} else if (*secs > 253402300799) {
588+
} else if (secs > 253402300799) {
588589
return absl::InvalidArgumentError(
589590
"maximum acceptable time value is 9999-12-31T23:59:59Z");
590591
}
591592

592593
// Ensure seconds is positive.
593-
*secs += 62135596800;
594+
secs += 62135596800;
594595

595596
auto nanos_field = Traits::MustHaveField(desc, 2);
596-
auto nanos = Traits::GetSize(nanos_field, msg) > 0
597-
? Traits::GetInt32(nanos_field, msg)
598-
: 0;
599-
RETURN_IF_ERROR(nanos.status());
597+
auto status_or_nanos = Traits::GetSize(nanos_field, msg) > 0
598+
? Traits::GetInt32(nanos_field, msg)
599+
: 0;
600+
RETURN_IF_ERROR(status_or_nanos.status());
601+
int32_t nanos = *status_or_nanos;
602+
603+
if (nanos < 0 || nanos > 999999999) {
604+
return absl::InvalidArgumentError(
605+
"nanos must be in range [0, +999,999,999]");
606+
}
600607

601608
// Julian Day -> Y/M/D, Algorithm from:
602609
// Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for
603610
// Processing Calendar Dates," Communications of the Association of
604611
// Computing Machines, vol. 11 (1968), p. 657.
605612
int32_t L, N, I, J, K;
606-
L = static_cast<int32_t>(*secs / 86400) - 719162 + 68569 + 2440588;
613+
L = static_cast<int32_t>(secs / 86400) - 719162 + 68569 + 2440588;
607614
N = 4 * L / 146097;
608615
L = L - (146097 * N + 3) / 4;
609616
I = 4000 * (L + 1) / 1461001;
@@ -614,18 +621,18 @@ absl::Status WriteTimestamp(JsonWriter& writer, const Msg<Traits>& msg,
614621
J = J + 2 - 12 * L;
615622
I = 100 * (N - 49) + I + L;
616623

617-
int32_t sec = *secs % 60;
618-
int32_t min = (*secs / 60) % 60;
619-
int32_t hour = (*secs / 3600) % 24;
624+
int32_t sec = secs % 60;
625+
int32_t min = (secs / 60) % 60;
626+
int32_t hour = (secs / 3600) % 24;
620627

621-
if (*nanos == 0) {
628+
if (nanos == 0) {
622629
writer.Write(absl::StrFormat(R"("%04d-%02d-%02dT%02d:%02d:%02dZ")", I, J, K,
623630
hour, min, sec));
624631
return absl::OkStatus();
625632
}
626633

627634
size_t digits = 9;
628-
uint32_t frac_seconds = std::abs(*nanos);
635+
uint32_t frac_seconds = std::abs(nanos);
629636
while (frac_seconds % 1000 == 0) {
630637
frac_seconds /= 1000;
631638
digits -= 3;
@@ -640,45 +647,47 @@ template <typename Traits>
640647
absl::Status WriteDuration(JsonWriter& writer, const Msg<Traits>& msg,
641648
const Desc<Traits>& desc) {
642649
constexpr int64_t kMaxSeconds = int64_t{3652500} * 86400;
643-
constexpr int64_t kMaxNanos = 999999999;
650+
constexpr int32_t kMaxNanos = 999999999;
644651

645652
auto secs_field = Traits::MustHaveField(desc, 1);
646-
auto secs = Traits::GetSize(secs_field, msg) > 0
647-
? Traits::GetInt64(secs_field, msg)
648-
: 0;
649-
RETURN_IF_ERROR(secs.status());
653+
auto status_or_secs = Traits::GetSize(secs_field, msg) > 0
654+
? Traits::GetInt64(secs_field, msg)
655+
: 0;
656+
RETURN_IF_ERROR(status_or_secs.status());
657+
int64_t secs = *status_or_secs;
650658

651-
if (*secs > kMaxSeconds || *secs < -kMaxSeconds) {
659+
if (secs > kMaxSeconds || secs < -kMaxSeconds) {
652660
return absl::InvalidArgumentError("duration out of range");
653661
}
654662

655663
auto nanos_field = Traits::MustHaveField(desc, 2);
656-
auto nanos = Traits::GetSize(nanos_field, msg) > 0
657-
? Traits::GetInt32(nanos_field, msg)
658-
: 0;
659-
RETURN_IF_ERROR(nanos.status());
664+
auto status_or_nanos = Traits::GetSize(nanos_field, msg) > 0
665+
? Traits::GetInt32(nanos_field, msg)
666+
: 0;
667+
RETURN_IF_ERROR(status_or_nanos.status());
668+
int32_t nanos = *status_or_nanos;
660669

661-
if (*nanos > kMaxNanos || *nanos < -kMaxNanos) {
670+
if (nanos > kMaxNanos || nanos < -kMaxNanos) {
662671
return absl::InvalidArgumentError("duration out of range");
663672
}
664-
if ((*secs != 0) && (*nanos != 0) && ((*secs < 0) != (*nanos < 0))) {
673+
if ((secs != 0) && (nanos != 0) && ((secs < 0) != (nanos < 0))) {
665674
return absl::InvalidArgumentError("nanos and seconds signs do not match");
666675
}
667676

668-
if (*nanos == 0) {
669-
writer.Write(absl::StrFormat(R"("%ds")", *secs));
677+
if (nanos == 0) {
678+
writer.Write(absl::StrFormat(R"("%ds")", secs));
670679
return absl::OkStatus();
671680
}
672681

673682
size_t digits = 9;
674-
uint32_t frac_seconds = std::abs(*nanos);
683+
uint32_t frac_seconds = std::abs(nanos);
675684
while (frac_seconds % 1000 == 0) {
676685
frac_seconds /= 1000;
677686
digits -= 3;
678687
}
679688

680-
absl::string_view sign = ((*secs < 0) || (*nanos < 0)) ? "-" : "";
681-
writer.Write(absl::StrFormat(R"("%s%d.%.*ds")", sign, std::abs(*secs), digits,
689+
absl::string_view sign = ((secs < 0) || (nanos < 0)) ? "-" : "";
690+
writer.Write(absl::StrFormat(R"("%s%d.%.*ds")", sign, std::abs(secs), digits,
682691
frac_seconds));
683692
return absl::OkStatus();
684693
}

0 commit comments

Comments
 (0)