Then thread X will access the B pointer, but B has been released by Z thread.
You may have misunderstood what I mean, the enqueue is done by Y, and X get an outdated pointer. X needs to access next field to get updated pointer, but because the bufferList obtained by X has been released, this will cause UAF.
This problem can be detected with ThreadSanitizer.
WARNING: ThreadSanitizer: data race (pid=1324466)
Write of size 8 at 0x7b8000018088 by main thread:
#0 free /build/gcc/src/gcc/libsanitizer/tsan/tsan_interceptors_posix.cpp:707 (libtsan.so.0+0x359f8)
#1 my_align_free /tests/Jiffy/MpScQueue.h:33 (output+0x30d0)
#2 MpScQueue<int>::dequeue(int&) /tests/Jiffy/MpScQueue.h:268 (output+0x30d0)
#3 testMyqueue(int, int, unsigned long) /tests/Jiffy/test.cpp:40 (output+0x30d0)
#4 main /tests/Jiffy/test.cpp:66 (output+0x25c5)
Previous read of size 4 at 0x7b800001808c by thread T2:
#0 MpScQueue<int>::enqueue(int const&) /tests/Jiffy/MpScQueue.h:286 (output+0x2994)
#1 trace_thread_action(MpScQueue<int>&, unsigned long, int) /tests/Jiffy/test.cpp:21 (output+0x2994)
#2 void std::__invoke_impl<void, void (*)(MpScQueue<int>&, unsigned long, int), std::reference_wrapper<MpScQueue<int> >, unsigned long, int>(std::__invoke_other, void (*&&)(MpScQueue<int>&, unsigned long, int), std::reference_wrapper<MpScQueue<int> >&&, unsigned long&&, int&&) /usr/include/c++/10.2.0/bits/invoke.h:60 (output+0x3782)
#3 std::__invoke_result<void (*)(MpScQueue<int>&, unsigned long, int), std::reference_wrapper<MpScQueue<int> >, unsigned long, int>::type std::__invoke<void (*)(MpScQueue<int>&, unsigned long, int), std::reference_wrapper<MpScQueue<int> >, unsigned long, int>(void (*&&)(MpScQueue<int>&, unsigned long, int), std::reference_wrapper<MpScQueue<int> >&&, unsigned long&&, int&&) /usr/include/c++/10.2.0/bits/invoke.h:95 (output+0x3782)
#4 void std::thread::_Invoker<std::tuple<void (*)(MpScQueue<int>&, unsigned long, int), std::reference_wrapper<MpScQueue<int> >, unsigned long, int> >::_M_invoke<0ul, 1ul, 2ul, 3ul>(std::_Index_tuple<0ul, 1ul, 2ul, 3ul>) /usr/include/c++/10.2.0/thread:264 (output+0x3782)
#5 std::thread::_Invoker<std::tuple<void (*)(MpScQueue<int>&, unsigned long, int), std::reference_wrapper<MpScQueue<int> >, unsigned long, int> >::operator()() /usr/include/c++/10.2.0/thread:271 (output+0x3782)
#6 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(MpScQueue<int>&, unsigned long, int), std::reference_wrapper<MpScQueue<int> >, unsigned long, int> > >::_M_run() /usr/include/c++/10.2.0/thread:215 (output+0x3782)
#7 execute_native_thread_routine /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:80 (libstdc++.so.6+0xcfc23)
Thread T2 (tid=1324469, finished) created by main thread at:
#0 pthread_create /build/gcc/src/gcc/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5efab)
#1 __gthread_create /build/gcc/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/gthr-default.h:663 (libstdc++.so.6+0xcfef9)
#2 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:135 (libstdc++.so.6+0xcfef9)
#3 main /tests/Jiffy/test.cpp:66 (output+0x25c5)
SUMMARY: ThreadSanitizer: data race /tests/Jiffy/MpScQueue.h:33 in my_align_free
Consider a jiffy queue,
headOfQueueandtailOfQueuepoint to samebufferList, called B,and head has advanced to last node in list.
There are three threads at this time
tailOfQueue.load()bufferList, and updatestailOfQueueheadOfQueue != tailOfQueue, so B is releasedThen thread X will access the B pointer, but B has been released by Z thread.
You said in the email
You may have misunderstood what I mean, the enqueue is done by Y, and X get an outdated pointer. X needs to access
nextfield to get updated pointer, but because thebufferListobtained by X has been released, this will cause UAF.This problem can be detected with ThreadSanitizer.
test code https://gist.github.com/quininer/3fd07999f341470466377617367d838d