-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
<iomanip>: std::put_time should not crash on invalid/out-of-range tm struct values #4882
Comments
Please note that cplusplus.com is widely regarded as low-quality, versus cppreference.com which is widely preferred. (Compare https://cplusplus.com/reference/iomanip/put_time/ to https://en.cppreference.com/w/cpp/io/manip/put_time .) However, even cppreference is unofficial (a community-edited wiki) and occasionally contains inaccuracies or simplifications. The C++ Working Paper (currently WG21-N4988) is the ultimate source of authority for our implementation work. In this case, the important questions are "what do we do for out-of-range fields", "do we set N4988 [ext.manip]/10 says that if (end.failed())
str.setstate(ios_base::badbit); [locale.categories.general]/2 says: "The C23 7.29.3.5 "The strftime function"/3 says: "If any of the specified values is outside the normal range, the characters stored are unspecified." Disclaimer: Despite working on this codebase for 17 years, I still find it difficult to understand iostreams/locales and their Standardese. However, this wording appears to be saying to me:
Corrections to my interpretation would be gratefully appreciated. |
To me, Silently replacing values seem me like undefined behavior. It would be best to not print anything and just report failure. I'm also open to other interpretations or suggestions. |
We need to figure out what the Standards say we must/can do. Judgement calls can be a factor when deciding what to do within the bounds of what the Standards say we can do, but otherwise we are absolutely constrained by the normative text. What you're describing sounds like inventing behavior that we "think" should happen - which would be appropriate in a library we're designing ourselves, but not in the Standard Library which has been (literally) designed by committee. Note - I'm not saying you're wrong on this specific point, just that it needs to be justified by citing specific paragraphs in the Standards. I can't find such paragraphs that say that
Considering the C Standard in isolation, this is incorrect by definition. The Standard decides what's undefined (anything can happen, including crashing, including backwards in time) versus unspecified, versus implementation-defined, versus well-defined. The sentence I cited clearly says that out-of-range values result in unspecified characters being stored. That not only means that silent replacement is something that implementations can decide to do, it also means that implementations aren't allowed to do other things, such as crash or report failure (by returning As I mentioned, I am less certain about the whole interaction between the C and C++ Standards here, but that uncertainty is "on me" - either there should be no actual ambiguity in what they require/allow here, or there's a defect in the library wording (hopefully not!). Although it isn't a definitive technique, we can also check the observable behavior of the other implementations libstdc++ and libc++ to see what they do - if they are united then it suggests that the Standard says their behavior is correct, if they diverge then that suggests that the Standard allows a range of behavior, or there are implementation bugs. |
Yes, sorry, I didn't wanted to imply that we should implement stuff how we "feel" it. I guess I just over trusted the "community-wikies" and I'm quite new into reading the actual standard papers. They are like studying law in university. :) But I guess there is no escaping here. I will try to dig in more tomorrow. I will also cross-reference what the other major compilers do as you suggested. |
@StephanTLavavej So I've spend a few hours researching what should be done here and to be honest it is not clearly defined. For example all functions which are supposed to create time object from string will do
Where I've also tested what other compilers are doing(GCC 14 and Clang 18). They are pretty much forwarding all the input to So, how we handle that situation for MS STL Given all that I've changed my mind a bit how we should handle this stuff here. We can also keep the stream in As a middle ground I propose for every invalid tm struct value to just print single |
Ok, I've pushed changes to my PR to update it to use my new understandings. I'm still open to suggestions for the best approach given the standard is not very explicit. |
Describe the bug
If an invalid or out-of-range tm struct is passed to
std::put_time()
it will lead to crash.Command-line test case
Expected behavior
The program should NOT crash.
Additional context
The crash is happening because of
strftime
which validates the data and if something is wrong it leads to crash if no handler is set.The text was updated successfully, but these errors were encountered: