Memory leak in cthreads.pp when hooking non-pascal threads
Original Reporter info from Mantis: Derek
-
Reporter name:
Original Reporter info from Mantis: Derek
- Reporter name:
Description:
This issue only applies when using cthreads and using non-pascal threads. I found in a large application which hooked many C threads and found memory growing even when the threads terminated.
This issue may be specific to Centos 6, or may be more general.
The routines HookThread words correctly, and although CthreadCleanup in itself does not cause an issue, the value of TLSKey is nil.
The issue is the way the pthreads system calls the clean up. The pthread documentation correctly states that the cleanup routines (destructor) is called when the TLS key value is non-null, however, there is no order for these calls nor is there information on what will happen when the destructor is nil.
Under Centos 6, I found the call to CthreadCleanup occurred as expected, but TLSKey was already nil. Any reference to a threadvar (e.g. exception) caused a new copy of thread storage to be created. The initial memory allocations was not freed.
I suspect that on thread termination, the pthreads processes all thread keys in the order they are created, and clears them in turn, calling the destructor only when a key value is non-nil. I did manage to prove this for Centos by reversing the order of the pthread_key_create calls (i.e. CleanupKey created first). When reverse, TLSKey was non-nil as expected.
This may not work on all versions of Linux, so I changed the fix to save the TLS address in the CleanupKey, not just setting a flag value of 1. This ensures the reference is always valid. When nil, CthreadCleanup would not have been called, otherwise it immediately restores TLSKey and continues. I also reset TLSKey to nil on completion.
Steps to reproduce:
Create an application under Linux which uses cthreads. For ease of testing/monitoring, ensure the program allocates a lot of data in thread storage using threadvar. Ensure the application hooks threads created outside of FPC, e.g. pascal. When a thread is hooked, memory will grow, but when destroyed, the memory does not decrease as expected.
Additional information:
A patch is attached which I have incorporated into my build.
Mantis conversion info:
- Mantis ID: 28806
- OS: Centos
- OS Build: 6
- Platform: Linux
- Version: 2.6.4
- Fixed in version: 3.1.1
- Fixed in revision: 32168 (#f0c0b004)
- Monitored by: » Vincent (Vincent Snijders)