You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
DiskUtils.TryGetReparseDataBuffer reads a struct from unzeroed pooled memory and ignores the number of bytes returned #242
byte[]buffer=ArrayPool<byte>.Shared.Rent(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);// ... DeviceIoControl(..., out _, ...) // bytes returned are discardedSpan<byte>bufferSpan=new(buffer);success=MemoryMarshal.TryRead(bufferSpan,outSymbolicLinkReparseBufferreparseDataBuffer);
Two things are wrong here:
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.
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.
In #246, we've migrated to GetFileInformationByHandleEx, so this is no longer a problem. We no longer use the array pool, and the current API usage pattern is much simpler.
Activity
ForNeVeR commentedon Oct 25, 2026
In #246, we've migrated to
GetFileInformationByHandleEx, so this is no longer a problem. We no longer use the array pool, and the current API usage pattern is much simpler.