Expose, test, and use ExceptionDispatchInfo.SetCurrentStackTrace
authorStephen Toub <stoub@microsoft.com>
Sat, 5 Oct 2019 18:12:52 +0000 (14:12 -0400)
committerStephen Toub <stoub@microsoft.com>
Sat, 5 Oct 2019 21:07:51 +0000 (17:07 -0400)
Commit migrated from https://github.com/dotnet/corefx/commit/615990343a9400e46122debf48a5fb08ec452787

14 files changed:
src/libraries/System.IO.FileSystem/src/System/IO/File.cs
src/libraries/System.IO.Pipes/src/System/IO/Pipes/ConnectionCompletionSource.cs
src/libraries/System.IO.Pipes/src/System/IO/Pipes/ReadWriteCompletionSource.cs
src/libraries/System.Net.Http/src/System/Net/Http/MessageProcessingHandler.cs
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/ConnectHelper.cs
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/CreditManager.cs
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RawConnectionStream.cs
src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionPal.Windows.cs
src/libraries/System.Net.Requests/src/System/Net/FtpWebRequest.cs
src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Implementation.cs
src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Tasks.cs
src/libraries/System.Runtime/ref/System.Runtime.cs
src/libraries/System.Runtime/tests/System/Runtime/ExceptionServices/ExceptionDispatchInfoTests.netcoreapp.cs

index 8a5ed38..93685a4 100644 (file)
@@ -7,6 +7,7 @@ using System.Buffers;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
+using System.Runtime.ExceptionServices;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
@@ -775,7 +776,11 @@ namespace System.IO
                 long fileLength = fs.Length;
                 if (fileLength > int.MaxValue)
                 {
-                    return Task.FromException<byte[]>(new IOException(SR.IO_FileTooLong2GB));
+                    var e = new IOException(SR.IO_FileTooLong2GB);
+#if !MS_IO_REDIST
+                    ExceptionDispatchInfo.SetCurrentStackTrace(e);
+#endif
+                    return Task.FromException<byte[]>(e);
                 }
 
                 returningInternalTask = true;
index 7d12edb..f5a34ba 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Runtime.ExceptionServices;
 using System.Threading;
 
 namespace System.IO.Pipes
@@ -34,12 +35,11 @@ namespace System.IO.Pipes
             base.AsyncCallback(errorCode, numBytes);
         }
 
-        protected override void HandleError(int errorCode)
-        {
-            TrySetException(Win32Marshal.GetExceptionForWin32Error(errorCode));
-        }
+        protected override void HandleError(int errorCode) =>
+            TrySetException(ExceptionDispatchInfo.SetCurrentStackTrace(Win32Marshal.GetExceptionForWin32Error(errorCode)));
 
-        protected override void HandleUnexpectedCancellation() => TrySetException(Error.GetOperationAborted());
+        protected override void HandleUnexpectedCancellation() =>
+            TrySetException(ExceptionDispatchInfo.SetCurrentStackTrace(Error.GetOperationAborted()));
     }
 
     internal struct VoidResult { }
index cac234a..b75b872 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Runtime.ExceptionServices;
 using System.Threading;
 
 namespace System.IO.Pipes
@@ -63,9 +64,7 @@ namespace System.IO.Pipes
             base.AsyncCallback(errorCode, numBytes);
         }
 
-        protected override void HandleError(int errorCode)
-        {
-            TrySetException(_pipeStream.WinIOError(errorCode));
-        }
+        protected override void HandleError(int errorCode) =>
+            TrySetException(ExceptionDispatchInfo.SetCurrentStackTrace(_pipeStream.WinIOError(errorCode)));
     }
 }
index 84bba19..55db3c6 100644 (file)
@@ -5,6 +5,7 @@
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.Runtime.ExceptionServices;
 using System.Text;
 using System.Threading.Tasks;
 using System.Threading;
@@ -68,7 +69,7 @@ namespace System.Net.Http
 
                     if (task.Result == null)
                     {
-                        sendState.TrySetException(new InvalidOperationException(SR.net_http_handler_noresponse));
+                        sendState.TrySetException(ExceptionDispatchInfo.SetCurrentStackTrace(new InvalidOperationException(SR.net_http_handler_noresponse)));
                         return;
                     }
 
index ac5d4e4..8b440de 100644 (file)
@@ -7,6 +7,7 @@ using System.IO;
 using System.Net.Security;
 using System.Net.Sockets;
 using System.Runtime.CompilerServices;
+using System.Runtime.ExceptionServices;
 using System.Security.Cryptography.X509Certificates;
 using System.Threading;
 using System.Threading.Tasks;
@@ -106,13 +107,13 @@ namespace System.Net.Http
                     case SocketError.ConnectionAborted:
                         if (CancellationToken.IsCancellationRequested)
                         {
-                            Builder.SetException(CancellationHelper.CreateOperationCanceledException(null, CancellationToken));
+                            Builder.SetException(ExceptionDispatchInfo.SetCurrentStackTrace(CancellationHelper.CreateOperationCanceledException(null, CancellationToken)));
                             break;
                         }
                         goto default;
 
                     default:
