可以信任 AccessViolationException 的 Stacktrace
Can the Stacktrace of an AccessViolationException be trusted
我们的一项服务中抛出了 AccessViolationException。我们注册了 AppDomain.CurrentDomain.UnhandledException
并且从事件中我们得到了调用堆栈。该事件在 2 秒内在三个不同的线程上被引发了三次,并且具有完全相同的堆栈。所以一切都应该清楚
另一方面 - windows 事件日志中的相关日志条目根本没有显示任何堆栈。我们的应用程序也使用非托管库,我的猜测是异常是由滥用它们(例如 oci)而不是所示的托管堆栈引起的。
我能否相信所报告的堆栈是导致问题的堆栈 - 或者这只是一个有根据的猜测?
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at System.Linq.EnumerableSorter`2.ComputeKeys(TElement[] elements, Int32 count)
at System.Linq.EnumerableSorter`1.Sort(TElement[] elements, Int32 count)
at System.Linq.OrderedEnumerable`1.<GetEnumerator>d__0.MoveNext()
at System.Linq.Enumerable.<TakeIterator>d__3a`1.MoveNext()
at System.Data.Services.QueryResultInfo.MoveNext()
at System.Data.Services.DataService`1.SerializeResponseBody(RequestDescription description, IDataService dataService, IODataResponseMessage responseMessage)
at System.Data.Services.DataService`1.HandleRequest()
at System.Data.Services.DataService`1.ProcessRequestForMessage(Stream messageBody)
at SyncInvokeProcessRequestForMessage(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(RequestContext request, Boolean cleanThread, OperationContext currentOperationContext)
at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(RequestContext request, OperationContext currentOperationContext)
at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(IAsyncResult result)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
at System.Runtime.InputQueue`1.AsyncQueueReader.Set(Item item)
at System.Runtime.InputQueue`1.EnqueueAndDispatch(Item item, Boolean canDispatchOnThisThread)
at System.Runtime.InputQueue`1.EnqueueAndDispatch(T item, Action dequeuedCallback, Boolean canDispatchOnThisThread)
at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue(QueueItemType item, Action dequeuedCallback, Boolean canDispatchOnThisThread)
at System.ServiceModel.Channels.HttpPipeline.EnqueueMessageAsyncResult.CompleteParseAndEnqueue(IAsyncResult result)
at System.ServiceModel.Channels.HttpPipeline.EnqueueMessageAsyncResult.HandleParseIncomingMessage(IAsyncResult result)
at System.Runtime.AsyncResult.SyncContinue(IAsyncResult result)
at System.ServiceModel.Channels.HttpPipeline.EmptyHttpPipeline.BeginProcessInboundRequest(ReplyChannelAcceptor replyChannelAcceptor, Action dequeuedCallback, AsyncCallback callback, Object state)
at System.ServiceModel.Channels.HttpChannelListener`1.HttpContextReceivedAsyncResult`1.ProcessHttpContextAsync()
at System.ServiceModel.Channels.HttpChannelListener`1.BeginHttpContextReceived(HttpRequestContext context, Action acceptorCallback, AsyncCallback callback, Object state)
at System.ServiceModel.Channels.SharedHttpTransportManager.EnqueueContext(IAsyncResult listenerContextResult)
at System.ServiceModel.Channels.SharedHttpTransportManager.OnGetContextCore(IAsyncResult listenerContextResult)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.ListenerAsyncResult.IOCompleted(ListenerAsyncResult asyncResult, UInt32 errorCode, UInt32 numBytes)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
作为备注:从 windows 事件日志中的异常代码猜测我认为它是 "real" windows AccessViolationException (0xc000005) 而不是 throw new AccessViolationException
(0xe043452)
AccessViolationException 的堆栈跟踪是否指示对访问冲突负责的代码?答案是否.
它仅显示哪个调用检测到访问冲突。随后的调用将失败,实际上整个应用程序将终止,因为 AccessViolationException
不是 catchable by default and you should not catch it。
这意味着内存已被其中一些(并非详尽列表)损坏:
- 非托管依赖项的错误使用
- GCHandle 使用不当
- 错误的不安全代码
您对非托管依赖项的潜在滥用的猜测可能是 AccessViolationException 的根本原因。
请记住,内存损坏不是确定性的:即使发生,运行时也不一定总能检测到。
下面的代码是在Console.WriteLine()
中获取AccessViolationException
的一种方法。但是它也可以提高 ExecutionEngineException
.
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
Thread.CurrentThread.Name = "Main";
ThreadPool.QueueUserWorkItem(Corrupt, Thread.CurrentThread);
ThreadPool.QueueUserWorkItem(RunMethod);
Console.ReadLine();
}
private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine(e.ExceptionObject);
}
private static void Corrupt(object state)
{
unsafe
{
var thread = (Thread)state;
fixed (char* str = thread.Name)
{
char* increment = str;
char* decrement = str;
while (true)
{
*(decrement--) = 'f';
*(increment++) = 'b';
Thread.Sleep(10);
}
}
}
}
[HandleProcessCorruptedStateExceptions ]
public static void RunMethod(object state)
{
try
{
while (true)
{
Console.WriteLine("I'm Alive");
Thread.Sleep(5000);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
堆栈跟踪顶部方法的源代码是 readily available。您可以判断哪个特定语句最有可能导致崩溃:
keys = new TKey[count];
这会引发您在堆栈跟踪中看不到的代码,您只会得到托管代码堆栈帧的转储。所以,是的,它是可靠的,AVE 是由处理器抛出的 "hard",它只是没有向您显示所有内容。
您需要崩溃进程的小型转储才能查看更多信息。并不是说这实际上对您有任何帮助,当然崩溃的代码不对崩溃负责。它也不是那种重复出现的崩溃,对代码进行小的更改或让它处理不同的数据,它很可能是另一个新的运算符调用失败。
Our application uses unmanaged libraries as well
这使我不必解释寻找可能损坏 GC 堆的非托管代码。不要指望在下个月左右完成任何事情,抱歉。
我们的一项服务中抛出了 AccessViolationException。我们注册了 AppDomain.CurrentDomain.UnhandledException
并且从事件中我们得到了调用堆栈。该事件在 2 秒内在三个不同的线程上被引发了三次,并且具有完全相同的堆栈。所以一切都应该清楚
另一方面 - windows 事件日志中的相关日志条目根本没有显示任何堆栈。我们的应用程序也使用非托管库,我的猜测是异常是由滥用它们(例如 oci)而不是所示的托管堆栈引起的。
我能否相信所报告的堆栈是导致问题的堆栈 - 或者这只是一个有根据的猜测?
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at System.Linq.EnumerableSorter`2.ComputeKeys(TElement[] elements, Int32 count)
at System.Linq.EnumerableSorter`1.Sort(TElement[] elements, Int32 count)
at System.Linq.OrderedEnumerable`1.<GetEnumerator>d__0.MoveNext()
at System.Linq.Enumerable.<TakeIterator>d__3a`1.MoveNext()
at System.Data.Services.QueryResultInfo.MoveNext()
at System.Data.Services.DataService`1.SerializeResponseBody(RequestDescription description, IDataService dataService, IODataResponseMessage responseMessage)
at System.Data.Services.DataService`1.HandleRequest()
at System.Data.Services.DataService`1.ProcessRequestForMessage(Stream messageBody)
at SyncInvokeProcessRequestForMessage(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(RequestContext request, Boolean cleanThread, OperationContext currentOperationContext)
at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(RequestContext request, OperationContext currentOperationContext)
at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(IAsyncResult result)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
at System.Runtime.InputQueue`1.AsyncQueueReader.Set(Item item)
at System.Runtime.InputQueue`1.EnqueueAndDispatch(Item item, Boolean canDispatchOnThisThread)
at System.Runtime.InputQueue`1.EnqueueAndDispatch(T item, Action dequeuedCallback, Boolean canDispatchOnThisThread)
at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue(QueueItemType item, Action dequeuedCallback, Boolean canDispatchOnThisThread)
at System.ServiceModel.Channels.HttpPipeline.EnqueueMessageAsyncResult.CompleteParseAndEnqueue(IAsyncResult result)
at System.ServiceModel.Channels.HttpPipeline.EnqueueMessageAsyncResult.HandleParseIncomingMessage(IAsyncResult result)
at System.Runtime.AsyncResult.SyncContinue(IAsyncResult result)
at System.ServiceModel.Channels.HttpPipeline.EmptyHttpPipeline.BeginProcessInboundRequest(ReplyChannelAcceptor replyChannelAcceptor, Action dequeuedCallback, AsyncCallback callback, Object state)
at System.ServiceModel.Channels.HttpChannelListener`1.HttpContextReceivedAsyncResult`1.ProcessHttpContextAsync()
at System.ServiceModel.Channels.HttpChannelListener`1.BeginHttpContextReceived(HttpRequestContext context, Action acceptorCallback, AsyncCallback callback, Object state)
at System.ServiceModel.Channels.SharedHttpTransportManager.EnqueueContext(IAsyncResult listenerContextResult)
at System.ServiceModel.Channels.SharedHttpTransportManager.OnGetContextCore(IAsyncResult listenerContextResult)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.ListenerAsyncResult.IOCompleted(ListenerAsyncResult asyncResult, UInt32 errorCode, UInt32 numBytes)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
作为备注:从 windows 事件日志中的异常代码猜测我认为它是 "real" windows AccessViolationException (0xc000005) 而不是 throw new AccessViolationException
(0xe043452)
AccessViolationException 的堆栈跟踪是否指示对访问冲突负责的代码?答案是否.
它仅显示哪个调用检测到访问冲突。随后的调用将失败,实际上整个应用程序将终止,因为 AccessViolationException
不是 catchable by default and you should not catch it。
这意味着内存已被其中一些(并非详尽列表)损坏:
- 非托管依赖项的错误使用
- GCHandle 使用不当
- 错误的不安全代码
您对非托管依赖项的潜在滥用的猜测可能是 AccessViolationException 的根本原因。
请记住,内存损坏不是确定性的:即使发生,运行时也不一定总能检测到。
下面的代码是在Console.WriteLine()
中获取AccessViolationException
的一种方法。但是它也可以提高 ExecutionEngineException
.
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
Thread.CurrentThread.Name = "Main";
ThreadPool.QueueUserWorkItem(Corrupt, Thread.CurrentThread);
ThreadPool.QueueUserWorkItem(RunMethod);
Console.ReadLine();
}
private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine(e.ExceptionObject);
}
private static void Corrupt(object state)
{
unsafe
{
var thread = (Thread)state;
fixed (char* str = thread.Name)
{
char* increment = str;
char* decrement = str;
while (true)
{
*(decrement--) = 'f';
*(increment++) = 'b';
Thread.Sleep(10);
}
}
}
}
[HandleProcessCorruptedStateExceptions ]
public static void RunMethod(object state)
{
try
{
while (true)
{
Console.WriteLine("I'm Alive");
Thread.Sleep(5000);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
堆栈跟踪顶部方法的源代码是 readily available。您可以判断哪个特定语句最有可能导致崩溃:
keys = new TKey[count];
这会引发您在堆栈跟踪中看不到的代码,您只会得到托管代码堆栈帧的转储。所以,是的,它是可靠的,AVE 是由处理器抛出的 "hard",它只是没有向您显示所有内容。
您需要崩溃进程的小型转储才能查看更多信息。并不是说这实际上对您有任何帮助,当然崩溃的代码不对崩溃负责。它也不是那种重复出现的崩溃,对代码进行小的更改或让它处理不同的数据,它很可能是另一个新的运算符调用失败。
Our application uses unmanaged libraries as well
这使我不必解释寻找可能损坏 GC 堆的非托管代码。不要指望在下个月左右完成任何事情,抱歉。