-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Free the tls memory on thread termination #95362
Conversation
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.
Changes look ok to me. I think @AaronRobinsonMSFT is also taking a look.
src/coreclr/vm/threads.cpp
Outdated
@@ -7702,6 +7708,15 @@ void Thread::DeleteThreadStaticData() | |||
CONTRACTL_END; | |||
|
|||
m_ThreadLocalBlock.FreeTable(); | |||
|
|||
delete[] t_ThreadStatics.NonGCThreadStaticBlocks; |
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.
so these were thought to be implicitly deleted but that isnt the case?
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.
correct.
If we intend to backport this fix to 8.0 so it gets included in the January Release, please target the release/8.0 branch directly, not staging, so we can flow it to internal quickly. Use: /backport to release/8.0 |
@kunalspathak no symbolization on the stack traces so I can only guess what's behind the failures -- maybe the cleanup needs to be conditional on the TLS not being nullptr? Linux may be more tolerant of calling delete on nulls. |
Here is what I found for 1 repro, but it doesn't always stay like that. Notice the
Under windbg, I always hit this kind of AV, which I think is coming because 0007ffe`4a379c9e c5fe7f65e0 vmovdqu ymmword ptr [rbp-20h],ymm4
00007ffe`4a379ca3 48894d10 mov qword ptr [rbp+10h],rcx
00007ffe`4a379ca7 488b4d10 mov rcx,qword ptr [rbp+10h]
00007ffe`4a379cab 488b4908 mov rcx,qword ptr [rcx+8]
00007ffe`4a379caf 48894df8 mov qword ptr [rbp-8],rcx
00007ffe`4a379cb3 488b4df8 mov rcx,qword ptr [rbp-8]
00007ffe`4a379cb7 48baf8597e4afe7f0000 mov rdx,7FFE4A7E59F8h
00007ffe`4a379cc1 e89a14435c call coreclr!JIT_ClassProfile32 (00007ffe`a67ab160)
00007ffe`4a379cc6 488b4df8 mov rcx,qword ptr [rbp-8]
00007ffe`4a379cca 48894de8 mov qword ptr [rbp-18h],rcx
00007ffe`4a379cce 488b4de8 mov rcx,qword ptr [rbp-18h]
00007ffe`4a379cd2 488b45e8 mov rax,qword ptr [rbp-18h]
00007ffe`4a379cd6 488b00 mov rax,qword ptr [rax] ds:00000000`00000000=???????????????? ; <----
00007ffe`4a379cd9 488b4060 mov rax,qword ptr [rax+60h]
00007ffe`4a379cdd ff5018 call qword ptr [rax+18h]
00007ffe`4a379ce0 85c0 test eax,eax
|
I just pushed the conditional checking as well as reset the other two variables. |
I verified locally and MSVC doesn't complain if using |
alright, verified the AV in jit code that I shared earlier and I can see it repros even on my local build from |
Is the |
Looking at the comments about runtime/src/coreclr/vm/threads.cpp Lines 2353 to 2359 in 8cb3c61
One of the caller runtime/src/coreclr/vm/threads.cpp Line 894 in 8cb3c61
but the fact that inside runtime/src/coreclr/vm/threads.cpp Lines 2962 to 2964 in 8cb3c61
I don't want to disturb the CI, but once it is done, I can try adding this check inside |
@mangod9 for his input:
|
alright, I added an assert locally and I hit that assert. m_ThreadLocalBlock.FreeTable();
+ Thread *pCurrentThread = GetThreadNULLOk();
+ DWORD CurrentThreadID = pCurrentThread?pCurrentThread->GetThreadId():0;
+ DWORD ThisThreadID = GetThreadId();
+
+ _ASSERTE(CurrentThreadID == ThisThreadID);
So given that I can guard the deletion only if we are on current thread, where can we delete the memory for detached threads? Is there code that detached threads execute before termination? |
Seems runtime/src/coreclr/vm/threads.cpp Line 983 in 8cb3c61
|
@kouvel, please see Kunal's question. We need to backport this PR tonight. |
/backport to release/8.0 |
Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/7042036275 |
if (t_ThreadStatics.NonGCThreadStaticBlocks != nullptr) | ||
{ | ||
delete[] t_ThreadStatics.NonGCThreadStaticBlocks; | ||
t_ThreadStatics.NonGCThreadStaticBlocks = nullptr; | ||
} | ||
if (t_ThreadStatics.GCThreadStaticBlocks != nullptr) | ||
{ | ||
delete[] t_ThreadStatics.GCThreadStaticBlocks; | ||
t_ThreadStatics.GCThreadStaticBlocks = nullptr; | ||
} |
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.
Nit: None of these null checks are needed.
The TLS memory that we used to store the TLS data per thread was never freed on thread termination. This results in memory leak.