I got this strange problem in EdiSyn already, there are always Exception TList index out of bounds but I never had any idea where it came from. in SynEdit it happend on scrolling in Lazarus happend very often when a selection was done. I tried to find out where it fires by addign debug outputs and search for TList access but I even did not find the function where exception was fired. (now I know why :-P)
The root of this problem was that the exception bring back a Stack dump but only the address no function name or so (as the crash trace back does). So I looked to AROS source, how to create such a trace back with function names and found that this is easy available via debug.library (in newer AROS Versions).
So now I get a nice trace back with all the names for functions on a exception in LCL applications, very nice.
So if I need a stack dump I can call LCLProc.DumStack to get this directly (for example to know from where a Event is called)
But back to the problem, (as visible in the screen shot) the crash appears to be in Classes.TFPList as we know already from the exception text. The function before is in MUIBaseUnit :-O so it’s in my code 😉
So my initial guess was not so bad, it has something to do with the timers, the timers are checked before the MUI messageloop is polled.
for i:= 0 to FTimers.Count -1 do begin TMUITimer(FTimers.items[i]).CheckTimer; end;
Which looks fine for the first moment, BUT if a Timer is removed (Deleted/Disabled inside a TimerEvent (another or the same)) the Count is not evaluated again in a for loop so this Index error can appear.
The for loop must be replaced by a loop which evaluates the FTimers.Count again, for example:
i := 0; Num := FTimers.Count; while i < FTimers.Count do begin TMUITimer(FTimers.items[i]).CheckTimer; if Num = FTimers.Count then Inc(i) else Num := FTimers.Count; end;
Mostly the timer self is removed (disabled), so we increase "i" only if the count did not change. This should be bullet proof for list index problem. But of course it can be some timers get called not so often (lets guess, a timer is activated and an other one is deactivated), but it only means a timer is fired 25-50 ms later which should be ok.