-                        Builder.SetException(new SocketException((int)SocketError));
+                        Builder.SetException(ExceptionDispatchInfo.SetCurrentStackTrace(new SocketException((int)SocketError)));
                         break;
                 }
             }
index bed59a3..6337f64 100644 (file)
@@ -5,6 +5,7 @@
 using System.Diagnostics;
 using System.Collections.Generic;
 using System.IO;
+using System.Runtime.ExceptionServices;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -121,7 +122,7 @@ namespace System.Net.Http
                 {
                     while (_waiters.TryDequeue(out Waiter waiter))
                     {
-                        waiter.TrySetException(CreateObjectDisposedException(forActiveWaiter: true));
+                        waiter.TrySetException(ExceptionDispatchInfo.SetCurrentStackTrace(CreateObjectDisposedException(forActiveWaiter: true)));
                     }
                 }
             }
index 4de47fe..06a4e81 100644 (file)
@@ -7,6 +7,7 @@ using System.Diagnostics;
 using System.IO;
 using System.Net.Http.Headers;
 using System.Runtime.CompilerServices;
+using System.Runtime.ExceptionServices;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
@@ -1159,7 +1160,7 @@ namespace System.Net.Http
 
                     if (http2Stream == null)
                     {
-                        return new ValueTask<int>(Task.FromException<int>(new ObjectDisposedException(nameof(Http2ReadStream))));
+                        return new ValueTask<int>(Task.FromException<int>(ExceptionDispatchInfo.SetCurrentStackTrace(new ObjectDisposedException(nameof(Http2ReadStream)))));
                     }
 
                     if (cancellationToken.IsCancellationRequested)
index 87c260f..05ec6f4 100644 (file)
@@ -3,6 +3,7 @@
 // See the LICENSE file in the project root for more information.
 
 using System.IO;
+using System.Runtime.ExceptionServices;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -175,7 +176,7 @@ namespace System.Net.Http
                 HttpConnection connection = _connection;
                 if (connection == null)
                 {
-                    return new ValueTask(Task.FromException(new IOException(SR.ObjectDisposed_StreamClosed)));
+                    return new ValueTask(Task.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(new IOException(SR.ObjectDisposed_StreamClosed))));
                 }
 
                 if (buffer.Length == 0)
index 576043d..b154aab 100644 (file)
@@ -3,6 +3,7 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Runtime.CompilerServices;
+using System.Runtime.ExceptionServices;
 using System.Runtime.InteropServices;
 using System.Net.Sockets;
 using System.Threading;
@@ -199,7 +200,7 @@ namespace System.Net
                 }
                 else
                 {
-                    state.SetResult(new SocketException((int)errorCode));
+                    state.SetResult(ExceptionDispatchInfo.SetCurrentStackTrace(new SocketException((int)errorCode)));
                 }
             }
             finally
index 1d27660..c7478f2 100644 (file)
@@ -989,7 +989,7 @@ namespace System.Net
                     {
                         if (sEx.SocketErrorCode == SocketError.TimedOut)
                         {
-                            SetException(new WebException(SR.net_timeout, WebExceptionStatus.Timeout));
+                            SetException(ExceptionDispatchInfo.SetCurrentStackTrace(new WebException(SR.net_timeout, WebExceptionStatus.Timeout)));
                         }
                     }
                 }
index e29252f..9403b2d 100644 (file)
@@ -200,7 +200,8 @@ namespace System.Net.Security
             {
                 if (_queuedReadCount + count > MaxQueuedReadBytes)
                 {
-                    return new IOException(SR.Format(SR.net_auth_ignored_reauth, MaxQueuedReadBytes.ToString(NumberFormatInfo.CurrentInfo)));
+                    return ExceptionDispatchInfo.SetCurrentStackTrace(
+                        new IOException(SR.Format(SR.net_auth_ignored_reauth, MaxQueuedReadBytes.ToString(NumberFormatInfo.CurrentInfo))));
                 }
 
                 if (count != 0)
@@ -646,7 +647,8 @@ namespace System.Net.Security
                 {
                     // Fail re-handshake.
                     ProtocolToken message = new ProtocolToken(null, status);
-                    StartSendAuthResetSignal(null, asyncRequest, ExceptionDispatchInfo.Capture(new AuthenticationException(SR.net_auth_SSPI, message.GetException())));
+                    StartSendAuthResetSignal(null, asyncRequest, ExceptionDispatchInfo.Capture(
+                        ExceptionDispatchInfo.SetCurrentStackTrace(new AuthenticationException(SR.net_auth_SSPI, message.GetException()))));
                     return;
                 }
 
@@ -1208,7 +1210,7 @@ namespace System.Net.Security
                 // Re-handshake status is not supported.
                 ArrayPool<byte>.Shared.Return(rentedBuffer);
                 ProtocolToken message = new ProtocolToken(null, status);
-                return new ValueTask(Task.FromException(new IOException(SR.net_io_encrypt, message.GetException())));
+                return new ValueTask(Task.FromException(ExceptionDispatchInfo.SetCurrentStackTrace(new IOException(SR.net_io_encrypt, message.GetException()))));
             }
 
             ValueTask t = writeAdapter.WriteAsync(outBuffer, 0, encryptedBytes);
