“Access Violation” means you access a wrong memory place, i.e. you have a pointer (which may also mean: a variable holding an instance of a class) that is not valid.
It means you have an instance of an object that is invalid (e.g. you have copied the pointer, and called Free
on another variable containing the same pointer). It may also mean you just access a variable equal to nil
(zero) – which is the case here, as your error message says “Acccess violation executing address $0000”.
I would actually
- Advise against trying to find it by commenting/uncommenting various places. This feels too much like “searching by luck”, you may end up wasting time doing 100 changes unrelated to the bug.
- Do not trust too much the intuition “this bug often occurs when…”. The root cause is that you have an invalid pointer. There are many many ways how you can get an invalid pointer.
Instead the first thing is to figure out when it occurs. I very advise to just use Lazarus debugger for this, usually this gives me the solution in 5 minutes.
To do this,
- Open the project in Lazarus, with Lazarus debugger on.
- Run.
- Lazarus will break at the exact Pascal line when it happens. This often helps and gives you straightforward place where the error occurs.
- Seldom, Lazarus cannot find the line in Pascal code – then you will land in Assembler window, which is less useful. But you can then still access “Call Stack” window in Lazarus. This tells you what Pascal routine caused it.
- If the Lazarus debugger didn’t give any useful results, then add just
WritelnLog
at the beginning of some larger pieces of code. Keep adding and removing them, and locate the place where the error occurs this way.
Once you find the place where it occurs, analyze what can do wrong.
Example:
X := MyObject.Y;
If the access violation happens there, it’s obvious that MyObject
is either nil
or a dangling pointer. To check this, you can e.g.
WritelnLog('MyObject <> nil? "%s"', [BoolToStr(MyObject <> nil, true)]);
right before that
X := MyObject.Y;
Or you can set in Lazarus breakpoint (F5) and right before the crashing line executes, check the contents of MyObject
. If they are not nil
– then you have a dangling pointer, and you need to understand why (something else freed it?) and secure from it (like making sure it is nil
when freed, or maybe nothing else should free it). If it is nil
– then understand why, and if it can happen, then you can simply add condition like
if MyObject <> nil then // during normal execution of the program, MyObject may have been freed by SomethingSomething
X := MyObject.Y;
It gets a little more complicated when the instruction is longer, like
X := MyObject.MyAnotherObject.Y;
Maybe MyObject
here is nil / invalid. Or maybe MyObject
is good, and MyObject.MyAnotherObject
is invalid. Again you will need to check it – with Lazarus breakpoint, or a sequence of writes to log.