У меня есть большое приложение, которое недавно начало проявлять довольно странное поведение при работе в отладчике. Во-первых, основы:
OS: Windows 7 64-bit.
Application: Multithreaded VCL app with many dlls, bpls, and other components.
Compiler/IDE: Embarcadero RAD Studio 2010.
Наблюдаемый симптом таков: пока отладчик подключен к моему приложению, некоторые задачи приводят к сбою приложения. Подробности также озадачивают: мое приложение останавливается с сообщением Windows, говорящим: "YourApplication перестала работать". И он помогает предложить отправить мини-накопитель Microsoft.
Следует отметить: приложение не падает, когда отладчик не подключен. Кроме того, отладчик не указывает на какие-либо исключения или другие проблемы во время работы приложения.
Настройка и переход по точкам прерывания, по-видимому, влияет на момент, когда приложение выходит из строя, но я подозреваю, что это признак отладки потока, отличного от проблемного.
Эти сбои также происходят на компьютерах моих коллег, с тем же поведением, которое я наблюдаю. Это приводит меня к тому, что я не подозреваю о неудачной установке чего-либо на моем компьютере. Мои коллеги, испытывающие эту проблему, также работают с 64-разрядной версией Windows 7. У меня нет коллег, которые не испытывают проблемы.
Я собрал проанализированный ряд полных дампов от сбоев. Я обнаружил, что неудача на самом деле происходила в одном и том же месте каждый раз. Вот данные исключения из дампов (это всегда одно и то же, за исключением, конечно, ThreadId):
Exception Information
ThreadId: 0x000014C0
Code: 0x4000001F Unknown (4000001F)
Address: 0x773F2507
Flags: 0x00000000
NumberParameters: 0x00000001
0x00000000
Google показывает, что код 0x4000001F - это STATUS_WX86_BREAKPOINT. Microsoft бесполезно описывает его как "Код состояния исключения, который используется подсистемой эмуляции Win32 x86".
Вот данные стека (которые, похоже, не меняются):
0x773F2507: ntdll.dll+0x000A2507: RtlQueryCriticalSectionOwner + 0x000000E8
0x773F3DAB: ntdll.dll+0x000A3DAB: RtlQueryProcessLockInformation + 0x0000020D
0x773D2ED9: ntdll.dll+0x00082ED9: RtlUlonglongByteSwap + 0x00005C69
0x773F3553: ntdll.dll+0x000A3553: RtlpQueryProcessDebugInformationRemote + 0x00000044
0x74F73677: kernel32.dll+0x00013677: BaseThreadInitThunk + 0x00000012
0x77389F02: ntdll.dll+0x00039F02: RtlInitializeExceptionChain + 0x00000063
0x77389ED5: ntdll.dll+0x00039ED5: RtlInitializeExceptionChain + 0x00000036
Стоит отметить, что существует функция epilog на 0x773F24ED, что скорее предполагает, что RtlQueryCriticalSectionOwner - это красная селедка. Аналогично, функция epilog ставит под сомнение RtlQueryProcessLockInformation. Смещение 0x5C69 ставит под сомнение RtlUlonglongByteSwap. Другие символы выглядят законными.
В частности, RtlpQueryProcessDebugInformationRemote выглядит законно. Некоторые люди в Интернете (http://www.cygwin.com/ml/cygwin-talk/2006-q2/msg00050.html), похоже, считают, что он создан отладчиком для сбора отладочной информации. Мне кажется, эта теория кажется мне интересной, так как она появляется только при прикреплении отладчика.
Как всегда, когда что-то ломается, что-то изменилось, что сломало его. В этом случае что-то динамически загружает новую dll. Я могу привести к тому, что авария перестанет происходить, не динамически загружая конкретную DLL. Я не уверен, что загрузка dll связана, но вот подробности, на всякий случай:
Источник dll - C. Здесь указаны параметры компиляции, которые не установлены по умолчанию:
Language Compliance: ANSI
Merge duplicate strings: True
Read-only strings: True
PCH usage: Do not use
Dynamic RTL: False
(Параметры проекта говорят, что для динамического RTL по умолчанию установлено значение False, хотя при создании проекта dll было установлено значение True.)
DLL загружается с LoadLibrary и освобождается FreeLibrary. Кажется, все хорошо с загрузкой и разгрузкой модуля. Однако вскоре после того, как библиотека выгружена (с FreeLibrary), вышеупомянутый поток вылетает из программы. Для отладки я удалил все фактические вызовы в библиотеку (в том числе, для большего тестирования, DllMain). Никакая комбинация вызовов или не звонков, DllMain или DllMain или что-либо еще, похоже, каким-либо образом изменяло поведение аварии. Просто загрузка и выгрузка dll вызывает крах позже.
Кроме того, изменение dll для использования Dynamic RTL также приводит к прекращению аварийного потока отладчика. Это нежелательно, потому что скомпилированная dll действительно должна использоваться без возможности использования CodeGear Runtime. Кроме того, размер dll важен. Код C, содержащийся в dll, не использует никаких библиотек. (Он не содержит заголовков, даже стандартных заголовков библиотек. Нет malloc/free, no printf, no nothin '. Он содержит только функции, которые зависят исключительно от их входов и не требуют динамического выделения.) Это также нежелательно, потому что "исправление" ошибка, изменяя материал, пока он не работает, не понимая, почему он работает, на самом деле никогда не является хорошим планом. (Это приводит к появлению ошибок и странным правилам кодирования. Но на самом деле, если я не могу найти что-либо еще, я могу признать поражение по этому счету.)
И, наконец, моя проблема может быть связана с одной из следующих проблем:
- Системная ошибка после отладки многопоточных приложений
- Программа и отладчик завершают работу без указания проблемы
Любые идеи или предложения будут оценены.