Нарушение прав доступа при доступе к COM-объекту из.Net

Прошу прощения, если сообщение слишком длинное, но я был бы рад, если бы кто-нибудь хотя бы указал на полужирные заголовки и указал мне правильное направление. У меня есть эта проблема в течение нескольких дней, но не смог найти ответ в сети. Это то, что я узнал до сих пор.

1. Исключение "нарушение прав доступа" уничтожает мое управляемое приложение

Мое приложение C# WinForms иногда закрывается с исключением "Нарушение прав доступа" ("Попытка чтения или записи в защищенную память"), прямо в момент выбора TabPage в форме окна TabControl. Из трассировки стека (попробуй / поймай вокруг Application.Run) я вижу, что исключение происходит при System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)называется внутри UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData),

- Сообщение: попытка чтения или записи в защищенную память. Это часто указывает на то, что другая память повреждена.
- Трассировка стека: в System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) в System.Windows.Forms.Application.ComponentManager
      .System.Windows.Forms.UnsafeNativeMethods
      .IMsoComponentManager.FPushMessageLoopDjectDopImpDataIp32Imp32ImpDataDupDupDupDupIllPlayPlayPlayDirect_Imp32ImpLoopDirect_Imp32ImpLoopDirect_Imp32ImpDataDirect_Imp32ImpLoopDirect_Imp32ImpToopLoopDirect_Imp32ImpLoopDirectUp) в System.Windows.Forms.Application.ThreadContext
      .RunMessageLoopInner(причина Int32, контекст ApplicationContext) в System.Windows.Forms.Application.ThreadContext
      .RunMessageLoop(причина Int32, контекст ApplicationContext) в System.Windows.Forms.Application.Run(ApplicationContext context) в MyApp.Program.Main ()

2. Кажется, что неисправный модуль является COM-объектом (ChartFX Client Server 6.2)

Используя WinDbg (с загруженным SoS), я обнаружил его на неуправляемой стороне, внутри ChartFX.ClientServer.Core.dll (это компонент построения диаграмм COM, который мы используем):

(ca84.c98c): нарушение прав доступа - код c0000005 (первый шанс)
Исключения первого шанса сообщаются перед обработкой любого исключения.
Это исключение можно ожидать и обработать.
eax=00000000 ebx=06e67c38 ecx=06e67c38 edx=000018c6 esi=06e7df30 edi=317a9e80
eip=31666110 esp=0015e040 ebp=0015e08c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
ChartFX_ClientServer_Core Ordinal5507+0x97b7:
31666110 8a404d          mov     al,byt ptr [eax + 4Dh] ds: 0023: 0000004d =??

[edit:] Я также не смог получить информацию о неповрежденном стеке из WinDbg (там говорилось: "Информация о размотке стека недоступна"):

0: 000> кП
ChildEBP RetAddr  
ВНИМАНИЕ: информация о размотке стека недоступна. Следующие кадры могут быть неправильными.
0015e08c 3166288b ChartFX_ClientServer_Core!Ordinal5507+0x97b7
0015e394 3165a921 ChartFX_ClientServer_Core!Ordinal5507+0x5f32
0015e480 31678685 ChartFX_ClientServer_Core!Ordinal5496+0x26a
0015e568 3167bef4 ChartFX_ClientServer_Core!Ordinal5492+0x975
0015e668 316a356b ChartFX_ClientServer_Core!Ordinal5492+0x41e4
0015e77c 31709496 ChartFX_ClientServer_Core!Ordinal443+0x5745
0015e7d0 31707f70 ChartFX_ClientServer_Core!Ordinal2584+0x3cdc
0015e7f8 3170817d ChartFX_ClientServer_Core!Ordinal2584+0x27b6
0015e81c 3162fd76 ChartFX_ClientServer_Core!Ordinal2584+0x29c3
0015e86c 7719f8d2 ChartFX_ClientServer_Core!Ordinal899+0x6b6
0015e898 7719f794 USER32!GetMessageW+0x93
0015e910 771a06f6 USER32!GetWindowLongW+0x115
0015e940 771a069c ПОЛЬЗОВАТЕЛЬ32! CallWindowProcW + 0x75
0015e960 747fcef4 USER32! CallWindowProcW + 0x1b
0015e97c 747fd073 comctl32! Ordinal377 + 0x5c
0015e9e0 747fd027 comctl32! DefSubclassProc + 0x92
0015ea04 747fd4e6 comctl32! DefSubclassProc + 0x46
0015ea20 747fd073 comctl32! DefSubclassProc + 0x505
0015ea84 747fd118 comctl32! DefSubclassProc + 0x92
0015eae4 7719f8d2 comctl32! DefSubclassProc + 0x137

