Fix filesystem::weakly_canonical()
on Win11 24H2 by StephanTLavavej · Pull Request #4844 · microsoft/STL (original) (raw)
We have a regression test for DevCom-538510 (internal VSO-850856) "std::filesystem::weakly_canonical
erroneously throws an exception":
// Also test VSO-850856 |
---|
// "std::filesystem::weakly_canonical should not throw an exception when a prefix is an existing file" |
const path fileWithSuffix = meow_txt.native() + L"/"; |
const path weaklyCanonicalFileWithSuffix = weakly_canonical(fileWithSuffix); // this should not throw |
assert(weaklyCanonicalFileWithSuffix.native().back() == L'\\'); |
This has regressed on the upcoming Win11 24H2, where we throw an exception (again). The relevant code is:
_EXPORT_STD _NODISCARD inline path weakly_canonical(const path& _Input, error_code& _Ec) { |
---|
// eventually calls GetFinalPathNameByHandleW |
_Ec.clear(); // for exception safety |
path _Temp; |
{ |
const auto _Err = _Canonical(_Temp, _Input.native()); |
if (_Err == __std_win_error::_Success) { |
return _Temp; |
} |
if (!__std_is_file_not_found(_Err)) { |
_Ec = _Make_ec(_Err); |
return {}; |
} |
} |
After calling _Canonical()
, anything other than _Err == __std_win_error::_Success
or __std_is_file_not_found(_Err)
is considered a hard error (which will cause the non-error_code
overload to throw a filesystem_error
).
In current OSes, the fileWithSuffix
scenario results in _Invalid_name
here. (Locally verified on Win11 23H2. Presumably we get the same behavior in the GitHub PR/CI system running Server 2022 21H2, although I didn't verify that.)
In Win11 24H2, we get _Directory_name_is_invalid
, which isn't recognized by __std_is_file_not_found
. 💥
The fix is backwards-compatible and a simple one-liner: add this error code enumerator to the list of synonyms that __std_is_file_not_found
recognizes. The plain meaning of _Directory_name_is_invalid
is clearly a subset of _Invalid_name
.
I've manually verified this (with significant but perhaps not surprising logistical difficulty) in an Azure VM with Win11 24H2. Regular test coverage will be provided by the MSVC-internal test harness (which is how we found this), and eventually by the GitHub test harness once Server 2025 24H2 is officially released.
Additionally, this uncaught exception from a non-error_code
overload manifested itself as an abort()
with no useful logs. To aid in future investigations, I'm including a simple change to the filesystem test. Now, we wrap the whole test in try ... catch
and print the contents of any exception before failing.