Opened 13 years ago
Closed 13 years ago
#3045 closed Bugs (duplicate)
Two problems with thread_specific_ptr
Reported by: | Owned by: | Anthony Williams | |
---|---|---|---|
Milestone: | Boost 1.40.0 | Component: | threads |
Version: | Boost 1.36.0 | Severity: | Problem |
Keywords: | thread_specific_ptr | Cc: | hkalfal@… |
Description
This note describes two problems with thread_specific_ptr that we have discovered and proposes solutions to both of them: 1) A crash at shutdown occurs when thread_specific_ptr is used from a dll and the dll gets unloaded before the thread shutdown cleanup code for thread local storage takes place.
2) A subtle leak in the implementation of thread_specific_ptr.
Analysis of the first problem A thread_specific_ptr object has different thread specific “data” in different threads (this is what is returned by the get() function). The thread specific data gets destructed and removed from their thread specific store at thread shutdown (the latter is implemented as a linked list of nodes each holding a pointer to the thread specific data and a pointer to a cleanup function). However, the thread where the thread_specic_ptr object was constructed must destruct its thread specific data and remove it from the store long before thread shutdown. It must do it when the thread_specific_ptr object is destructed. The implementation in tss.hpp attempts to do this by calling reset() with a nil argument in the destructor of the thread_specific_ptr template class. Unfortunately, because this does not remove the entry from the linked list of thread specifics, and because it does not clear the cleanup pointer for that entry, it is possible to get a crash if the dll where the thread_specific_ptr was constructed gets unloaded before the thread shutdown cleanup code occurs. This can happen because the thread shutdown cleanup code calls the delete function of each node in the linked list even if the data in the node (the pointer to thread local data itself) is nil. The call to the delete function leads to a crash because the dll where the function pointer was defined has been unloaded. Proposed solution for first problem To avoid this issue, thread_specific_ptr should be clearing the cleanup pointer on destruction. Another solution is for thread_specific_ptr to remove the node from the linked list on destruction. Furthermore, in the definition of thread_specific_ptr, we should expect consistent behavior with release and reset with a nil argument. Currently, release clears the cleanup function pointer but reset with a nil argument does not. We expect they both be consistent, one way or another. Analysis of the second problem Because thread_specific_ptr does not remove the node from the tss linked list at destruction, we have a problem. The size of the linked list can become very large depending on the usage pattern of thread_specific_ptr. If the program creates and destructs thread_specific_ptr repetitively this may lead to major increase in the size of the linked list. A possible scenario where this can occur is if objects of class A are shared across threads, and if we keep creating and destructing them repetitively during execution. It is conceivable that the programmer need to store thread specific information in class A: Class A { private: thread_specific_ptr ts_ptr; }; If the program creates and destructs objects of class A repetitively this will lead to a leak as nodes get added to the cleanup list but never removed until thread shutdown. It is conceivable that the executable run out of memory because of this.
Proposed solution for second problem: thread_specific_ptr must remove the node from the linked list on destruction.
Duplicate of #2797