/
githubmirror
/
aspnetcore
Обзор
Документация
Войти
/
githubmirror
/
aspnetcore
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Shared/StackTrace/StackFrame/StackTraceHelper.cs
263 строки
8 KB
Martin Costello
Fix metadata typos (#62771)
18 июл 2025, 21:49
Не верифицирован
18 июл 2025, 21:49
0791d1c
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using Microsoft.Extensions.Internal; #nullable enable namespace Microsoft.Extensions.StackTrace.Sources; internal sealed class StackTraceHelper { [UnconditionalSuppressMessage("Trimmer", "IL2026", Justification = "MethodInfo for a stack frame might be incomplete or removed. GetFrames does the best it can to provide frame details.")] public static IList<StackFrameInfo> GetFrames(Exception exception, out AggregateException? error) { if (exception == null) { error = default; return Array.Empty<StackFrameInfo>(); } var needFileInfo = true; var stackTrace = new System.Diagnostics.StackTrace(exception, needFileInfo); var stackFrames = stackTrace.GetFrames(); if (stackFrames == null) { error = default; return Array.Empty<StackFrameInfo>(); } var frames = new List<StackFrameInfo>(stackFrames.Length); List<Exception>? exceptions = null; for (var i = 0; i < stackFrames.Length; i++) { var frame = stackFrames[i]; var method = frame.GetMethod(); // MethodInfo should always be available for methods in the stack, but double check for null here. // Apps with trimming enabled may remove some metadata. Better to be safe than sorry. if (method == null) { continue; } // Always show last stackFrame if (!ShowInStackTrace(method) && i < stackFrames.Length - 1) { continue; } var stackFrame = new StackFrameInfo(frame.GetFileLineNumber(), frame.GetFileName(), frame, GetMethodDisplayString(method)); frames.Add(stackFrame); } if (exceptions != null) { error = new AggregateException(exceptions); return frames; } error = default; return frames; } internal static MethodDisplayInfo? GetMethodDisplayString(MethodBase? method) { // Special case: no method available if (method == null) { return null; } // Type name var type = method.DeclaringType; var methodName = method.Name; string? subMethod = null; if (type != null && type.IsDefined(typeof(CompilerGeneratedAttribute)) && (typeof(IAsyncStateMachine).IsAssignableFrom(type) || typeof(IEnumerator).IsAssignableFrom(type))) { // Convert StateMachine methods to correct overload +MoveNext() if (TryResolveStateMachineMethod(ref method, out type)) { subMethod = methodName; } } string? declaringTypeName = null; // ResolveStateMachineMethod may have set declaringType to null if (type != null) { declaringTypeName = TypeNameHelper.GetTypeDisplayName(type, includeGenericParameterNames: true); } string? genericArguments = null; if (method.IsGenericMethod) { genericArguments = "<" + string.Join(", ", method.GetGenericArguments() .Select(arg => TypeNameHelper.GetTypeDisplayName(arg, fullName: false, includeGenericParameterNames: true))) + ">"; } // Method parameters var parameters = method.GetParameters().Select(parameter => { var parameterType = parameter.ParameterType; var prefix = string.Empty; if (parameter.IsOut) { prefix = "out"; } else if (parameterType != null && parameterType.IsByRef) { prefix = "ref"; } var parameterTypeString = "?"; if (parameterType != null) { if (parameterType.IsByRef) { parameterType = parameterType.GetElementType(); } parameterTypeString = TypeNameHelper.GetTypeDisplayName(parameterType!, fullName: false, includeGenericParameterNames: true); } return new ParameterDisplayInfo { Prefix = prefix, Name = parameter.Name, Type = parameterTypeString, }; }); var methodDisplayInfo = new MethodDisplayInfo(declaringTypeName, method.Name, genericArguments, subMethod, parameters); return methodDisplayInfo; } private static bool ShowInStackTrace(MethodBase method) { // Don't show any methods marked with the StackTraceHiddenAttribute // https://github.com/dotnet/coreclr/pull/14652 if (HasStackTraceHiddenAttribute(method)) { return false; } var type = method.DeclaringType; if (type == null) { return true; } if (HasStackTraceHiddenAttribute(type)) { return false; } // Fallbacks for runtime pre-StackTraceHiddenAttribute if (type == typeof(ExceptionDispatchInfo) && method.Name == "Throw") { return false; } else if (type == typeof(TaskAwaiter) || type == typeof(TaskAwaiter<>) || type == typeof(ConfiguredTaskAwaitable.ConfiguredTaskAwaiter) || type == typeof(ConfiguredTaskAwaitable<>.ConfiguredTaskAwaiter)) { switch (method.Name) { case "HandleNonSuccessAndDebuggerNotification": case "ThrowForNonSuccess": case "ValidateEnd": case "GetResult": return false; } } return true; } [UnconditionalSuppressMessage("Trimmer", "IL2075", Justification = "Unable to require a method has all information on it to resolve state machine.")] private static bool TryResolveStateMachineMethod(ref MethodBase method, out Type? declaringType) { Debug.Assert(method != null); Debug.Assert(method.DeclaringType != null); declaringType = method.DeclaringType; var parentType = declaringType.DeclaringType; if (parentType == null) { return false; } var methods = parentType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly); if (methods == null) { return false; } foreach (var candidateMethod in methods) { var attributes = candidateMethod.GetCustomAttributes<StateMachineAttribute>(); if (attributes == null) { continue; } foreach (var asma in attributes) { if (asma.StateMachineType == declaringType) { method = candidateMethod; declaringType = candidateMethod.DeclaringType; // Mark the iterator as changed; so it gets the + annotation of the original method // async statemachines resolve directly to their builder methods so aren't marked as changed return asma is IteratorStateMachineAttribute; } } } return false; } private static bool HasStackTraceHiddenAttribute(MemberInfo memberInfo) { IList<CustomAttributeData> attributes; try { // Accessing MemberInfo.GetCustomAttributesData throws for some types (such as types in dynamically generated assemblies). // We'll skip looking up StackTraceHiddenAttributes on such types. attributes = memberInfo.GetCustomAttributesData(); } catch { return false; } for (var i = 0; i < attributes.Count; i++) { if (attributes[i].AttributeType.Name == "StackTraceHiddenAttribute") { return true; } } return false; } }