microsoft / microsoft/STL

`<filesystem>`: `directory_iterator` with `\\\\.\\pipe` can produce invalid paths

Open
#4,423 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug filesystem
Dominant language
C++
Stars
11.1k
Forks
1.7k
Avg merge
4d 15h
Merged PRs (30d)
22

Description

Describe the bug

Attempting to use directory_iterator or recursive_directory_iterator with the path \\\\.\\pipe (to list named pipes) can produce invalid paths. It seems that although the documentation states that pipe names can't include backslashes, this isn't actually enforced. If a pipe under \\\\.\\pipe\\ does include a backslash in its name then _Dir_enum_impl::_Refresh only replaces the previous pipe name from the last backslash onwards, producing paths like "\\\\.\\pipe\\Winsock2\\Winsock2\\Winsock2\\Winsock2\\Winsock2\\Winsock2\\Winsock2\\def", where a previously found pipe was named "\\\\.\\pipe\\WinSock2\\abc".

Command-line test case

C:\DirectoryIteratorTest>type DirectoryIteratorTest.cpp
#include <filesystem>
#include <iostream>

#include <Windows.h>

int main()
{
        // Random strings that shouldn't already exist in pipe names
        const std::wstring strRand1{ L"5639357256" }, strRand2{ L"9423298489" }, strRand3{ L"3214769820" };

        // The base path for pipes
        const std::filesystem::path pathPipeBase{ "\\\\.\\pipe" };
        // A pipe path with a backslash in its name
        const std::filesystem::path pathPipeBad{ pathPipeBase / strRand1 / strRand2 };
        // A pipe path without a backslash in its name
        const std::filesystem::path pathPipeOk{ pathPipeBase / strRand3 };

        HANDLE hPipeBad(CreateNamedPipeW(pathPipeBad.native().c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 1024, 1024, 0, nullptr));
        HANDLE hPipeOk(CreateNamedPipeW(pathPipeOk.native().c_str(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 1024, 1024, 0, nullptr));
        if (!std::filesystem::exists(pathPipeBad) || !std::filesystem::exists(pathPipeOk))
        {
                std::cout << "CreateNamedPipe failed" << std::endl;
                return 1;
        }

        for (const auto& entry : std::filesystem::directory_iterator{ pathPipeBase })
        {
                // Look for paths that contain the random string in the bad path before the backslash, but not the one after
                if ((entry.path().native().find(strRand1) != std::wstring::npos) && (entry.path().native().find(strRand2) == std::wstring::npos))
                        std::cout << entry.path() << std::endl;
        }

        CloseHandle(hPipeOk);
        CloseHandle(hPipeBad);
}

C:\DirectoryIteratorTest>cl /EHsc /W4 /WX /std:c++latest DirectoryIteratorTest.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.40.33521 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.

DirectoryIteratorTest.cpp
Microsoft (R) Incremental Linker Version 14.40.33521.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:DirectoryIteratorTest.exe
DirectoryIteratorTest.obj

C:\DirectoryIteratorTest>.\DirectoryIteratorTest.exe
"\\\\.\\pipe\\Winsock2\\Winsock2\\Winsock2\\Winsock2\\Winsock2\\Winsock2\\Winsock2\\Winsock2\\PIPE_EVENTROOT\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\ProtectedPrefix\\LocalService\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\uv\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\IdentityNexusIntegrationPipe\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\LOCAL\\5639357256\\3214769820"

Expected behavior

In the example above there should be no output, in general pipe names with backslashes should be handled correctly

STL version

Microsoft Visual Studio Professional 2022 (64-bit) - Preview
Version 17.10.0 Preview 1.0

Additional context

I have no idea whether supporting \\\\.\\pipe with std::filesystem is even intended, though it would be nice

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the directory_iterator and recursive_directory_iterator implementation, especially _Dir_enum_impl::_Refresh, and reproduce the behavior using the command-line test case with named pipes under \.\pipe. Trace how entries containing backslashes are converted into paths. Done means pipe names with backslashes are returned correctly without accumulating or duplicating path components.

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
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.