Skip to content

<filesystem>: weakly_canonical doesn't make absolute path for relative path with only correct drive. #6054

@Extra-Creativity

Description

@Extra-Creativity

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

Additional context

In the standard, weakly_canonical is specified as:

Effects: Using status(p) or status(p, ec), respectively, to determine existence, return a path composed by operator/= from the result of calling canonical with a path argument composed of the leading elements of p that exist, if any, followed by the elements of p that 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:

STL/stl/inc/filesystem

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 :-).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfilesystemC++17 filesystem

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions