Improve StackTraceHiddenAttribute handling (#83)

* Add .NET Core 2.1 as target for tests to allow testing for StackTraceHiddenAttribute handling

* Customize EnhancedStackTrace "hidden" frames selection strategy depending on the runtime, and optimize attribute access for non-reflection-only assemblies

* Add .NET Core 2.1 as target for benchmarks to allow benchmarking for it
This commit is contained in:
Aristarkh Zagorodnikov 2019-02-10 23:50:03 +03:00 committed by Ben Adams
parent 8604340a0e
commit a9830f38e3
3 changed files with 78 additions and 53 deletions

View File

@ -19,6 +19,8 @@ namespace System.Diagnostics
{ {
public partial class EnhancedStackTrace public partial class EnhancedStackTrace
{ {
private static readonly Type StackTraceHiddenAttibuteType = Type.GetType("System.Diagnostics.StackTraceHiddenAttribute", false);
private static List<EnhancedStackFrame> GetFrames(Exception exception) private static List<EnhancedStackFrame> GetFrames(Exception exception)
{ {
if (exception == null) if (exception == null)
@ -645,60 +647,59 @@ namespace System.Diagnostics
private static bool ShowInStackTrace(MethodBase method) private static bool ShowInStackTrace(MethodBase method)
{ {
Debug.Assert(method != null); Debug.Assert(method != null);
try var type = method.DeclaringType;
if (type == typeof(Task<>) && method.Name == "InnerInvoke")
{ {
var type = method.DeclaringType; return false;
if (type == typeof(Task<>) && method.Name == "InnerInvoke") }
if (type == typeof(Task))
{
switch (method.Name)
{
case "ExecuteWithThreadLocal":
case "Execute":
case "ExecutionContextCallback":
case "ExecuteEntry":
case "InnerInvoke":
return false;
}
}
if (type == typeof(ExecutionContext))
{
switch (method.Name)
{
case "RunInternal":
case "Run":
return false;
}
}
if (StackTraceHiddenAttibuteType != null)
{
// Don't show any methods marked with the StackTraceHiddenAttribute
// https://github.com/dotnet/coreclr/pull/14652
if (IsStackTraceHidden(method))
{ {
return false; return false;
} }
if (type == typeof(Task)) }
{
switch (method.Name)
{
case "ExecuteWithThreadLocal":
case "Execute":
case "ExecutionContextCallback":
case "ExecuteEntry":
case "InnerInvoke":
return false;
}
}
if (type == typeof(ExecutionContext))
{
switch (method.Name)
{
case "RunInternal":
case "Run":
return false;
}
}
// Don't show any methods marked with the StackTraceHiddenAttribute if (type == null)
{
return true;
}
if (StackTraceHiddenAttibuteType != null)
{
// Don't show any types marked with the StackTraceHiddenAttribute
// https://github.com/dotnet/coreclr/pull/14652 // https://github.com/dotnet/coreclr/pull/14652
foreach (var attibute in EnumerableIList.Create(method.GetCustomAttributesData())) if (IsStackTraceHidden(type))
{ {
// internal Attribute, match on name return false;
if (attibute.AttributeType.Name == "StackTraceHiddenAttribute")
{
return false;
}
} }
}
if (type == null) else
{ {
return true;
}
foreach (var attibute in EnumerableIList.Create(type.GetCustomAttributesData()))
{
// internal Attribute, match on name
if (attibute.AttributeType.Name == "StackTraceHiddenAttribute")
{
return false;
}
}
// Fallbacks for runtime pre-StackTraceHiddenAttribute // Fallbacks for runtime pre-StackTraceHiddenAttribute
if (type == typeof(ExceptionDispatchInfo) && method.Name == "Throw") if (type == typeof(ExceptionDispatchInfo) && method.Name == "Throw")
{ {
@ -723,15 +724,39 @@ namespace System.Diagnostics
return false; return false;
} }
} }
catch
{
// GetCustomAttributesData can throw
return true;
}
return true; return true;
} }
private static bool IsStackTraceHidden(MemberInfo memberInfo)
{
if (!memberInfo.Module.Assembly.ReflectionOnly)
{
return memberInfo.GetCustomAttributes(StackTraceHiddenAttibuteType, false).Length != 0;
}
EnumerableIList<CustomAttributeData> attributes;
try
{
attributes = EnumerableIList.Create(memberInfo.GetCustomAttributesData());
}
catch (NotImplementedException)
{
return false;
}
foreach (var attribute in attributes)
{
// reflection-only attribute, match on name
if (attribute.AttributeType.FullName == StackTraceHiddenAttibuteType.FullName)
{
return true;
}
}
return false;
}
private static bool TryResolveStateMachineMethod(ref MethodBase method, out Type declaringType) private static bool TryResolveStateMachineMethod(ref MethodBase method, out Type declaringType)
{ {
Debug.Assert(method != null); Debug.Assert(method != null);

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0"> <Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netcoreapp2.0;net462</TargetFrameworks> <TargetFrameworks>netcoreapp2.1;netcoreapp2.0;net462</TargetFrameworks>
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
</PropertyGroup> </PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks> <TargetFrameworks>netcoreapp2.1;netcoreapp2.0;net46</TargetFrameworks>
<SignAssembly>true</SignAssembly> <SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\..\src\Ben.Demystifier\key.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>..\..\src\Ben.Demystifier\key.snk</AssemblyOriginatorKeyFile>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>