https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127815
liu zhenyu <lzy20000419 at outlook dot com> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |lzy20000419 at outlook dot com
--- Comment #6 from liu zhenyu <lzy20000419 at outlook dot com> ---
r17-5617 fixes the lower bound, but the upper bound has the mirror problem and
it is unchanged on trunk. For an instant at or after the last period's until()
(sys_days(year::max()/December/31)), _M_get_sys_info clamps with `tp =
(--i)->until();` (libstdc++-v3/src/c++20/tzdb.cc:1082 on trunk 20261105), which
is the exclusive end of that period. If the last period follows a rule set, the
rule expansion stops at info.end == tp, no generated sys_info contains tp, and
get_info throws. This testcase does not depend on the system tzdata:
```c++
#include <chrono>
#include <cstdio>
#include <filesystem>
#include <fstream>
namespace __gnu_cxx { const char* zoneinfo_dir_override() { return
"/tmp/tzmax-repro"; } }
int main(int argc, char**)
{
std::filesystem::create_directories("/tmp/tzmax-repro");
std::ofstream("/tmp/tzmax-repro/tzdata.zi")
<< "# version test\n"
"R X 2000 ma - Mar lastSu 2 1 D\n"
"R X 2000 ma - O lastSu 2 0 S\n"
"Z Test -6 X C%sT\n"
"Z Plain -6 - CST\n";
using namespace std::chrono;
const char* name = argc > 1 ? "Plain" : "Test"; // one zone per run
(get_info caches expansions)
const sys_seconds U{sys_days{year::max() / December / 31}};
int bad = 0;
for (sys_seconds t : {U, sys_seconds::max(), U - 1s})
try { sys_info i = locate_zone(name)->get_info(t); std::printf("%s: ok,
abbrev=%s\n", name, i.abbrev.c_str()); }
catch (const std::exception& e) { std::printf("%s: threw %s\n", name,
e.what()); bad = 1; }
return bad;
}
```
```
$ g++ -std=c++20 t.cc && ./a.out
Test: threw time_zone::get_info
Test: threw time_zone::get_info
Test: ok, abbrev=CST
$ ./a.out plain
Plain: ok, abbrev=CST
Plain: ok, abbrev=CST
Plain: ok, abbrev=CST
```
Expected: all three calls return a sys_info (as U - 1s and the rule-less zone
do). With the system tzdata,
`locate_zone("America/New_York")->get_info(sys_seconds::max())` throws as well.
The result also depends on cache history: after a query in the last year, the
same call returns a sys_info that does not contain tp instead of throwing.
Tested with 14.2.0. I did not build trunk libstdc++, but the clamp at
tzdb.cc:1082 is the same on trunk after r17-5617. Clamping to `(--i)->until() -
1s` (like the new lower-bound clamp) should avoid it, since U - 1s already
works.
Disclaimer: This test case was found with LLM-assisted targeted testing, and
the report was written with LLM assistance.