<filesystem>: weakly_canonical("nonexistent.txt") and weakly_canonical("./nonexistent.txt") behavior
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 11.1k
- Forks
- 1.7k
- Avg merge
- 4d 15h
- Merged PRs (30d)
- 22
Description
C:\Temp>type repro.cpp
#include <assert.h>
#include <filesystem>
#include <fstream>
#include <iostream>
using std::cout, std::endl, std::ofstream;
using std::filesystem::absolute, std::filesystem::remove, std::filesystem::weakly_canonical;
int main() {
{
ofstream f("temporary.txt");
f << "meow" << endl;
}
cout << R"( absolute("temporary.txt" ): )" << absolute("temporary.txt" ) << endl;
cout << R"(weakly_canonical("temporary.txt" ): )" << weakly_canonical("temporary.txt" ) << endl;
cout << R"(weakly_canonical("./temporary.txt"): )" << weakly_canonical("./temporary.txt") << endl;
assert(weakly_canonical("temporary.txt" ) == absolute("temporary.txt"));
assert(weakly_canonical("./temporary.txt") == absolute("temporary.txt"));
remove("temporary.txt");
cout << endl;
cout << R"( absolute("nonexistent.txt" ): )" << absolute("nonexistent.txt" ) << endl;
cout << R"(weakly_canonical("nonexistent.txt" ): )" << weakly_canonical("nonexistent.txt" ) << endl;
cout << R"(weakly_canonical("./nonexistent.txt"): )" << weakly_canonical("./nonexistent.txt") << endl;
assert(weakly_canonical("nonexistent.txt" ) == "nonexistent.txt");
assert(weakly_canonical("./nonexistent.txt") == absolute("nonexistent.txt"));
}
C:\Temp>cl /EHsc /nologo /W4 /std:c++17 repro.cpp
repro.cpp
C:\Temp>repro
absolute("temporary.txt" ): "C:\\Temp\\temporary.txt"
weakly_canonical("temporary.txt" ): "C:\\Temp\\temporary.txt"
weakly_canonical("./temporary.txt"): "C:\\Temp\\temporary.txt"
absolute("nonexistent.txt" ): "C:\\Temp\\nonexistent.txt"
weakly_canonical("nonexistent.txt" ): "nonexistent.txt"
weakly_canonical("./nonexistent.txt"): "nonexistent.txt"
Assertion failed: weakly_canonical("./nonexistent.txt") == absolute("nonexistent.txt"), file repro.cpp, line 29
The Standardese is WG21-N4835 [fs.op.weakly.canonical] https://eel.is/c++draft/fs.op.weakly.canonical :
path weakly_canonical(const path& p);
path weakly_canonical(const path& p, error_code& ec);
1 Returns:pwith symlinks resolved and the result normalized (29.11.7.1).
2 Effects: Usingstatus(p)orstatus(p, ec), respectively, to determine existence, return a path composed byoperator/=from the result of callingcanonical()with a path argument composed of the leading elements ofpthat exist, if any, followed by the elements ofpthat do not exist, if any. For the first form,canonical()is called without anerror_codeargument. For the second form,canonical()is called withecas anerror_codeargument, andpath()is returned at the first error occurrence, if any.
3 Ensures: The returned path is in normal form (29.11.7.1).
4 Remarks: Implementations should avoid unnecessary normalization such as whencanonicalhas already been called on the entirety ofp.
5 Throws: As specified in 29.11.6.
There's implementation divergence here; see https://godbolt.org/z/BRkB4V . The behavior that I observe is:
[MSVC]
weakly_canonical("nonexistent.txt" ): "nonexistent.txt"
weakly_canonical("./nonexistent.txt"): "nonexistent.txt"
Assertion failed: weakly_canonical("./nonexistent.txt") == absolute("nonexistent.txt"), file repro.cpp, line 29
[GCC 9.2, libstdc++]
weakly_canonical("nonexistent.txt" ): "nonexistent.txt"
weakly_canonical("./nonexistent.txt"): "/home/ubuntu/nonexistent.txt"
[assertions pass]
[Clang 9.0.0, libc++]
weakly_canonical("nonexistent.txt" ): "/home/ubuntu/nonexistent.txt"
weakly_canonical("./nonexistent.txt"): "/home/ubuntu/nonexistent.txt"
output.s: ./example.cpp:28: int main(): Assertion `weakly_canonical("nonexistent.txt" ) == "nonexistent.txt"' failed.
Also tracked by DevCom-818027 and Microsoft-internal VSO-1021558 / AB#1021558.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by compiling and running the supplied C++17 repro.cpp with MSVC, then compare the weakly_canonical results against [fs.op.weakly.canonical] in WG21-N4835 and the GCC/libstdc++ behavior described. Trace the filesystem implementation entry point used by weakly_canonical; done means the nonexistent-path cases follow the specified normalization behavior and the repro assertions pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- operating-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100