Most often case for such issues is when something "gets freed twice".
E.g. in case you create a list of some items that "owns" those items like
MyList = TObjectList.Create(true);
MyClass := TObject.Create;
MyList.Add(MyClass);
MyClass.Free; // now the class is freed and MyList has a dangling pointer inside
MyList.Free; // it tries to call (danglingpointer).Free and crashes
I don't remember if
TComponent derivatives automatically handle free notification, if not then e.g.
MyClass := TComponent.Create(Form1);
MyClass.Free; // now Form1 has a dangling pointer to "owned" child
Form1.Close; // this will crash, as it will attempt to (danglingpointer).Free
Of course usually it's much more entangled. Like "Class1 has a list inside which contains and owns Object1, and frees the list in the Destructor; Class2 has a list inside which contains and owns Object1 and frees the list in the Destructor; both classes are parented to Form and when form frees, it frees Class1 (which frees list inside, which frees Object1) and then frees Class2 (which frees list inside which tries to free Object1 again and crashes)". These bugs are rather hard to debug, so usually it's a good idea to "remember" what changes started causing this issue - and see what could get screwed with ownership there.