-
-
Notifications
You must be signed in to change notification settings - Fork 6.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CThread: fix memory leak #21640
base: master
Are you sure you want to change the base?
CThread: fix memory leak #21640
Conversation
@@ -200,6 +200,7 @@ void CThread::StopThread(bool bWait /*= true*/) | |||
lock.unlock(); | |||
if (!Join(std::chrono::milliseconds::max())) // eh? | |||
lthread->join(); | |||
delete lthread; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nope, lthread
is assigned from m_thread
and m_thread
is deleted in CThread
s desctructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, this introduces the possibility of a double-free.
The same block sets m_thread to nullptr which prevents the CThread destructor to clean it. We should keep in mind that some classes, which are child of CThread, are overriding the destructor and rely on StopThread to clean the thread. This issue triggers the gcc sanitizer. |
True, I'll let someone with more knowledge about |
The design allows CThread to be constructed with an "autodelete" feature, which allows for "new and forget me" type construction. In this mode, And yes, this has caused sanitizers to go nuts a lot. Adding a If anything, it'd be nice to shut the sanitizers up. |
This issue is specific to StopThread(), I don't think that autodelete is affected by this change. StopThread() is explicitly called and we must ensure that m_thread is deleted in the process. |
The issue is that StopThread() behavior now depends on autodelete (because the destiny of the pointer depends on autodelete). If autodelete was true on creation, then stopping the thread manually will cause a double free. |
My advice: remove autodelete. Nothing short of this will clean the santizer errors. Use refcounting or make a manager that tracks autodeleting threads. |
This change fixes the sanitizer errors triggered by StopThread(); I let you try on your configuration. |
The change quiets the sanitizers, but they wouldn't see the double free for the same reason they didn't see the single free. Have you runtime tested this change? Can you launch and stop an autodelete thread, and verify that a double-free doesn't occur, as it appears to me it would? |
OK, I will check. |
Here is a simplified version of CThread for test purposes: https://gist.github.com/repojohnray/8642d27635534e23ab85630dca56f7e3
"free(): invalid pointer" is happening at the autodelete "delete" execution (line 344). In this specific case StopThread() is not even called, I don't think autodelete is working. Here is the output with the sanitizer:
|
@a1rwulf I believe you're correct. Ideally this should be fixed by removing CThread. Inheriting from CThread is an anti-patternn @garbear on autodelete; if thread management were independent of business functionality then this wouldn't be needed. IOW, if there was a thread pool based executor that supported daemon threads then ALL thread management would be delegated to the executor and no one would need to inherit from CThread (and CThread could be deleted). I had started work on this once a while back. It proved to be quite invasive so I dropped it. Maybe I'll pick it up again. |
Description
m_thread was allocated with a "new", this commit ensures that the thread is properly freed.