Skip to content

<iomanip>: std::put_time should copy unknown conversion specifiers instead of crash #4820

@TheStormN

Description

@TheStormN

Describe the bug

I know that behind the scenes std::put_time does use strftime which leads to crash if some kind of invalid input is provided. I haven't exactly read the standard, but the cplusplus.com docs on the function says if anything wrong happens, it should set the failbit on the stream and not crash the program. While undefined behavior is allowed for strftime on invalid input, this does not seems to be the case for std::put_time and this is why I'm reporting this as a bug.

Now, some ideas from my research on the topic. According to MS docs the only way to recover from strftime error case is to use _set_invalid_parameter_handler/_set_thread_local_invalid_parameter_handler https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/set-invalid-parameter-handler-set-thread-local-invalid-parameter-handler?view=msvc-170

The first one seems unfeasible as it will modify the global CRT invalid handler for C functions. The second option about thread local storage might be a better option if set and unset before/after calling std::put_time and using it to properly flag the stream error. This would still trigger an assert in debug mode, but at least it will not crash release versions.

But in general, the best solution for me would be for the UCRT team to modify the existing strftime implementations or create a completely new variant which can handle errors in a more graceful manner, but if this is not possible at least the STL team should try to handle this case somehow by perhaps using the workaround I've proposed.

Command-line test case

C:\Temp>type repro.cpp
#include <iostream>
#include <iomanip>
#include <sstream>
#include <ctime>

int main() {
    std::time_t t = std::time(0);
    std::tm* now = std::localtime(&t);
    std::ostringstream output;
    output << std::put_time(now, "%E%J%P"); // some random invalid formatting string

    if(output.good()) {
        std::cout << "All good\n";
    } else {
        std::cout << "Date time formatting failed due to invalid input\n";
    }
}

C:\Temp>cl /EHsc /W4 /WX /std:c++20 .\repro.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.36.32546 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

repro.cpp
Microsoft (R) Incremental Linker Version 19.36.32546.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:repro.exe
repro.obj

C:\Temp>.\repro.exe
!!!App Crashed!!!

Expected behavior

That would be for the program to NOT crash and output "Date time formatting failed due to invalid input".

(Edited: See analysis below.)

STL version

VS 2022 17.6.16

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfixedSomething works now, yay!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions