-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
Describe the bug
Say I have a directory Temp in C drive and my current directory is C:\Temp; Temp contains a subdirectory foo. There is no bar in Temp and foo.
And given the program below:
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
fs::current_directory("C:\\Temp");
// Should be (and currently is) C:\Temp.
std::cout << fs::weakly_canonical("C:") << "\n";
// Should be (and currently is) C:\Temp\foo\bar, though bar doesn't exist.
std::cout << fs::weakly_canonical("C:foo\\bar") << "\n";
// Should be (**but currently is not**) C:\Temp\bar, though bar doesn't exist.
std::cout << fs::weakly_canonical("C:bar") << "\n";
}Command-line test case
C:\Temp>type repro.cpp
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main()
{
// Prepare reproduction environment.
fs::path tempDir{ "C:\\Temp" };
fs::create_directories(tempDir / "foo");
// Test
fs::current_path(tempDir);
std::cout << fs::weakly_canonical("C:") << "\n";
std::cout << fs::weakly_canonical("C:foo\\bar") << "\n";
std::cout << fs::weakly_canonical("C:bar") << "\n";
// Clean reproduction environment.
fs::remove_all(tempDir / "foo");
}
C:\Temp>cl /EHsc /W4 /WX /std:c++latest .\repro.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.44.35214 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
/std:c++latest is provided as a preview of language features from the latest C++
working draft, and we're eager to hear about bugs and suggestions for improvements.
However, note that these features are provided as-is without support, and subject
to changes or removal as the working draft evolves. See
https://go.microsoft.com/fwlink/?linkid=2045807 for details.
repro.cpp
Microsoft (R) Incremental Linker Version 14.44.35214.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:repro.exe
repro.obj
C:\Temp>.\repro.exe
"C:\\Temp"
"C:\\Temp\\foo\\bar"
"C:bar"
Expected behavior
The last output should be "C:\\Temp\\bar".
STL version
- Option 1: MSVC Compiler version: 19.44.35214
- Option 2:
_MSVC_STL_UPDATEvalue: 202503 - Option 3: git commit hash: this problem still exists in the [current latest commit] (https://github.com/microsoft/STL/blob/3f76681e18fa51e1441c9150099b8010c1d18e1c/stl/inc/filesystem).
Additional context
In the standard, weakly_canonical is specified as:
Effects: Using
status(p)orstatus(p, ec), respectively, to determine existence, return a path composed byoperator/=from the result of calling canonical with a path argument composed of the leading elements ofpthat exist, if any, followed by the elements ofpthat do not exist, if any.
And the elements of path are specifed as:
A path is a sequence of elements that identify the location of a file within a filesystem. The elements are the root-name, root-directory, and an optional sequence of filename ([fs.path.generic]).
So C: as the root-name is a legal leading element in the path and thus the last line in test case should be "C:\\Temp\\bar" instead.
The problem is that MS-STL skips initial value of the element for this case:
Lines 4132 to 4159 in 3f76681
| const path _Normalized = _Input.lexically_normal(); | |
| path _Result = _Normalized.root_path(); | |
| const path _Normalized_relative = _Normalized.relative_path(); | |
| bool _Call_canonical = true; | |
| for (const auto& _Elem : _Normalized_relative) { | |
| _Result /= _Elem; | |
| if (_Call_canonical) { | |
| _Temp.clear(); | |
| const auto _Err = _Canonical(_Temp, _Result.native()); | |
| if (_Err == __std_win_error::_Success) { | |
| _Result = _STD move(_Temp); | |
| } else if (__std_is_file_not_found(_Err)) { | |
| _Call_canonical = false; | |
| } else { | |
| _Ec = _Make_ec(_Err); | |
| return {}; | |
| } | |
| } | |
| } | |
| return _Result; |
Here in the loop, for C:bar, the first _Result to call _Canonical is C:bar instead of C:. I'd like to submit a PR if this is considered as a bug :-).