Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/time_zone_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,13 @@ inline civil_second YearShift(const civil_second& cs, year_t shift) {
bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
const std::string& abbr,
std::uint_least8_t* index) {
// Keep synthesized types within a day of UTC, matching the bound the reader
// enforces on file-supplied types (see Load). ParsePosixSpec() accepts an
// std/dst offset field up to 24:59:59, so a future spec can otherwise reach
// here with an out-of-range offset the TZif path would have rejected.
if (utc_offset <= -kSecsPerDay || utc_offset >= kSecsPerDay) {
return false;
}
std::size_t type_index = 0;
std::size_t abbr_index = abbreviations_.size();
for (; type_index != transition_types_.size(); ++type_index) {
Expand Down
21 changes: 21 additions & 0 deletions src/time_zone_lookup_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,14 @@ std::unique_ptr<ZoneInfoSource> ExtendedTestFactory(
return std::unique_ptr<ZoneInfoSource>(new StringZoneInfoSource(
MakeExtendedTzif(0, -5 * 3600, "EST", "EST5EDT,M3.2.0,M11.1.0")));
}
if (name == "test:ExtendedOversizeOffset") {
// The DST offset field 24:30:00 (88200s) is more than a day from UTC.
// The reader rejects such offsets in file-supplied types, so the type
// synthesized from the POSIX footer must be rejected too.
return std::unique_ptr<ZoneInfoSource>(new StringZoneInfoSource(
MakeExtendedTzif(0, -5 * 3600, std::string{"EST", 4},
"EST5EDT24:30:00,M3.2.0,M11.1.0")));
}
return fallback(name);
}

Expand Down Expand Up @@ -1122,6 +1130,19 @@ TEST(TimeZoneEdgeCase, ExtendedOverlappingRules) {
cctz_extension::zone_info_source_factory = prev_factory;
}

// A POSIX footer whose std/dst offset field is a day or more from UTC yields
// a transition type the TZif reader would reject; loading must fail rather
// than build a zone with an out-of-range offset.
TEST(TimeZoneEdgeCase, ExtendedOversizeOffset) {
auto prev_factory = cctz_extension::zone_info_source_factory;
cctz_extension::zone_info_source_factory = ExtendedTestFactory;

time_zone tz;
EXPECT_FALSE(load_time_zone("test:ExtendedOversizeOffset", &tz));

cctz_extension::zone_info_source_factory = prev_factory;
}

// Looking up the maximum time in an extended zone must fold back through the
// 400-year cycle without overflowing when BreakTime() computes the shift.
TEST(TimeZoneEdgeCase, ExtendedFarFuture) {
Expand Down