#delphi #stack #delphi-5
#delphi #стек #delphi-5
Вопрос:
Следующий код, похоже, работает нормально на моем компьютере, но приводит к нарушению доступа для клиента.
procedure TSummaryThread.Execute;
var
When: String;
begin
try
FCarcassListCS := TCriticalSection.Create;
FCarcassLists := TObjectList.Create;
while (not Terminated) do
begin
try
When := 'GetMessage';
if (GetMessage(Msg, 0, 0, 0))
then begin
if (Msg.message = WM_SUMMARISE)
then begin
When := 'WM_SUMMARISE';
Update(True);
end
else if (Msg.message = WM_UPDATE)
then begin
When := 'WM_UPDATE';
Update(False);
end
else if (Msg.message = WM_RELOAD_SETUP)
then begin
When := 'WM_RELOAD_SETUP';
ReloadSetup(Pointer(Msg.wParam));
end
else if (Msg.message = WM_SEND_TO)
then begin
When := 'WM_SEND_TO';
SendToThread(Pointer(Msg.wParam));
end
else if (Msg.message = WM_UPDATE_ORDER_SUM)
then begin
When := 'WM_UPDATE_ORDER_SUM';
DoOrderSummary;
end
else if (Msg.message = WM_SUMMARISE_LOAD)
then begin
When := 'WM_SUMMARISE_LOAD';
LoadAndSummarise;
end
else begin
When := 'DispatchMessage';
DispatchMessage(Msg);
end;
end;
except
on E: Exception do
Log('Exception (' E.ClassName ') in summary thread at ' When ': ' E.Message);
end;
end;
except
on E: Exception do
Log('Exception (' E.ClassName ') in summary thread (2) at ' When ': ' E.Message);
end;
procedure TSummaryThread.Update(Full: Boolean);
var
CarcassList: TObjectList;
Where: String;
begin
try
Where := 'GetList';
FCarcassListCS.Enter;
try
if (FCarcassLists.Count = 0)
then raise Exception.Create('No carcass list found');
CarcassList := FCarcassLists[0] as TObjectList;
FCarcassLists.Extract(CarcassList);
finally
FCarcassListCS.Leave;
end;
FSummaryListCS.Enter;
try
Where := 'LoadFiles';
SetFiles;
try
Where := 'AddCcs';
CarcassList := GetShiftCarcassList(CarcassList);
AddCarcassesToSummaries(CarcassList, Full);
finally
CloseFiles;
end;
Where := 'Send';
SendSummaries;
Where := 'Done';
finally
FreeAndNil(CarcassList);
FSummaryListCS.Leave;
end;
except
on E: Exception do
begin
E.Message := 'Update(' Where '): ' E.Message;
raise;
end;
end;
end;
Из журнала я могу сказать, что When := 'WM_UPDATE';
это происходит, а Where := 'GetList';
не нет. Это наводит меня на мысль, что нарушение доступа происходит, когда локальная Where
переменная в Update()
процедуре добавляется в стек.
Какую дополнительную диагностику я мог бы добавить, чтобы помочь определить причину проблемы? Есть ли какой-нибудь способ проверить, поврежден ли стек и / или где Where
переменная добавляется в стек?
Я понимаю, что это довольно расплывчатый вопрос, но я не могу придумать ничего, чтобы попытаться сузить этот вопрос.
Точная ошибка:
Исключение (EAccessViolation) в итоговом потоке в WM_UPDATE: нарушение доступа по адресу 004B6759 в модуле ‘Application.exe «. Считывание адреса 00000008
Комментарии:
1. (1) точное сообщение об ошибке? (2) вы уверены, что объект потока действителен и еще не исчез?
2. Как вы узнаете, что происходит нарушение доступа? Каков фактический симптом / журнал? Неспособность поместить переменную в стек не генерирует AV, а присвоение значения (особенно литерала) a
String
в любом случае не помещает эти данные в стек. В этом коде нет ничего, что могло бы вызвать AV, где вы утверждаете, если только AV не поступает из самого диспетчера памяти RTL, и в этом случае ваше приложение заблокировано, и вам нужно перезапустить его.3. И КСТАТИ, когда дело доходит до отслеживания проблем с памятью, постарайтесь уменьшить выделение памяти, не используйте выделение для отслеживания проблемы. Используйте
OutputDebugString()
для ведения журнала и используйте такой инструмент, как DebugView , чтобы видеть эти сообщения, когда вы запускаете приложение вне отладчика IDE.4. @JensG Я добавил точное сообщение об ошибке. Верхняя часть кода взята из TSummaryThread. Выполнить метод, поэтому я думаю, что объект thread все еще действителен.
5. Включите madexcept в процесс и получите реальную информацию. Выглядит как нулевой объект. Возможно, значение self равно нулю.
Ответ №1:
В параметрах проекта вашего исполняемого файла найдите настройки компоновщика. Убедитесь, что Map file
параметр настроен на Detailed
. Находясь на странице настроек компоновщика, проверьте Image base
адрес. Скорее всего, это $ 00400000, если не записать его, помните, на что он установлен.
Перестройте свой исполняемый файл (я предполагаю, что ваш проект представляет собой один исполняемый файл, который, как представляется, основан на предоставленном вами тексте исключения). В выходном каталоге компилятора вы должны найти файл с именем «Application.map». Откройте этот файл в вашем любимом текстовом редакторе.
Теперь возьмем адрес, указанный в сообщении об исключении (в данном случае $ 004B6759). Вычтите базовый адрес исполняемого файла ($ 00400000) из адреса исключения. Это дает вам 6759 долларов. Вычтите 1000 долларов (я почти уверен, что это вычтет, если кто-то не укажет, что это должно быть добавлено в комментариях). Осталось $ B5759. Это смещение в исполняемом файле, где произошло нарушение доступа.
Используя файл карты, который вы загрузили ранее, посмотрите в Detailed map of segments
разделе. Найдите первую запись, которая меньше или равна $ B5759, и сразу за ней следует сегмент, который больше, чем $ B5759. Имя модуля сканирования, связанного с сегментом (это тот, который отмечен «M =»).
Найдите имя объекта в файле карты, вы найдете раздел под названием «Номера строк для XXX (..) segment .text», где XXX — это имя объекта, который вы ищете. В этом разделе будет список номеров строк и смещение к первому байту кода для этого номера строки. Найдите номер первой строки (на основе адреса), который меньше или равен $ B5759 и за которым сразу следует смещение больше, чем $ B5759.
Это сообщит вам номер строки (и исходного файла), который содержит скомпилированный код, который фактически вызывает нарушение доступа.
И, как заявляли другие, учитывая, что исключение составляет чтение в размере 8 долларов, вы, вероятно, пытаетесь прочитать из нулевого указателя или объекта.. вероятно, второе поле записи или объекта (при условии 32-битного кода).
Желаю удачи.