Fix DenseThreadId static destruction order fiasco#12789
Merged
bneradt merged 1 commit intoapache:masterfrom Jan 8, 2026
Merged
Fix DenseThreadId static destruction order fiasco#12789bneradt merged 1 commit intoapache:masterfrom
bneradt merged 1 commit intoapache:masterfrom
Conversation
35dba8f to
7a90602
Compare
The _id_stack vector was being destroyed before thread-local _Id objects, causing use-after-free when _Id::~_Id() tried to write to the freed vector. This patch addresses this by using std::array instead of std::vector. Since std::array<std::size_t, N> has a trivial destructor, the memory remains valid to the threads trying to use it regardless of destruction order. This bug was latent and only exposed when linking order changed (e.g., when adding new source files that changed static initialization order). Here's the valgrind output diagnosing the issue being fixed here: ==29149== Invalid write of size 8 ==29149== at 0x565832: DenseThreadId::_Id::~_Id() ==29149== by 0x6126DD8: ??? (in /usr/lib64/libstdc++.so.6.0.19) ==29149== by 0x6B40059: __cxa_finalize (in /usr/lib64/libc-2.17.so) ==29149== ... ==29149== Address 0xd4be1c0 is 0 bytes inside a block of size 2,048 free'd ==29149== at 0x4C2B6DF: operator delete(void*, unsigned long) ==29149== by 0x6B40059: __cxa_finalize (in /usr/lib64/libc-2.17.so) ==29149== ... ==29149== Block was alloc'd at ==29149== at 0x4C2A593: operator new(unsigned long) ==29149== by 0x566820: std::vector<...>::_M_default_append(unsigned long) ==29149== by 0x56515C: __tls_init
7a90602 to
0629365
Compare
serrislew
approved these changes
Jan 8, 2026
Contributor
serrislew
left a comment
There was a problem hiding this comment.
Thanks for working on this!
bneradt
pushed a commit
to bneradt/trafficserver
that referenced
this pull request
Jan 8, 2026
…)" This reverts commit aed2261.
bneradt
added a commit
to bneradt/trafficserver
that referenced
this pull request
Jan 23, 2026
The _id_stack vector was being destroyed before thread-local _Id objects, causing use-after-free when _Id::~_Id() tried to write to the freed vector. This patch addresses this by using std::array instead of std::vector. Since std::array<std::size_t, N> has a trivial destructor, the memory remains valid to the threads trying to use it regardless of destruction order. This bug was latent and only exposed when linking order changed (e.g., when adding new source files that changed static initialization order). Here's the valgrind output diagnosing the issue being fixed here: ==29149== Invalid write of size 8 ==29149== at 0x565832: DenseThreadId::_Id::~_Id() ==29149== by 0x6126DD8: ??? (in /usr/lib64/libstdc++.so.6.0.19) ==29149== by 0x6B40059: __cxa_finalize (in /usr/lib64/libc-2.17.so) ==29149== ... ==29149== Address 0xd4be1c0 is 0 bytes inside a block of size 2,048 free'd ==29149== at 0x4C2B6DF: operator delete(void*, unsigned long) ==29149== by 0x6B40059: __cxa_finalize (in /usr/lib64/libc-2.17.so) ==29149== ... ==29149== Block was alloc'd at ==29149== at 0x4C2A593: operator new(unsigned long) ==29149== by 0x566820: std::vector<...>::_M_default_append(unsigned long) ==29149== by 0x56515C: __tls_init (cherry picked from commit aed2261)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I have verified that this resolves the centos crash we have been seeing in #12669
The _id_stack vector was being destroyed before thread-local _Id objects,
causing use-after-free when _Id::~_Id() tried to write to the freed vector.
This patch addresses this by using std::array instead of std::vector.
Since std::array<std::size_t, N> has a trivial destructor, the memory
remains valid to the threads trying to use it regardless of destruction
order.
This bug was latent and only exposed when linking order changed (e.g.,
when adding new source files that changed static initialization order).
Here's the valgrind output diagnosing the issue being fixed here: