chrono::current_zone() fails if /etc/localtime is a symlink to a zone
with three components, like "America/Indiana/Indianapolis", because we
only try to find "Indianapolis" and "Indiana/Indianapolis" but neither
of those exists.
We need to try up to three components to handle all valid cases, such as
"UTC", "America/Indianapolis", and "America/Indiana/Indianapolis".
Since two components is the most common case, we could consider trying
last[-2]/last[-1] first, then if that doesn't match trying only the last
component and the last three components, but this patch doesn't do that.
libstdc++-v3/ChangeLog:
PR libstdc++/122567
* src/c++20/tzdb.cc (tzdb::current_zone): Loop over trailing
components of /etc/localtime path for up to three components.
---
Tested x86_64-linux.
There's no new testcase for this because it requires root access to
change /etc/localtime. I've verified it locally.
libstdc++-v3/src/c++20/tzdb.cc | 26 ++++++++++++++++++--------
1 file changed, 18 insertions(+), 8 deletions(-)
diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc
index 53441880ae6e..44ba3ea890f2 100644
--- a/libstdc++-v3/src/c++20/tzdb.cc
+++ b/libstdc++-v3/src/c++20/tzdb.cc
@@ -1896,14 +1896,24 @@ namespace std::chrono
auto first = path.begin(), last = path.end();
if (std::distance(first, last) > 2)
{
- --last;
- string name = last->string();
- if (auto tz = do_locate_zone(this->zones, this->links, name))
- return tz;
- --last;
- name = last->string() + '/' + name;
- if (auto tz = do_locate_zone(this->zones, this->links, name))
- return tz;
+ string name, part;
+ // Check trailing components of the path against known zone names.
+ // Valid zones can have one, two, or three components, e.g.
+ // "UTC", "Europe/London", "America/Indiana/Indianapolis"
+ for (int i = 0; i < 3 && last != first; ++i)
+ {
+ --last;
+ part = last->string();
+ if (name.empty())
+ name = std::move(part);
+ else
+ {
+ part += '/';
+ name = std::move(part) + std::move(name);
+ }
+ if (auto tz = do_locate_zone(this->zones, this->links, name))
+ return tz;
+ }
}
}
#endif
--
2.52.0