3. Воспроизвести ошибку нелегко (хотя ее можно спровоцировать менее чем за 5 минут)

У меня есть несколько экземпляров Chart на нескольких вкладках, и это обычно происходит во время переключения вкладок. Я до сих пор не знаю, как воспроизвести его, кроме переключения этих вкладок на несколько минут, прежде чем это произойдет, поэтому я не могу использовать наш контроль версий, чтобы надежно найти сборку, в которой не было этой проблемы. Я получаю доступ к диаграммам через управляемый класс-оболочку AxChart (производный от AxHost), который был автоматически создан дизайнером VS.

4. Каким должен быть мой следующий шаг?

Если бы кто-то мог указать мне на следующий шаг, который я должен сделать, чтобы найти истинную причину, я был бы очень благодарен. Экспериментирование (удаление и возврат кода) не приносит пользы, потому что я не знаю, как его воспроизвести, поэтому на каждую итерацию уйдет много времени, чтобы убедить себя, что ошибка все еще существует.

Я обнаружил, что люди часто предлагают что-то вроде "переключения оптимизации компилятора", но, поскольку исключение не выдается детерминистически, я не хочу просто переставлять некоторые байты и надеюсь, что оно никогда не вернется.

Заранее большое спасибо!

С наилучшими пожеланиями, Groo

3 ответа

Решение

Добавив множество следов журналов по всему коду, мне удалось заметить, что в некоторых случаях одно из свойств диаграммы превращается в Double.NaN. После этого приложение всегда зависало при следующей перерисовке диаграммы. Обрабатывая события Chart PrePaint и PostPaint (к счастью, у них есть эти события), я подтвердил, что сбой происходит прямо между этими двумя событиями.

В частности, это происходит только в том случае, если я установил масштаб графика до того, как он был нарисован в первый раз (впервые после последнего обновления). Мне удалось сделать это по-другому, и с тех пор он не разбился.

Я не очень доволен этим "решением", так как это, очевидно, какая-то внутренняя проблема, которая не может быть точно обнаружена до ее фактического сбоя, и я, возможно, только скрываю ее таким образом. Но я должен оставить все как есть, потому что иначе я теряю слишком много времени.

[Обновить]

Реплицированная ошибка успешно

Я выполнил быстрое тестовое приложение, в котором я дважды устанавливал свойства диаграммы, прежде чем она на самом деле была нарисована, и приложение сразу зависало. Я сообщил об ошибке в Software FX, но не получил ответа. Это не первая раздражающая ошибка, с которой я сталкиваюсь с этим элементом управления, но в следующем выпуске мы переключаемся на их управляемую (.Net) версию, поэтому, по крайней мере, у нас будет Reflector, чтобы выяснить, как устранить эти ошибки.

В любом случае спасибо всем!

Это очень похоже на проблему безопасности потоков.
Я бы посоветовал вам начать с прочтения документации по элементу управления, обращая особое внимание на упоминание безопасности потоков. Модель потоков, обычно используемая COM-компонентами, отличается - и часто несовместима - с (тривиальным) использованием.NET.

Был один из них некоторое время назад. Нашим примером был вызов PInvoke: OpenPrinter(string port);

Наша проблема заключалась в том, что управляемый код отправил: "LPT1:", но неуправляемый код объявил массив байтов [1024] и прочитал 1024 байта и далее с адреса строки. Это будет считывать за пределами выделенной строки ("LPT1:") и иногда попадать в память, которая не была выделена для приложения, вызывая это прерывистое исключение AccessViolationException.

Мы исправили это, изменив вызов на: OpenPrinter(int length, string port), чтобы неуправляемый код мог объявить байтовый массив, который был правильной длины.

В этом посте ctacke также есть некоторые полезные сведения о том, что может быть причиной этой проблемы.

Другие вопросы по тегам