Skip to content

Conversation

@StephanTLavavej
Copy link
Member

@StephanTLavavej StephanTLavavej commented Feb 2, 2026

This is the correct fix for the bug identified by #5976. Thanks @SiliconA-Z for finding this, @Morddin for identifying the correct constant to use (which I double-checked), and Fulgen on the STL Discord for providing the PowerShell incantation to create a junction.

Commits

  • Adjust how much _Read_reparse_data() allocates.
    • This doesn't appear to impact correctness, but FSCTL_GET_REPARSE_POINT control code in the Windows Drivers documentation says:

      Must be at least REPARSE_DATA_BUFFER_HEADER_SIZE plus the size of the expected user-defined data; and must be less than or equal to MAXIMUM_REPARSE_DATA_BUFFER_SIZE.

    • So, adding sizeof(wchar_t) appears to be totally unjustified and unnecessary.
  • Fix __std_fs_write_reparse_data_buffer().
    • FSCTL_SET_REPARSE_POINT control code in the Windows Drivers documentation says:

      For a REPARSE_DATA_BUFFER structure, this value must be at least REPARSE_DATA_BUFFER_HEADER_SIZE, plus the size of the user-defined data, and it must be less than or equal to MAXIMUM_REPARSE_DATA_BUFFER_SIZE.

    • Annoyingly, this constant appears in the WDK, but not the normal WinSDK (as mentioned by filesystem.cpp: __std_fs_write_reparse_data_buffer() should use the size of the buffer, not buffer pointer #5976 (comment)). However, it can easily be computed and visually verified against our structure definition. The correct constant is always 8 regardless of architecture (I checked x64 and x86).
    • Because the totally bogus sizeof(_Buffer) was measuring the size of the pointer const __std_fs_reparse_data_buffer* const _Buffer, this bug was cloaked on x64 and ARM64 with their 8-byte pointers. This bug reproed only for x86 with its 4-byte pointers.
  • Move constant to filesystem.cpp.
    • It didn't need to be in <xfilesystem_abi.h> where it was visible to users.

Repro

C:\Temp>type meow.cpp
// Create a junction in PowerShell before running this test case:
// mkdir DELME
// New-Item -ItemType Junction -Path TestJunction -Value "$PWD\DELME"

#include <filesystem>
#include <print>
using namespace std;

template <class Op>
void try_fs_op(Op op) {
    try {
        op();
    } catch (const filesystem::filesystem_error& e) {
        println("          e.what(): {}", e.what());
        println("  e.code().value(): {}", e.code().value());
        println("e.code().message(): {}", e.code().message());
    }
}

int main() {
    println("{}-bit.", sizeof(void*) * 8);
    try_fs_op([] { filesystem::remove("TestJunction2"); });
    try_fs_op([] { filesystem::copy("TestJunction", "TestJunction2", filesystem::copy_options::copy_symlinks); });
    try_fs_op([] { filesystem::remove("TestJunction2"); });
    println("Done!");
}
C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /MTd /Od /Zi /Fdmeow.pdb meow.cpp && meow
meow.cpp
64-bit.
Done!
C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /MTd /Od /Zi /Fdmeow.pdb meow.cpp && meow
meow.cpp
32-bit.
          e.what(): copy: The data present in the reparse point buffer is invalid.: "TestJunction", "TestJunction2"
  e.code().value(): 4392
e.code().message(): The data present in the reparse point buffer is invalid.
Done!

Notes

I've manually verified that the fix makes both x64 and x86 succeed.

Because junctions are weird and we aren't frequently changing this code, I'm not updating our automated test coverage for this.

This doesn't appear to impact correctness, but https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/fsctl-get-reparse-point says:
"Must be at least REPARSE_DATA_BUFFER_HEADER_SIZE plus the size of the expected user-defined data; and must be less than or equal to MAXIMUM_REPARSE_DATA_BUFFER_SIZE."
Adding `sizeof(wchar_t)` appears to be totally unjustified and unnecessary.
https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/fsctl-set-reparse-point
"For a REPARSE_DATA_BUFFER structure, this value must be at least REPARSE_DATA_BUFFER_HEADER_SIZE, plus the size of the user-defined data, and it must be less than or equal to MAXIMUM_REPARSE_DATA_BUFFER_SIZE."

Annoyingly, this constant appears in the WDK, but not the normal WinSDK. However, it can easily be computed, and visually verified against our structure definition.

The correct constant is always 8 regardless of architecture (I checked x64 and x86).

Because the totally bogus `sizeof(_Buffer)` was measuring the size of the pointer `const __std_fs_reparse_data_buffer* const _Buffer`,
this bug was cloaked on x64 and ARM64 with their 8-byte pointers. This bug reproed only for x86 with its 4-byte pointers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working filesystem C++17 filesystem

Projects

Status: Final Review

Development

Successfully merging this pull request may close these issues.

3 participants