On 27.11.2010 18:12, Michael Van Canneyt wrote:

Pierre muller has a better solution.

He uses TLS callbacks. His solution is finished, but is in need of testing.
If you want, I can send you his patch, and then you can test it too.


Yes, I'd like to test that. Especially as I'm curious how he's done that :D

As for the DoneThread: your solution number 3 is the one to take. It is
by far the safest. We'll need to implement it anyway like that
to fix the case of the TLS done callback and the DLL_DETACH_THREAD.


Great :D

Regards,
Sven

Michael.

On Sat, 27 Nov 2010, Sven Barth wrote:

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
_______________________________________________
fpc-devel maillist - fpc-devel@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-devel

_______________________________________________
fpc-devel maillist - fpc-devel@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-devel

_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply via email to