<html>
<head>
<base href="https://bugs.llvm.org/">
</head>
<body><table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Bug ID</th>
<td><a class="bz_bug_link
bz_status_NEW "
title="NEW - std::get_time does not check month range minimum"
href="https://bugs.llvm.org/show_bug.cgi?id=48319">48319</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>std::get_time does not check month range minimum
</td>
</tr>
<tr>
<th>Product</th>
<td>libc++
</td>
</tr>
<tr>
<th>Version</th>
<td>3.2
</td>
</tr>
<tr>
<th>Hardware</th>
<td>PC
</td>
</tr>
<tr>
<th>OS</th>
<td>Linux
</td>
</tr>
<tr>
<th>Status</th>
<td>NEW
</td>
</tr>
<tr>
<th>Severity</th>
<td>normal
</td>
</tr>
<tr>
<th>Priority</th>
<td>P
</td>
</tr>
<tr>
<th>Component</th>
<td>All Bugs
</td>
</tr>
<tr>
<th>Assignee</th>
<td>unassignedclangbugs@nondot.org
</td>
</tr>
<tr>
<th>Reporter</th>
<td>emile.cormier.jr@gmail.com
</td>
</tr>
<tr>
<th>CC</th>
<td>llvm-bugs@lists.llvm.org, mclow.lists@gmail.com
</td>
</tr></table>
<p>
<div>
<pre>libc++'s std::get_time allows a day input of "00" for the %m specifier, whereas
the POSIX spec for strptime constrains it to [01,12].
When converted to a std::tm, the month becomes zero-based with a range of
[0,11], so it's understandable how this oversight in range checking could have
happened.
libc++'s std::get_time doesn't allow an input of "00" for the %d specifier, so
the range checking behavior is not consistent between the %m and %d specifiers.
For comparison, GCC's libstdc++ does not allow an input of "00" for the %m
specifier.
I've tracked the problem down to this line, where there should be an extra
condition to check that __t >= 0:
<a href="https://github.com/llvm/llvm-project/blob/527a7fdfbd7461e2aaa9eb279543c5d9dc8efa5a/libcxx/include/locale#L1956">https://github.com/llvm/llvm-project/blob/527a7fdfbd7461e2aaa9eb279543c5d9dc8efa5a/libcxx/include/locale#L1956</a>
I'm currently set-up with Clang version 11, but checking the git blame on
Github reveals that this bug probably existed since the initial import back in
2010, so I've set the Version field of this bug report to the earliest possible
value.
I don't have time to set up a build environment to check if that is indeed the
proper fix, so I leave it to the libc++ maintainers.
Here is a program that reproduces the problem:
#include <cstring>
#include <ctime>
#include <iostream>
#include <sstream>
#include <iomanip>
int main()
{
using namespace std;
istringstream good_month("2000-01-01");
istringstream bad_month("2000-00-01");
istringstream bad_day("2000-01-00");
tm ymd;
memset(&ymd, 0, sizeof(ymd));
good_month >> get_time(&ymd, "%Y-%m-%d");
cout << "!good_month=" << !good_month; // prints 0, as expected
cout << ", ymd.tm_mon=" << ymd.tm_mon << "\n"; // prints -1
bad_month >> get_time(&ymd, "%Y-%m-%d");
cout << "!bad_month=" << !bad_month; // *** prints 0, should be 1 ***
cout << ", ymd.tm_mon=" << ymd.tm_mon << "\n"; // prints 0
bad_day >> get_time(&ymd, "%Y-%m-%d");
cout << "!bad_day=" << !bad_day << "\n"; // prints 1, as expected
const char c_bad_month[] = "2000-00-01";
auto result = strptime(c_bad_month, "%Y-%m-%d", &ymd);
cout << "(result==nullptr)=" << (result==nullptr) << "\n"; // prints 1
return 0;
}</pre>
</div>
</p>
<hr>
<span>You are receiving this mail because:</span>
<ul>
<li>You are on the CC list for the bug.</li>
</ul>
</body>
</html>