Skip to content

Commit d4a2fa1

Browse files
khellangdavidfowl
authored andcommitted
Handle exceptions thrown by PEReader (#14612)
* Catch and log exceptions from PortablePdbReader.PopulateStackFrame
1 parent f31ce2d commit d4a2fa1

File tree

9 files changed

+96
-28
lines changed

9 files changed

+96
-28
lines changed

src/Hosting/Hosting/src/GenericHost/GenericWebHostedService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ private RequestDelegate BuildErrorPageApplication(Exception exception)
173173
{
174174
var exceptionDetailProvider = new ExceptionDetailsProvider(
175175
HostingEnvironment.ContentRootFileProvider,
176+
Logger,
176177
sourceCodeLineCount: 6);
177178

178179
model.ErrorDetails = exceptionDetailProvider.GetDetails(exception);

src/Hosting/Hosting/src/Internal/WebHost.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ private RequestDelegate BuildApplication()
270270
{
271271
var exceptionDetailProvider = new ExceptionDetailsProvider(
272272
hostingEnv.ContentRootFileProvider,
273+
logger,
273274
sourceCodeLineCount: 6);
274275

275276
model.ErrorDetails = exceptionDetailProvider.GetDetails(ex);

src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddleware.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public DeveloperExceptionPageMiddleware(
7272
_logger = loggerFactory.CreateLogger<DeveloperExceptionPageMiddleware>();
7373
_fileProvider = _options.FileProvider ?? hostingEnvironment.ContentRootFileProvider;
7474
_diagnosticSource = diagnosticSource;
75-
_exceptionDetailsProvider = new ExceptionDetailsProvider(_fileProvider, _options.SourceCodeLineCount);
75+
_exceptionDetailsProvider = new ExceptionDetailsProvider(_fileProvider, _logger, _options.SourceCodeLineCount);
7676
_exceptionHandler = DisplayException;
7777

7878
foreach (var filter in filters.Reverse())

src/Middleware/Diagnostics/test/UnitTests/ExceptionDetailsProviderTest.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public void DisplaysSourceCodeLines_ForAbsolutePaths(string absoluteFilePath)
6666
using (var provider = new PhysicalFileProvider(rootPath))
6767
{
6868
// Act
69-
var exceptionDetailProvider = new ExceptionDetailsProvider(provider, sourceCodeLineCount: 6);
69+
var exceptionDetailProvider = new ExceptionDetailsProvider(provider, logger: null, sourceCodeLineCount: 6);
7070
var stackFrame = exceptionDetailProvider.GetStackFrameSourceCodeInfo(
7171
"func1",
7272
absoluteFilePath,
@@ -90,7 +90,7 @@ public void DisplaysSourceCodeLines_ForRelativePaths(string relativePath)
9090
using (var provider = new PhysicalFileProvider(rootPath))
9191
{
9292
// Act
93-
var exceptionDetailProvider = new ExceptionDetailsProvider(provider, sourceCodeLineCount: 6);
93+
var exceptionDetailProvider = new ExceptionDetailsProvider(provider, logger: null, sourceCodeLineCount: 6);
9494
var stackFrame = exceptionDetailProvider.GetStackFrameSourceCodeInfo(
9595
"func1",
9696
relativePath,
@@ -116,7 +116,7 @@ public void DisplaysSourceCodeLines_ForRelativeEmbeddedPaths(string relativePath
116116
baseNamespace: $"{typeof(ExceptionDetailsProviderTest).GetTypeInfo().Assembly.GetName().Name}.Resources");
117117

118118
// Act
119-
var exceptionDetailProvider = new ExceptionDetailsProvider(provider, sourceCodeLineCount: 6);
119+
var exceptionDetailProvider = new ExceptionDetailsProvider(provider, logger: null, sourceCodeLineCount: 6);
120120
var stackFrame = exceptionDetailProvider.GetStackFrameSourceCodeInfo(
121121
"func1",
122122
relativePath,
@@ -259,7 +259,8 @@ public void DisplaysSourceCodeLines_PreAndPostErrorLine(ErrorData errorData)
259259
// Act
260260
var exceptionDetailProvider = new ExceptionDetailsProvider(
261261
new PhysicalFileProvider(Directory.GetCurrentDirectory()),
262-
sourceCodeLineCount: 6);
262+
logger: null,
263+
sourceCodeLineCount: 6);
263264

264265
exceptionDetailProvider.ReadFrameContent(
265266
stackFrame,

src/Servers/IIS/IIS/src/StartupHook.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ public static void Initialize()
8181

8282
var exceptionDetailProvider = new ExceptionDetailsProvider(
8383
new PhysicalFileProvider(contentRoot),
84+
logger: null,
8485
sourceCodeLineCount: 6);
8586

8687
// The startup hook is only present when detailed errors are allowed, so

src/Shared/StackTrace/ExceptionDetails/ExceptionDetailsProvider.cs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,20 @@
77
using System.Linq;
88
using System.Reflection;
99
using Microsoft.Extensions.FileProviders;
10+
using Microsoft.Extensions.Logging;
1011

1112
namespace Microsoft.Extensions.StackTrace.Sources
1213
{
1314
internal class ExceptionDetailsProvider
1415
{
1516
private readonly IFileProvider _fileProvider;
17+
private readonly ILogger _logger;
1618
private readonly int _sourceCodeLineCount;
1719

18-
public ExceptionDetailsProvider(IFileProvider fileProvider, int sourceCodeLineCount)
20+
public ExceptionDetailsProvider(IFileProvider fileProvider, ILogger logger, int sourceCodeLineCount)
1921
{
2022
_fileProvider = fileProvider;
23+
_logger = logger;
2124
_sourceCodeLineCount = sourceCodeLineCount;
2225
}
2326

@@ -30,15 +33,27 @@ public IEnumerable<ExceptionDetails> GetDetails(Exception exception)
3033
yield return new ExceptionDetails
3134
{
3235
Error = ex,
33-
StackFrames = StackTraceHelper.GetFrames(ex)
34-
.Select(frame => GetStackFrameSourceCodeInfo(
35-
frame.MethodDisplayInfo.ToString(),
36-
frame.FilePath,
37-
frame.LineNumber))
36+
StackFrames = GetStackFrames(ex),
3837
};
3938
}
4039
}
4140

41+
private IEnumerable<StackFrameSourceCodeInfo> GetStackFrames(Exception original)
42+
{
43+
var stackFrames = StackTraceHelper.GetFrames(original, out var exception)
44+
.Select(frame => GetStackFrameSourceCodeInfo(
45+
frame.MethodDisplayInfo.ToString(),
46+
frame.FilePath,
47+
frame.LineNumber));
48+
49+
if (exception != null)
50+
{
51+
_logger?.FailedToReadStackTraceInfo(exception);
52+
}
53+
54+
return stackFrames;
55+
}
56+
4257
private static IEnumerable<Exception> FlattenAndReverseExceptionTree(Exception ex)
4358
{
4459
// ReflectionTypeLoadException is special because the details are in
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System;
5+
using Microsoft.Extensions.Logging;
6+
7+
namespace Microsoft.Extensions.StackTrace.Sources
8+
{
9+
internal static class LoggerExtensions
10+
{
11+
private static readonly Action<ILogger, Exception> _failedToReadStackFrameInfo;
12+
13+
static LoggerExtensions()
14+
{
15+
_failedToReadStackFrameInfo = LoggerMessage.Define(
16+
logLevel: LogLevel.Debug,
17+
eventId: new EventId(0, "FailedToReadStackTraceInfo"),
18+
formatString: "Failed to read stack trace information for exception.");
19+
}
20+
21+
public static void FailedToReadStackTraceInfo(this ILogger logger, Exception exception)
22+
{
23+
_failedToReadStackFrameInfo(logger, exception);
24+
}
25+
}
26+
}

src/Shared/StackTrace/StackFrame/StackTraceHelper.cs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ namespace Microsoft.Extensions.StackTrace.Sources
1515
{
1616
internal class StackTraceHelper
1717
{
18-
public static IList<StackFrameInfo> GetFrames(Exception exception)
18+
public static IList<StackFrameInfo> GetFrames(Exception exception, out AggregateException error)
1919
{
2020
var frames = new List<StackFrameInfo>();
2121

2222
if (exception == null)
2323
{
24+
error = default;
2425
return frames;
2526
}
2627

@@ -32,9 +33,12 @@ public static IList<StackFrameInfo> GetFrames(Exception exception)
3233

3334
if (stackFrames == null)
3435
{
36+
error = default;
3537
return frames;
3638
}
3739

40+
List<Exception> exceptions = null;
41+
3842
for (var i = 0; i < stackFrames.Length; i++)
3943
{
4044
var frame = stackFrames[i];
@@ -56,14 +60,33 @@ public static IList<StackFrameInfo> GetFrames(Exception exception)
5660

5761
if (string.IsNullOrEmpty(stackFrame.FilePath))
5862
{
59-
// .NET Framework and older versions of mono don't support portable PDBs
60-
// so we read it manually to get file name and line information
61-
portablePdbReader.PopulateStackFrame(stackFrame, method, frame.GetILOffset());
63+
try
64+
{
65+
// .NET Framework and older versions of mono don't support portable PDBs
66+
// so we read it manually to get file name and line information
67+
portablePdbReader.PopulateStackFrame(stackFrame, method, frame.GetILOffset());
68+
}
69+
catch (Exception ex)
70+
{
71+
if (exceptions is null)
72+
{
73+
exceptions = new List<Exception>();
74+
}
75+
76+
exceptions.Add(ex);
77+
}
6278
}
6379

6480
frames.Add(stackFrame);
6581
}
6682

83+
if (exceptions != null)
84+
{
85+
error = new AggregateException(exceptions);
86+
return frames;
87+
}
88+
89+
error = default;
6790
return frames;
6891
}
6992
}

src/Shared/test/Shared.Tests/StackTraceHelperTest.cs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public void StackTraceHelper_IncludesLineNumbersForFiles()
3333
}
3434

3535
// Act
36-
var stackFrames = StackTraceHelper.GetFrames(exception);
36+
var stackFrames = StackTraceHelper.GetFrames(exception, out _);
3737

3838
// Assert
3939
Assert.Collection(stackFrames,
@@ -55,7 +55,7 @@ public void StackTraceHelper_PrettyPrintsStackTraceForGenericMethods()
5555
var exception = Record.Exception(() => GenericMethod<string>(null));
5656

5757
// Act
58-
var stackFrames = StackTraceHelper.GetFrames(exception);
58+
var stackFrames = StackTraceHelper.GetFrames(exception, out _);
5959

6060
// Assert
6161
var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray();
@@ -69,7 +69,7 @@ public void StackTraceHelper_PrettyPrintsStackTraceForMethodsWithOutParameters()
6969
var exception = Record.Exception(() => MethodWithOutParameter(out var value));
7070

7171
// Act
72-
var stackFrames = StackTraceHelper.GetFrames(exception);
72+
var stackFrames = StackTraceHelper.GetFrames(exception, out _);
7373

7474
// Assert
7575
var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray();
@@ -83,7 +83,7 @@ public void StackTraceHelper_PrettyPrintsStackTraceForMethodsWithGenericOutParam
8383
var exception = Record.Exception(() => MethodWithGenericOutParameter("Test", out int value));
8484

8585
// Act
86-
var stackFrames = StackTraceHelper.GetFrames(exception);
86+
var stackFrames = StackTraceHelper.GetFrames(exception, out _);
8787

8888
// Assert
8989
var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray();
@@ -98,7 +98,7 @@ public void StackTraceHelper_PrettyPrintsStackTraceForMethodsWithRefParameters()
9898
var exception = Record.Exception(() => MethodWithRefParameter(ref value));
9999

100100
// Act
101-
var stackFrames = StackTraceHelper.GetFrames(exception);
101+
var stackFrames = StackTraceHelper.GetFrames(exception, out _);
102102

103103
// Assert
104104
var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray();
@@ -113,7 +113,7 @@ public void StackTraceHelper_PrettyPrintsStackTraceForMethodsWithGenericRefParam
113113
var exception = Record.Exception(() => MethodWithGenericRefParameter(ref value));
114114

115115
// Act
116-
var stackFrames = StackTraceHelper.GetFrames(exception);
116+
var stackFrames = StackTraceHelper.GetFrames(exception, out _);
117117

118118
// Assert
119119
var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray();
@@ -128,7 +128,7 @@ public void StackTraceHelper_PrettyPrintsStackTraceForMethodsWithNullableParamet
128128
var exception = Record.Exception(() => MethodWithNullableParameter(value));
129129

130130
// Act
131-
var stackFrames = StackTraceHelper.GetFrames(exception);
131+
var stackFrames = StackTraceHelper.GetFrames(exception, out _);
132132

133133
// Assert
134134
var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray();
@@ -142,7 +142,7 @@ public void StackTraceHelper_PrettyPrintsStackTraceForMethodsOnGenericTypes()
142142
var exception = Record.Exception(() => new GenericClass<int>().Throw(0));
143143

144144
// Act
145-
var stackFrames = StackTraceHelper.GetFrames(exception);
145+
var stackFrames = StackTraceHelper.GetFrames(exception, out _);
146146

147147
// Assert
148148
var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray();
@@ -175,7 +175,7 @@ public void StackTraceHelper_ProducesReadableOutput()
175175
}
176176

177177
// Act
178-
var stackFrames = StackTraceHelper.GetFrames(exception);
178+
var stackFrames = StackTraceHelper.GetFrames(exception, out _);
179179
var methodNames = stackFrames.Select(stackFrame => stackFrame.MethodDisplayInfo.ToString()).ToArray();
180180

181181
// Assert
@@ -189,7 +189,7 @@ public void StackTraceHelper_DoesNotIncludeInstanceMethodsOnTypesWithStackTraceH
189189
var exception = Record.Exception(() => InvokeMethodOnTypeWithStackTraceHiddenAttribute());
190190

191191
// Act
192-
var stackFrames = StackTraceHelper.GetFrames(exception);
192+
var stackFrames = StackTraceHelper.GetFrames(exception, out _);
193193

194194
// Assert
195195
var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray();
@@ -204,7 +204,7 @@ public void StackTraceHelper_DoesNotIncludeStaticMethodsOnTypesWithStackTraceHid
204204
var exception = Record.Exception(() => InvokeStaticMethodOnTypeWithStackTraceHiddenAttribute());
205205

206206
// Act
207-
var stackFrames = StackTraceHelper.GetFrames(exception);
207+
var stackFrames = StackTraceHelper.GetFrames(exception, out _);
208208

209209
// Assert
210210
var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray();
@@ -219,7 +219,7 @@ public void StackTraceHelper_DoesNotIncludeMethodsWithStackTraceHiddenAttribute(
219219
var exception = Record.Exception(() => new TypeWithMethodWithStackTraceHiddenAttribute().Throw());
220220

221221
// Act
222-
var stackFrames = StackTraceHelper.GetFrames(exception);
222+
var stackFrames = StackTraceHelper.GetFrames(exception, out _);
223223

224224
// Assert
225225
var methods = stackFrames.Select(frame => frame.MethodDisplayInfo.ToString()).ToArray();
@@ -237,7 +237,7 @@ public void GetFrames_DoesNotFailForDynamicallyGeneratedAssemblies()
237237
var exception = Record.Exception(action);
238238

239239
// Act
240-
var frames = StackTraceHelper.GetFrames(exception).ToArray();
240+
var frames = StackTraceHelper.GetFrames(exception, out _).ToArray();
241241

242242
// Assert
243243
var frame = frames[0];

0 commit comments

Comments
 (0)