[fpc-devel] Question regarding thread finalization
Sven Barth
pascaldragon at googlemail.com
Sat Nov 27 17:25:53 CET 2010
Hello together!
As you might now, I'm working on a (according to Michael maybe
temporary) solution for the clean up of external threads (see
http://bugs.freepascal.org/view.php?id=17300 ).
My current state is that the collector thread which is used inside a
"program" is working correctly and now I'm going to tackle the problem
of DLLs.
I've looked at the necessary include files some time now and I might
have spotted a potential problem with thread finalization in DLLs.
Consider the following: in a DLL we start a thread and once it has done
its duty we call "EndThread" and return from the thread method (I'm
thinking in terms of "BeginThread" not "TThread" for this example).
After we've returned from the method Windows will call our DLL's entry
point (and that of any other loaded DLL) with DLL_THREAD_DETACH where we
call "DoneThread" because the current thread is not the "main" thread
(another interesting story...).
The call of "DoneThread" is decorated with a comment "Assume everything
is idempotent there". I'm hereby proposing that this assumption is not
correct.
I've looked at "EndThread" and "DoneThread". "EndThread" calls the
thread manager's "EndThread" method which on Windows calls
"DoneThread"(!) and the API method "ExitThread".
"DoneThread" finalizes the RTL for that thread and starts with the
WideString manager (not looked into that) and continues with the heap.
Now the first thing the heap does is getting the address of its
"freelists" record (which is a threadvar!) and plays around a bit with
its contents (not really important for this discussion). "DoneThread"
then continues finalizing other parts of the RTL and finally calls the
thread managers "ReleaseThreadVars" method.
I sincerely hope that every alarm bell rings now. By calling
"DoneThread" twice in a DLL we are basically accessing already freed
memory: the thread var data.
As this is a very serious problem I now ask you how this should be solved:
1) keep it as it is (I hope not O.o)
2) fullfill the assumption and check the code which is called by
"DoneThread" to be idempotent (which can break again at any time)
3) stop assuming that "DoneThread" is idempotent and do some checks
here. E.g. by checking whether TlsGetValue(TLSKey) is Nil before calling
"DoneThread" in DLL_THREAD_DETACH, which means that a) the RTL was never
initialised (a thread that was created before DLL_PROCESS_ATTACH and
never called into the DLL's code - see below) or b) the thread was
already finalized.
Problem 3a is the following:
A thread is created in an application. Now the main thread loads a FPC
library and some time after that the thread exits (it has never called
any method in the DLL). Now the DLL receives a DLL_THREAD_DETACH and
currently blindly finalizes a never initialized RTL (because it has
never received a DLL_THREAD_ATTACH call for this thread!).
Modifying the RTL in this way might also solve the external thread
problem for DLLs (I still have to think that one through, though).
Regards,
Sven
More information about the fpc-devel
mailing list