[Boost-bugs] [Boost C++ Libraries] #13159: Assert hit in wcsftime.cpp on Windows due to tm_year out of range

Subject: [Boost-bugs] [Boost C++ Libraries] #13159: Assert hit in wcsftime.cpp on Windows due to tm_year out of range
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2017-08-12 08:00:39


#13159: Assert hit in wcsftime.cpp on Windows due to tm_year out of range
------------------------------+---------------------
 Reporter: dstftw@… | Owner: (none)
     Type: Bugs | Status: new
Milestone: To Be Determined | Component: None
  Version: Boost 1.63.0 | Severity: Problem
 Keywords: |
------------------------------+---------------------
 The issue is only reproducible on MSVC (toolsets tested v120, v140, v141)
 and caused by a limitation imposed on `tm_year` of `tm` to belong to the
 range `[-1900; 8099]` (see assert below).

 Here is the sample code that reproduces the problem:

 {{{
 #include "stdafx.h"

 #include <sstream>
 #include <boost/date_time.hpp>

 int main()
 {
         std::ostringstream os;
         os.imbue(std::locale(std::locale::classic(), new
 boost::posix_time::time_facet("%Y")));
         os << boost::posix_time::ptime(boost::gregorian::date(10000, 1,
 1));
         return 0;
 }
 }}}

 Stack trace:
 {{{
         ucrtbased.dll!expand_time(__crt_locale_pointers * locale, wchar_t
 specifier, const tm * timeptr, wchar_t * * string, unsigned __int64 *
 left, const __crt_lc_time_data * lc_time, bool alternate_form) Line 971
 C++
         ucrtbased.dll!_Wcsftime_l(wchar_t * string, unsigned __int64
 max_size, const wchar_t * format, const tm * timeptr, void * lc_time_arg,
 __crt_locale_pointers * locale) Line 1134 C++
         ucrtbased.dll!_Strftime_l(char * const string, const unsigned
 __int64 maxsize, const char * const format, const tm * const timeptr, void
 * const lc_time_arg, __crt_locale_pointers * const locale) Line 169 C++
         ucrtbased.dll!_Strftime(char * string, unsigned __int64 max_size,
 const char * format, const tm * timeptr, void * lc_time_arg) Line 197 C++
>
 msvcp140d.dll!std::time_put<char,std::ostreambuf_iterator<char,std::char_traits<char>
> >::do_put(std::ostreambuf_iterator<char,std::char_traits<char> > _Dest,
 std::ios_base & __formal, char __formal, const tm * _Pt, char _Specifier,
 char _Modifier) Line 799 C++
 msvcp140d.dll!std::time_put<char,std::ostreambuf_iterator<char,std::char_traits<char>
> >::put(std::ostreambuf_iterator<char,std::char_traits<char> > _Dest,
 std::ios_base & _Iosbase, char _Fill, const tm * _Pt, const char *
 _Fmtfirst, const char * _Fmtlast) Line 732 C++
 DateTimePlayground.exe!boost::date_time::date_facet<boost::gregorian::date,char,std::ostreambuf_iterator<char,std::char_traits<char>
> >::do_put_tm(std::ostreambuf_iterator<char,std::char_traits<char> >
 next, std::ios_base & a_ios, char fill_char, const tm & tm_value,
 std::basic_string<char,std::char_traits<char>,std::allocator<char> >
 a_format) Line 342 C++
 DateTimePlayground.exe!boost::date_time::time_facet<boost::posix_time::ptime,char,std::ostreambuf_iterator<char,std::char_traits<char>
> >::put(std::ostreambuf_iterator<char,std::char_traits<char> > next_arg,
 std::ios_base & ios_arg, char fill_arg, const boost::posix_time::ptime &
 time_arg) Line 427 C++
 DateTimePlayground.exe!boost::posix_time::operator<<<char,std::char_traits<char>
>(std::basic_ostream<char,std::char_traits<char> > & os, const
 boost::posix_time::ptime & p) Line 52 C++
         DateTimePlayground.exe!main() Line 11 C++
         [External Code]
 }}}

 Assert:

 {{{
 Debug Assertion Failed!

 Program: ...\Projects\DateTimePlayground\x64\Debug\DateTimePlayground.exe
 File: minkernel\crts\ucrt\src\appcrt\time\wcsftime.cpp
 Line: 971

 Expression: timeptr->tm_year >= -1900 && timeptr->tm_year <= 8099

 For information on how your program can cause an assertion
 failure, see the Visual C++ documentation on asserts.

 (Press Retry to debug the application)
 }}}

 Any date with year `10000` will hit this assert. Starting with year
 `10001` `boost::gregorian::bad_year` is thrown instead.

 Such behavior is caused by max year
 (include/boost/date_time/gregorian/greg_year.hpp#L28) that allows year
 `10000`. This causes `tm_year` of `tm` to be `8100` out of range `[-1900;
 8099]` when converting ptime to tm
 (include/boost/date_time/time_facet.hpp#L428).

 I would expect consistent `boost::gregorian::bad_year` thrown in all cases
 without crashes.

 One possible solution is to consider changing max year to `9999`. This
 would also fix #12630 and make `%Y` format specifier to be more consistent
 with its definition (xmldoc/format_flags.xml#L220) - a `Four digit year`.
 Currently, the following code on Linux outputs `10000` instead of throwing
 `boost::gregorian::bad_year` that is at least confusing since `10000` does
 not look like a four digit number as promised by `%Y`:
 {{{
 #include <sstream>
 #include <boost/date_time.hpp>

 int main()
 {
         std::ostringstream os;
         os.imbue(std::locale(std::locale::classic(), new
 boost::posix_time::time_facet("%Y")));
         os << boost::posix_time::ptime(boost::gregorian::date(10000, 1,
 1));
         std::cout << os.str();
         return 0;
 }
 }}}

-- 
Ticket URL: <https://svn.boost.org/trac10/boost/ticket/13159>
Boost C++ Libraries <http://www.boost.org/>
Boost provides free peer-reviewed portable C++ source libraries.

This archive was generated by hypermail 2.1.7 : 2017-08-12 08:07:28 UTC