From 9ac41819ab05282798c498b373a5017b1c2c4e64 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Fri, 23 Mar 2018 12:41:21 -0400 Subject: [PATCH] Fix Path.GetTempFileName on Windows (#17148) GetTempFileNameW doesn't return the required length of the buffer; it returns the unique number used in the temporary file name. But the calling code is using that result as a length, resulting in sometimes truncated paths, and sometimes paths that aren't at all related to the original due to state left over in a pooled buffer. --- src/mscorlib/shared/System/IO/Path.Windows.cs | 11 +++-------- src/mscorlib/shared/System/Text/ValueStringBuilder.cs | 4 ++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/mscorlib/shared/System/IO/Path.Windows.cs b/src/mscorlib/shared/System/IO/Path.Windows.cs index 8f1bed0..f22a991 100644 --- a/src/mscorlib/shared/System/IO/Path.Windows.cs +++ b/src/mscorlib/shared/System/IO/Path.Windows.cs @@ -165,20 +165,15 @@ namespace System.IO Span initialBuffer = stackalloc char[PathInternal.MaxShortPath]; var builder = new ValueStringBuilder(initialBuffer); - uint result = 0; - while ((result = Interop.Kernel32.GetTempFileNameW( - ref tempPathBuilder.GetPinnableReference(), "tmp", 0, ref builder.GetPinnableReference())) > builder.Capacity) - { - // Reported size is greater than the buffer size. Increase the capacity. - builder.EnsureCapacity(checked((int)result)); - } + uint result = Interop.Kernel32.GetTempFileNameW( + ref tempPathBuilder.GetPinnableReference(), "tmp", 0, ref builder.GetPinnableReference()); tempPathBuilder.Dispose(); if (result == 0) throw Win32Marshal.GetExceptionForLastWin32Error(); - builder.Length = (int)result; + builder.Length = builder.RawChars.IndexOf('\0'); string path = PathHelper.Normalize(ref builder); builder.Dispose(); diff --git a/src/mscorlib/shared/System/Text/ValueStringBuilder.cs b/src/mscorlib/shared/System/Text/ValueStringBuilder.cs index b1abdd5..d41bea0 100644 --- a/src/mscorlib/shared/System/Text/ValueStringBuilder.cs +++ b/src/mscorlib/shared/System/Text/ValueStringBuilder.cs @@ -27,6 +27,7 @@ namespace System.Text get => _pos; set { + Debug.Assert(value >= 0); Debug.Assert(value <= _chars.Length); _pos = value; } @@ -70,6 +71,9 @@ namespace System.Text return s; } + /// Returns the underlying storage of the builder. + public Span RawChars => _chars; + /// /// Returns a span around the contents of the builder. /// -- 2.7.4