On Fri, 9 Jan 2026 at 18:32, Jonathan Wakely <[email protected]> wrote:
>
> On Fri, 9 Jan 2026 at 18:13, Tomasz Kaminski <[email protected]> wrote:
> >
> >
> >
> > On Fri, Jan 9, 2026 at 6:58 PM Tomasz Kaminski <[email protected]> wrote:
> >>
> >>
> >>
> >> On Fri, Jan 9, 2026 at 6:37 PM Jonathan Wakely <[email protected]> wrote:
> >>>
> >>> 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)
> >>
> >> Is there any real benefit of hardcoding 3 components here, instead of using
> >> while (last != first), so we would handle any longer names?
>
> It will slow down the unlikely case, where the symlink refers to a
> zone that we don't recognize as a valid name, but that's probably not
> a major concern.
>
> The docs say that most zones should have a name of the form
> AREA/LOCATION so more than two components is already rare:
> https://data.iana.org/time-zones/theory.html#naming
> Four or more components isn't actually forbidden, but it seems very unlikely.

I suppose it's possible that somebody could use an arbitrary number of
filename components in a custom version of the database, replacing or
overriding tzdata.zi with their own file and then setting
/etc/localtime to refer to one of their own zones.


>
> >
> > If we have more than 4 components in future, then such a new timezone 
> > database
> > can be downloaded by the older version of the library. And we will checking 
> > only more
> > than tree components, only if the current zone is not something that we 
> > could match.
> >>
> >>
> >>>
> >>> +             {
> >>> +               --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
> >>>

Reply via email to