Three possible causes:
A memory overwrite which happens to overwrite things in "accessible" memory (so no AV). But triggers an invalid change to
FormListObject
.Something else (something like OnShow event) is actually removing items from
FormListObject
. It doesn't have to be a different thread; but of course that's also possible. NOTE: Although you asked if it's a GUI threading issue, I really doubt this is the case because you would have to be specifically calling GUI code from a different thread for this possibility.Re-entrant code is causing
FormListObject
to be changed while in the middle of the loop. This happens when you callApplication.ProcessMessages
while in the middle of processing another message. My debuggey-sense is twitching on this one. Even if you aren't guilty of theApplication.ProcessMessages
sin, some component on the form you're showing may be.
PS: I notice in a comment you say you already have a stack-trace. Check further down the stack-trace, and see if your code is re-entrant.
Since you're unable to reproduce the issue, you need extra debug logging to get more info. Assuming you have Log method that simply appends to a debug file. (The log method should output current thread ID to confirm threading issues.) Add debug logging as follows:
Log('Start loop');
for ii := FormListObject.Count - 1 downto 0 do begin
// Error happens here
TForm(FormListObject[ii]).Show;
end;
Log('End loop');
Encapsulate your FormListObject
so that any code to remove/delete/clear items goes through code under your control. I.e. don't expose direct access to the underlying list which would allow rogue code to change the list without your kowledge. Then add logging on any method that can remove items:
Log(Format('(%p)FormListObject.Clear', [Pointer(Self)]));
It might also be useful to log creation/destruction of FormListObject
instances.
When the issue occurrs, you'll have to analyse the log file to determine what went wrong. For example, if my hunch about the most likely cause of the issue is correct, you might find the following pattern (note each entry is on the same thread):
(Thread X) Start Loop
(Thread X) Start Loop
(Thread X) End Loop
(Thread X) ($........) Clear
EDIT
I've added a third possibility; which I actually have a hunch is the most likely cause.
Also added some specific debugging suggestions to narrow it down.