With this code no more problem :
procedure TDosCommand.Stop;
begin
if (FThread <> nil) then
begin
FThread.FreeOnTerminate := true;
If not FThread.Finished then FThread.Terminate; //terminate the process
FThread := nil;
end;
end;
Actually: "No problem that you have spotted yet.
The code has a race condition. So there is a problem.
FThread.FreeOnTerminate := true;
After that line, when the thread does end, it will free the TThread object. That is the object to which FThread points.
So, from this point on, FThread should be treated as a "dangling pointer". Because it can change into that, at any point.
Of course, if you could guarantee that the thread can not finish.... But since you check in the next line, if it has finished, clearly you can not guarantee this.
If not FThread.Finished then FThread.Terminate; //terminate the process
So you call "Finished", but the object (pointed to by FThread), may already have been destroyed. The result may be random, or the call may even crash.
And even, if the call is made on a still existing object, that is no good, because the object can be freed between the return from "Finished" and the access to "Terminate". Same dangling pointer issue here.
And mind "FThread <> nil" does not help either. After all a dangling pointer is a non-nil value.
And even if the thread would set FThread to nil, before destroying the object. Still a race condition. Still could happen between your check, and the "then" action that requires the check....