The following code seems to work okay on my machine, but gives an access violation for a customer.
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;
From the logging I can tell that When := 'WM_UPDATE';
is being hit and Where := 'GetList';
is not. This leads me to think that the access violation is occurring when the local Where
variable in the Update()
procedure is being added to the Stack.
What extra diagnostics could I add to help work out what's causing the issue? Is there any way I can check if the stack is corrupted and/or where the Where
variable is being added to the stack?
I realize this is a rather vague question, but I cannot think of anything to try and narrow this down.
Exact error is:
Exception (EAccessViolation) in summary thread at WM_UPDATE: Access violation at address 004B6759 in module 'Application.exe'. Read of address 00000008
In your executable's Project Options, locate the Linker settings. Ensure that the Map file
setting is configured to Detailed
. While you're on the Linker settings page, check the Image base
address. It is most likely $00400000, if not write it remember what it is set to.
Rebuild your executable (I'm assuming your project is a single executable, which it appears to be based on the exception text you provided). In the compiler's output directory, you should find a file named "Application.map". Open this file in your favorite text editor.
Now, take the address reported in the exception message (in this case $004B6759). Subtract the executable's base address ($00400000) from the exception's address. This gives you $B6759. Subtract $1000 (I'm pretty sure it's subtract, if not someone will point out that it should add in the comments). Leaving $B5759. This is the offset within the executable where the access violation occurred.
Using the map file that you loaded earlier, look in the Detailed map of segments
section. Locate the first entry that is less than or equal to $B5759 and is immediately followed by a segment that is greater than $B5759. Scan unit name of associated with the segment (it's the one marked with "M=").
Search for the unit name in the map file, you will find a section titled "Line numbers for XXX(..) segment .text" where XXX is the name of the unit you are looking for. In this section will be a list of line numbers and the offset to the first byte of code for that line number. Locate the first line number (based on the address) that is less than or equal to $B5759 and is immediately followed by an offset greater than $B5759.
This will tell you the line number (and source file) that contains the compiled code that is actually causing the access violation.
And as others have stated, given that the exception is a read of $8, you are likely trying to read from a nil pointer or object.. probably the second field of record or object (assuming 32bit code).
Best of luck.