index 72b85f3..1dc7680 100644 (file)
@@ -7,6 +7,7 @@ using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
 using System.Runtime.CompilerServices;
+using System.Runtime.ExceptionServices;
 using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading.Tasks;
@@ -635,7 +636,7 @@ namespace System.Net.Sockets
         /// <summary>Gets a SocketException or an IOException wrapping a SocketException for the specified error.</summary>
         private static Exception GetException(SocketError error, bool wrapExceptionsInIOExceptions = false)
         {
-            Exception e = new SocketException((int)error);
+            Exception e = ExceptionDispatchInfo.SetCurrentStackTrace(new SocketException((int)error));
             return wrapExceptionsInIOExceptions ?
                 new IOException(SR.Format(SR.net_io_readwritefailure, e.Message), e) :
                 e;
@@ -1107,15 +1108,21 @@ namespace System.Net.Sockets
                     cancellationToken.ThrowIfCancellationRequested();
                 }
 
-                throw CreateException(error);
+                throw CreateException(error, forAsyncThrow: false);
             }
 
-            private Exception CreateException(SocketError error)
+            private Exception CreateException(SocketError error, bool forAsyncThrow = true)
             {
-                var se = new SocketException((int)error);
+                Exception e = new SocketException((int)error);
+
+                if (forAsyncThrow)
+                {
+                    e = ExceptionDispatchInfo.SetCurrentStackTrace(e);
+                }
+
                 return WrapExceptionsInIOExceptions ? (Exception)
-                    new IOException(SR.Format(SR.net_io_readfailure, se.Message), se) :
-                    se;
+                    new IOException(SR.Format(SR.net_io_readfailure, e.Message), e) :
+                    e;
             }
         }
     }
index e36732f..117dc3c 100644 (file)
@@ -7054,6 +7054,7 @@ namespace System.Runtime.ExceptionServices
         internal ExceptionDispatchInfo() { }
         public System.Exception SourceException { get { throw null; } }
         public static System.Runtime.ExceptionServices.ExceptionDispatchInfo Capture(System.Exception source) { throw null; }
+        public static System.Exception SetCurrentStackTrace(System.Exception source) { throw null; }
         [System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute]
         public void Throw() { }
         [System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute]
index 17bd10d..f9b18bf 100644 (file)
@@ -2,6 +2,8 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
 using System.Text.RegularExpressions;
 using Xunit;
 
@@ -26,5 +28,46 @@ namespace System.Runtime.ExceptionServices.Tests
                 Assert.Equal(i, Regex.Matches(e.StackTrace, RethrowMessageSubstring).Count);
             }
         }
+
+        [Fact]
+        public static void SetCurrentStackTrace_Invalid_Throws()
+        {
+            Exception e;
+
+            // Null argument
+            e = null;
+            AssertExtensions.Throws<ArgumentNullException>("source", () => ExceptionDispatchInfo.SetCurrentStackTrace(e));
+
+            // Previously set current stack
+            e = new Exception();
+            ExceptionDispatchInfo.SetCurrentStackTrace(e);
+            Assert.Throws<InvalidOperationException>(() => ExceptionDispatchInfo.SetCurrentStackTrace(e));
+
+            // Previously thrown
+            e = new Exception();
+            try { throw e; } catch { }
+            Assert.Throws<InvalidOperationException>(() => ExceptionDispatchInfo.SetCurrentStackTrace(e));
+        }
+
+        [Fact]
+        public static void SetCurrentStackTrace_IncludedInExceptionStackTrace()
+        {
+            Exception e;
+
+            e = new Exception();
+            ABCDEFGHIJKLMNOPQRSTUVWXYZ(e);
+            Assert.Contains(nameof(ABCDEFGHIJKLMNOPQRSTUVWXYZ), e.StackTrace);
+
+            e = new Exception();
+            ABCDEFGHIJKLMNOPQRSTUVWXYZ(e);
+            try { throw e; } catch { }
+            Assert.Contains(nameof(ABCDEFGHIJKLMNOPQRSTUVWXYZ), e.StackTrace);
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
+        private static void ABCDEFGHIJKLMNOPQRSTUVWXYZ(Exception e)
+        {
+            Assert.Same(e, ExceptionDispatchInfo.SetCurrentStackTrace(e));
+        }
     }
 }