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
|
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
|
&& (fp = _Xfsopen(filename, 0, prot)) != nullptr) { // file must not exist, close and fail |
and
|
if ((fp = _Xfsopen(filename, n, prot)) == nullptr) { |
, if a file named by
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
|
"r", "w", "w", "a", "rb", "wb", "wb", "ab", "r+", "w+", "a+", "r+b", "w+b", "a+b", nullptr}; |
?
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::_Nocreateexactly mean?By
STL/stl/src/fiopen.cpp
Line 52 in cc515bb
ios_base::_Nocreateimpliesios_base::in. But what happens for a write-only mode, i.e.ios_base::outorios_base::app? Is it the tradition meaning of "nocreate" in this case?TOCTTOU issue on handling
io_base::_NoreplaceThis one seems a real bug. Between
STL/stl/src/fiopen.cpp
Line 71 in cc515bb
STL/stl/src/fiopen.cpp
Line 80 in cc515bb
filenameis 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 POSIXopento make sure the exclusive open-and-create semantics. The idiomatic correct way is usingO_CREAT | O_EXCLin 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_modein_wfdopen) even if an object referenced byFILE*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
STL/stl/src/fiopen.cpp
Line 14 in cc515bb