Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

DiskUtils.TryGetReparseDataBuffer reads a struct from unzeroed pooled memory and ignores the number of bytes returned

Open
#242 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
Half a day
Newbie friendliness
57/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
csharp
Domain
backend

Research direction

Start with TruePath/DiskUtils.cs at TryGetReparseDataBuffer and inspect how DeviceIoControl reports the number of bytes returned. Check how IsJunction consumes the result and how SymbolicLinkReparseBuffer represents tag-specific fields. Done when short responses cannot produce a successful read of stale data and fields are interpreted according to the reparse tag.

Written by the indexing model from the issue text.

Description

bug good first issue help wanted

DiskUtils.TryGetReparseDataBuffer reads a SymbolicLinkReparseBuffer out of a buffer rented from ArrayPool<byte>.Shared:

byte[] buffer = ArrayPool<byte>.Shared.Rent(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
// ... DeviceIoControl(..., out _, ...)   // bytes returned are discarded
Span<byte> bufferSpan = new(buffer);
success = MemoryMarshal.TryRead(bufferSpan, out SymbolicLinkReparseBuffer reparseDataBuffer);

Two things are wrong here:

  1. Pooled arrays are not zeroed, and the number of bytes written by DeviceIoControl is ignored. The span covers the whole (larger-than-needed) array, so TryRead always succeeds, even when the driver returned fewer bytes than sizeof(SymbolicLinkReparseBuffer) (20 bytes). Reparse points with little or no payload leave the remaining fields filled with leftovers of whatever previously used the pooled array.
  2. SymbolicLinkReparseBuffer is a symlink-specific layout. Its Flags field only exists for symlinks. For junctions (mount points), and for other tags, the same four bytes are PathBuffer contents or arbitrary data.

No wrong result is observable today, because the only consumer, DiskUtils.IsJunction, reads just ReparseTag, which is always in the first four bytes of a successful response. But the method is a trap for the next person who reads another field. It reads uninitialized (stale) data and returns a struct whose fields can be garbage while the method reports success.

Recommendations

  • Capture lpBytesReturned and use new Span<byte>(buffer, 0, (int)bytesReturned), so that TryRead fails for a response that's too short.
  • Better: make the method return only what it can actually vouch for. Either return just the ReparseTag (that's all IsJunction needs), or expose a header-only struct (ReparseTag, ReparseDataLength, Reserved) and parse the tag-specific part per tag.
  • Rename or document the struct accordingly, so it's clear that Flags is valid only for IO_REPARSE_TAG_SYMLINK.
Dominant language
C#
Stars
109
Forks
26
Avg merge
3d 2h
Merged PRs (30d)
13

Getting set up

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.

More from ForNeVeR/TruePath

All issues in ForNeVeR/TruePath

Similar issues

More C# issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.