-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
The implementation strategy in https://github.com/microsoft/STL/blob/main/stl/src/fiopen.cpp is quite unnatrual, which leaves to problems for non-standard flags, even the expect behaviors are not well-documented.
What does ios_base::_Nocreate exactly mean?
By
Line 52 in cc515bb
| mode |= ios_base::in; // file must exist |
ios_base::_Nocreate implies ios_base::in. But what happens for a write-only mode, i.e. ios_base::out or ios_base::app? Is it the tradition meaning of "nocreate" in this case?
TOCTTOU issue on handling io_base::_Noreplace
This one seems a real bug. Between
Line 71 in cc515bb
| && (fp = _Xfsopen(filename, 0, prot)) != nullptr) { // file must not exist, close and fail |
Line 80 in cc515bb
| if ((fp = _Xfsopen(filename, n, prot)) == nullptr) { |
filename is created, the check is voided, so the flag is useless in this case. It looks like the same to the infamous anti-pattern of multiple calls to POSIX open to make sure the exclusive open-and-create semantics. The idiomatic correct way is using O_CREAT | O_EXCL in a single call, to enforce the atomicity.
Related implementation question
The concerned functions are implemented by the stdio extension function _fsopen. Why not use lowio (i.e. _wsopen) instead? This can easily resolve the correctness problems mentioned above, and it could be a bit more efficient due to the simpler mode translation and parsing (in the underlying implementation; once you have the implementation-specific knowledge, it seems not difficult to bypass the redundant passing like __acrt_stdio_parse_mode in _wfdopen) even if an object referenced by FILE* is still needed to be created later.
If lowio is not an appropriate choice for some coding policies I don't know, is it considerable to use C11-style "x" modes in
Line 14 in cc515bb
| "r", "w", "w", "a", "rb", "wb", "wb", "ab", "r+", "w+", "a+", "r+b", "w+b", "a+b", nullptr}; |