From 1fd17475798e445c166fbcb62def502bbfef6191 Mon Sep 17 00:00:00 2001
From: "Serov, Vladimir" <vladimir.serov@intel.com>
Date: Tue, 8 Jun 2021 13:05:16 +0300
Subject: [PATCH 1/3] ASAN: Use after scope in conformance_concurrent_queue

concurrent_queue_rep holds reference to Allocator, which is managed by
concurrent_queue. This reference can be invalid after moving
concurrent_queue_rep from one concurrent_queue to another.

Updating concurrent_queue_rep for using provider Allocator instead of
holding reference.

Signed-off-by: Serov, Vladimir <vladimir.serov@intel.com>
---
 include/oneapi/tbb/concurrent_queue.h         | 48 +++++++--------
 .../tbb/detail/_concurrent_queue_base.h       | 61 +++++++++----------
 src/tbb/concurrent_bounded_queue.cpp          |  4 +-
 3 files changed, 54 insertions(+), 59 deletions(-)

diff --git a/include/oneapi/tbb/concurrent_queue.h b/include/oneapi/tbb/concurrent_queue.h
index a7a6689a4..758143e30 100644
--- a/include/oneapi/tbb/concurrent_queue.h
+++ b/include/oneapi/tbb/concurrent_queue.h
@@ -26,7 +26,7 @@
 
 namespace tbb {
 namespace detail {
-namespace d1 {
+namespace d2 {
 
 // A high-performance thread-safe non-blocking concurrent queue.
 // Multiple threads may each push and pop concurrently.
@@ -57,7 +57,7 @@ class concurrent_queue {
         my_allocator(a), my_queue_representation(nullptr)
     {
         my_queue_representation = static_cast<queue_representation_type*>(r1::cache_aligned_allocate(sizeof(queue_representation_type)));
-        queue_allocator_traits::construct(my_allocator, my_queue_representation, my_allocator);
+        queue_allocator_traits::construct(my_allocator, my_queue_representation);
 
         __TBB_ASSERT(is_aligned(my_queue_representation, max_nfs_size), "alignment error" );
         __TBB_ASSERT(is_aligned(&my_queue_representation->head_counter, max_nfs_size), "alignment error" );
@@ -76,13 +76,13 @@ class concurrent_queue {
     concurrent_queue(const concurrent_queue& src, const allocator_type& a) :
         concurrent_queue(a)
     {
-        my_queue_representation->assign(*src.my_queue_representation, copy_construct_item);
+        my_queue_representation->assign(*src.my_queue_representation, my_allocator, copy_construct_item);
     }
 
     concurrent_queue(const concurrent_queue& src) :
         concurrent_queue(queue_allocator_traits::select_on_container_copy_construction(src.get_allocator()))
     {
-        my_queue_representation->assign(*src.my_queue_representation, copy_construct_item);
+        my_queue_representation->assign(*src.my_queue_representation, my_allocator, copy_construct_item);
     }
 
     // Move constructors
@@ -101,7 +101,7 @@ class concurrent_queue {
             internal_swap(src);
         } else {
             // allocators are different => performing per-element move
-            my_queue_representation->assign(*src.my_queue_representation, move_construct_item);
+            my_queue_representation->assign(*src.my_queue_representation, my_allocator, move_construct_item);
             src.clear();
         }
     }
@@ -109,7 +109,7 @@ class concurrent_queue {
     // Destroy queue
     ~concurrent_queue() {
         clear();
-        my_queue_representation->clear();
+        my_queue_representation->clear(my_allocator);
         queue_allocator_traits::destroy(my_allocator, my_queue_representation);
         r1::cache_aligned_deallocate(my_queue_representation);
     }
@@ -177,7 +177,7 @@ class concurrent_queue {
     template <typename... Args>
     void internal_push( Args&&... args ) {
         ticket_type k = my_queue_representation->tail_counter++;
-        my_queue_representation->choose(k).push(k, *my_queue_representation, std::forward<Args>(args)...);
+        my_queue_representation->choose(k).push(k, *my_queue_representation, my_allocator, std::forward<Args>(args)...);
     }
 
     bool internal_try_pop( void* dst ) {
@@ -193,7 +193,7 @@ class concurrent_queue {
                 // Queue had item with ticket k when we looked. Attempt to get that item.
                 // Another thread snatched the item, retry.
             } while (!my_queue_representation->head_counter.compare_exchange_strong(k, k + 1));
-        } while (!my_queue_representation->choose(k).pop(dst, k, *my_queue_representation));
+        } while (!my_queue_representation->choose(k).pop(dst, k, *my_queue_representation, my_allocator));
         return true;
     }
 
@@ -230,7 +230,7 @@ class concurrent_monitor;
 // The concurrent monitor tags for concurrent_bounded_queue.
 static constexpr std::size_t cbq_slots_avail_tag = 0;
 static constexpr std::size_t cbq_items_avail_tag = 1;
-} // namespace d1
+} // namespace d2
 
 
 namespace r1 {
@@ -246,7 +246,7 @@ namespace r1 {
 } // namespace r1
 
 
-namespace d1 {
+namespace d2 {
 // A high-performance thread-safe blocking concurrent bounded queue.
 // Supports boundedness and blocking semantics.
 // Multiple threads may each push and pop concurrently.
@@ -260,7 +260,7 @@ class concurrent_bounded_queue {
 
     template <typename FuncType>
     void internal_wait(r1::concurrent_monitor* monitors, std::size_t monitor_tag, std::ptrdiff_t target, FuncType pred) {
-        delegated_function<FuncType> func(pred);
+        d1::delegated_function<FuncType> func(pred);
         r1::wait_bounded_queue_monitor(monitors, monitor_tag, target, func);
     }
 public:
@@ -285,7 +285,7 @@ class concurrent_bounded_queue {
         my_queue_representation = reinterpret_cast<queue_representation_type*>(
             r1::allocate_bounded_queue_rep(sizeof(queue_representation_type)));
         my_monitors = reinterpret_cast<r1::concurrent_monitor*>(my_queue_representation + 1);
-        queue_allocator_traits::construct(my_allocator, my_queue_representation, my_allocator);
+        queue_allocator_traits::construct(my_allocator, my_queue_representation);
         my_capacity = std::size_t(-1) / (queue_representation_type::item_size > 1 ? queue_representation_type::item_size : 2);
 
         __TBB_ASSERT(is_aligned(my_queue_representation, max_nfs_size), "alignment error" );
@@ -305,13 +305,13 @@ class concurrent_bounded_queue {
     concurrent_bounded_queue( const concurrent_bounded_queue& src, const allocator_type& a ) :
         concurrent_bounded_queue(a)
     {
-        my_queue_representation->assign(*src.my_queue_representation, copy_construct_item);
+        my_queue_representation->assign(*src.my_queue_representation, my_allocator, copy_construct_item);
     }
 
     concurrent_bounded_queue( const concurrent_bounded_queue& src ) :
         concurrent_bounded_queue(queue_allocator_traits::select_on_container_copy_construction(src.get_allocator()))
     {
-        my_queue_representation->assign(*src.my_queue_representation, copy_construct_item);
+        my_queue_representation->assign(*src.my_queue_representation, my_allocator, copy_construct_item);
     }
 
     // Move constructors
@@ -330,7 +330,7 @@ class concurrent_bounded_queue {
             internal_swap(src);
         } else {
             // allocators are different => performing per-element move
-            my_queue_representation->assign(*src.my_queue_representation, move_construct_item);
+            my_queue_representation->assign(*src.my_queue_representation, my_allocator, move_construct_item);
             src.clear();
         }
     }
@@ -338,7 +338,7 @@ class concurrent_bounded_queue {
     // Destroy queue
     ~concurrent_bounded_queue() {
         clear();
-        my_queue_representation->clear();
+        my_queue_representation->clear(my_allocator);
         queue_allocator_traits::destroy(my_allocator, my_queue_representation);
         r1::deallocate_bounded_queue_rep(reinterpret_cast<std::uint8_t*>(my_queue_representation),
                                          sizeof(queue_representation_type));
@@ -456,12 +456,12 @@ class concurrent_bounded_queue {
             try_call( [&] {
                 internal_wait(my_monitors, cbq_slots_avail_tag, target, pred);
             }).on_exception( [&] {
-                my_queue_representation->choose(ticket).abort_push(ticket, *my_queue_representation);
+                my_queue_representation->choose(ticket).abort_push(ticket, *my_queue_representation, my_allocator);
             });
 
         }
         __TBB_ASSERT((static_cast<std::ptrdiff_t>(my_queue_representation->head_counter.load(std::memory_order_relaxed)) > target), nullptr);
-        my_queue_representation->choose(ticket).push(ticket, *my_queue_representation, std::forward<Args>(args)...);
+        my_queue_representation->choose(ticket).push(ticket, *my_queue_representation, my_allocator, std::forward<Args>(args)...);
         r1::notify_bounded_queue_monitor(my_monitors, cbq_items_avail_tag, ticket);
     }
 
@@ -477,7 +477,7 @@ class concurrent_bounded_queue {
             // Another thread claimed the slot, so retry.
         } while (!my_queue_representation->tail_counter.compare_exchange_strong(ticket, ticket + 1));
 
-        my_queue_representation->choose(ticket).push(ticket, *my_queue_representation, std::forward<Args>(args)...);
+        my_queue_representation->choose(ticket).push(ticket, *my_queue_representation, my_allocator, std::forward<Args>(args)...);
         r1::notify_bounded_queue_monitor(my_monitors, cbq_items_avail_tag, ticket);
         return true;
     }
@@ -505,7 +505,7 @@ class concurrent_bounded_queue {
                 });
             }
             __TBB_ASSERT(static_cast<std::ptrdiff_t>(my_queue_representation->tail_counter.load(std::memory_order_relaxed)) > target, nullptr);
-        } while (!my_queue_representation->choose(target).pop(dst, target, *my_queue_representation));
+        } while (!my_queue_representation->choose(target).pop(dst, target, *my_queue_representation, my_allocator));
 
         r1::notify_bounded_queue_monitor(my_monitors, cbq_slots_avail_tag, target);
         return true;
@@ -523,7 +523,7 @@ class concurrent_bounded_queue {
                 // Queue had item with ticket k when we looked.  Attempt to get that item.
                 // Another thread snatched the item, retry.
             } while (!my_queue_representation->head_counter.compare_exchange_strong(ticket, ticket + 1));
-        } while (!my_queue_representation->choose(ticket).pop(dst, ticket, *my_queue_representation));
+        } while (!my_queue_representation->choose(ticket).pop(dst, ticket, *my_queue_representation, my_allocator));
 
         r1::notify_bounded_queue_monitor(my_monitors, cbq_slots_avail_tag, ticket);
         return true;
@@ -563,13 +563,13 @@ concurrent_bounded_queue( It, It, Alloc = Alloc() )
 
 #endif /* __TBB_CPP17_DEDUCTION_GUIDES_PRESENT */
 
-} //namespace d1
+} //namespace d2
 } // namesapce detail
 
 inline namespace v1 {
 
-using detail::d1::concurrent_queue;
-using detail::d1::concurrent_bounded_queue;
+using detail::d2::concurrent_queue;
+using detail::d2::concurrent_bounded_queue;
 using detail::r1::user_abort;
 using detail::r1::bad_last_alloc;
 
diff --git a/include/oneapi/tbb/detail/_concurrent_queue_base.h b/include/oneapi/tbb/detail/_concurrent_queue_base.h
index 9f7e76afc..e3669fadc 100644
--- a/include/oneapi/tbb/detail/_concurrent_queue_base.h
+++ b/include/oneapi/tbb/detail/_concurrent_queue_base.h
@@ -30,7 +30,7 @@
 
 namespace tbb {
 namespace detail {
-namespace d1 {
+namespace d2 {
 
 using ticket_type = std::size_t;
 
@@ -67,6 +67,7 @@ class micro_queue {
 
     using allocator_type = Allocator;
     using allocator_traits_type = tbb::detail::allocator_traits<allocator_type>;
+    using queue_allocator_type = typename allocator_traits_type::template rebind_alloc<queue_rep_type>;
 
     static constexpr size_type item_size = sizeof(T);
     static constexpr size_type items_per_page = item_size <=   8 ? 32 :
@@ -123,7 +124,7 @@ class micro_queue {
         }
 
         if (tail_counter.load(std::memory_order_relaxed) != k) spin_wait_until_my_turn(tail_counter, k, base);
-        call_itt_notify(acquired, &tail_counter);
+        d1::call_itt_notify(d1::acquired, &tail_counter);
 
         if (p) {
             spin_mutex::scoped_lock lock( page_mutex );
@@ -141,10 +142,10 @@ class micro_queue {
     }
 
     template<typename... Args>
-    void push( ticket_type k, queue_rep_type& base, Args&&... args )
+    void push( ticket_type k, queue_rep_type& base, queue_allocator_type& allocator, Args&&... args )
     {
         padded_page* p = nullptr;
-        page_allocator_type page_allocator(base.get_allocator());
+        page_allocator_type page_allocator(allocator);
         size_type index = prepare_page(k, base, page_allocator, p);
         __TBB_ASSERT(p != nullptr, "Page was not prepared");
 
@@ -152,38 +153,38 @@ class micro_queue {
         // variadic capture on GCC 4.8.5
         auto value_guard = make_raii_guard([&] {
             ++base.n_invalid_entries;
-            call_itt_notify(releasing, &tail_counter);
+            d1::call_itt_notify(d1::releasing, &tail_counter);
             tail_counter.fetch_add(queue_rep_type::n_queue);
         });
 
         page_allocator_traits::construct(page_allocator, &(*p)[index], std::forward<Args>(args)...);
         // If no exception was thrown, mark item as present.
         p->mask.store(p->mask.load(std::memory_order_relaxed) | uintptr_t(1) << index, std::memory_order_relaxed);
-        call_itt_notify(releasing, &tail_counter);
+        d1::call_itt_notify(d1::releasing, &tail_counter);
 
         value_guard.dismiss();
         tail_counter.fetch_add(queue_rep_type::n_queue);
     }
 
-    void abort_push( ticket_type k, queue_rep_type& base) {
+    void abort_push( ticket_type k, queue_rep_type& base, queue_allocator_type& allocator ) {
         padded_page* p = nullptr;
-        prepare_page(k, base, base.get_allocator(), p);
+        prepare_page(k, base, allocator, p);
         ++base.n_invalid_entries;
         tail_counter.fetch_add(queue_rep_type::n_queue);
     }
 
-    bool pop( void* dst, ticket_type k, queue_rep_type& base ) {
+    bool pop( void* dst, ticket_type k, queue_rep_type& base, queue_allocator_type& allocator) {
         k &= -queue_rep_type::n_queue;
         spin_wait_until_eq(head_counter, k);
-        call_itt_notify(acquired, &head_counter);
+        d1::call_itt_notify(d1::acquired, &head_counter);
         spin_wait_while_eq(tail_counter, k);
-        call_itt_notify(acquired, &tail_counter);
+        d1::call_itt_notify(d1::acquired, &tail_counter);
         padded_page *p = head_page.load(std::memory_order_acquire);
         __TBB_ASSERT( p, nullptr );
         size_type index = modulo_power_of_two( k/queue_rep_type::n_queue, items_per_page );
         bool success = false;
         {
-            page_allocator_type page_allocator(base.get_allocator());
+            page_allocator_type page_allocator(allocator);
             micro_queue_pop_finalizer<self_type, value_type, page_allocator_type> finalizer(*this, page_allocator,
                 k + queue_rep_type::n_queue, index == items_per_page - 1 ? p : nullptr );
             if (p->mask.load(std::memory_order_relaxed) & (std::uintptr_t(1) << index)) {
@@ -196,7 +197,7 @@ class micro_queue {
         return success;
     }
 
-    micro_queue& assign( const micro_queue& src, queue_rep_type& base,
+    micro_queue& assign( const micro_queue& src, queue_allocator_type& allocator,
         item_constructor_type construct_item )
     {
         head_counter.store(src.head_counter.load(std::memory_order_relaxed), std::memory_order_relaxed);
@@ -211,7 +212,7 @@ class micro_queue {
             size_type end_in_first_page = (index+n_items < items_per_page) ? (index + n_items) : items_per_page;
 
             try_call( [&] {
-                head_page.store(make_copy(base, srcp, index, end_in_first_page, g_index, construct_item), std::memory_order_relaxed);
+                head_page.store(make_copy(allocator, srcp, index, end_in_first_page, g_index, construct_item), std::memory_order_relaxed);
             }).on_exception( [&] {
                 head_counter.store(0, std::memory_order_relaxed);
                 tail_counter.store(0, std::memory_order_relaxed);
@@ -221,7 +222,7 @@ class micro_queue {
             try_call( [&] {
                 if (srcp != src.tail_page.load(std::memory_order_relaxed)) {
                     for (srcp = srcp->next; srcp != src.tail_page.load(std::memory_order_relaxed); srcp=srcp->next ) {
-                        cur_page->next = make_copy( base, srcp, 0, items_per_page, g_index, construct_item );
+                        cur_page->next = make_copy( allocator, srcp, 0, items_per_page, g_index, construct_item );
                         cur_page = cur_page->next;
                     }
 
@@ -229,7 +230,7 @@ class micro_queue {
                     size_type last_index = modulo_power_of_two(tail_counter.load(std::memory_order_relaxed) / queue_rep_type::n_queue, items_per_page);
                     if( last_index==0 ) last_index = items_per_page;
 
-                    cur_page->next = make_copy( base, srcp, 0, last_index, g_index, construct_item );
+                    cur_page->next = make_copy( allocator, srcp, 0, last_index, g_index, construct_item );
                     cur_page = cur_page->next;
                 }
                 tail_page.store(cur_page, std::memory_order_relaxed);
@@ -244,10 +245,10 @@ class micro_queue {
         return *this;
     }
 
-    padded_page* make_copy( queue_rep_type& base, const padded_page* src_page, size_type begin_in_page,
+    padded_page* make_copy( queue_allocator_type& allocator, const padded_page* src_page, size_type begin_in_page,
         size_type end_in_page, ticket_type& g_index, item_constructor_type construct_item )
     {
-        page_allocator_type page_allocator(base.get_allocator());
+        page_allocator_type page_allocator(allocator);
         padded_page* new_page = page_allocator_traits::allocate(page_allocator, 1);
         new_page->next = nullptr;
         new_page->mask.store(src_page->mask.load(std::memory_order_relaxed), std::memory_order_relaxed);
@@ -287,10 +288,10 @@ class micro_queue {
         tail_page.store(pg, std::memory_order_relaxed);
     }
 
-    void clear(queue_rep_type& base) {
+    void clear(queue_allocator_type& allocator ) {
         padded_page* curr_page = head_page.load(std::memory_order_relaxed);
         std::size_t index = head_counter.load(std::memory_order_relaxed);
-        page_allocator_type page_allocator(base.get_allocator());
+        page_allocator_type page_allocator(allocator);
 
         while (curr_page) {
             for (; index != items_per_page - 1; ++index) {
@@ -423,14 +424,13 @@ struct concurrent_queue_rep {
     static constexpr size_type item_size = micro_queue_type::item_size;
     static constexpr size_type items_per_page = micro_queue_type::items_per_page;
 
-    concurrent_queue_rep( queue_allocator_type& alloc ) : my_queue_allocator(alloc)
-    {}
+    concurrent_queue_rep() {}
 
     concurrent_queue_rep( const concurrent_queue_rep& ) = delete;
     concurrent_queue_rep& operator=( const concurrent_queue_rep& ) = delete;
 
-    void clear() {
-        page_allocator_type page_allocator(my_queue_allocator);
+    void clear( queue_allocator_type& alloc ) {
+        page_allocator_type page_allocator(alloc);
         for (size_type i = 0; i < n_queue; ++i) {
             padded_page* tail_page = array[i].get_tail_page();
             if( is_valid_page(tail_page) ) {
@@ -444,7 +444,7 @@ struct concurrent_queue_rep {
         }
     }
 
-    void assign( const concurrent_queue_rep& src, item_constructor_type construct_item ) {
+    void assign( const concurrent_queue_rep& src, queue_allocator_type& alloc, item_constructor_type construct_item ) {
         head_counter.store(src.head_counter.load(std::memory_order_relaxed), std::memory_order_relaxed);
         tail_counter.store(src.tail_counter.load(std::memory_order_relaxed), std::memory_order_relaxed);
         n_invalid_entries.store(src.n_invalid_entries.load(std::memory_order_relaxed), std::memory_order_relaxed);
@@ -453,11 +453,11 @@ struct concurrent_queue_rep {
         size_type queue_idx = 0;
         try_call( [&] {
             for (; queue_idx < n_queue; ++queue_idx) {
-                array[queue_idx].assign(src.array[queue_idx], *this, construct_item);
+                array[queue_idx].assign(src.array[queue_idx], alloc, construct_item);
             }
         }).on_exception( [&] {
             for (size_type i = 0; i < queue_idx + 1; ++i) {
-                array[i].clear(*this);
+                array[i].clear(alloc);
             }
             head_counter.store(0, std::memory_order_relaxed);
             tail_counter.store(0, std::memory_order_relaxed);
@@ -486,10 +486,6 @@ struct concurrent_queue_rep {
         return tc - hc - nie;
     }
 
-    queue_allocator_type& get_allocator() {
-        return my_queue_allocator;
-    }
-
     friend class micro_queue<T, Allocator>;
 
     // Map ticket_type to an array index
@@ -507,7 +503,6 @@ struct concurrent_queue_rep {
     alignas(max_nfs_size) std::atomic<ticket_type> head_counter{};
     alignas(max_nfs_size) std::atomic<ticket_type> tail_counter{};
     alignas(max_nfs_size) std::atomic<size_type> n_invalid_entries{};
-    queue_allocator_type& my_queue_allocator;
 }; // class concurrent_queue_rep
 
 #if _MSC_VER && !defined(__INTEL_COMPILER)
@@ -652,7 +647,7 @@ class concurrent_queue_iterator : public concurrent_queue_iterator_base<typename
     friend struct concurrent_queue_iterator_provider;
 }; // class concurrent_queue_iterator
 
-} // namespace d1
+} // namespace d2
 } // namespace detail
 } // tbb
 
diff --git a/src/tbb/concurrent_bounded_queue.cpp b/src/tbb/concurrent_bounded_queue.cpp
index 90077936f..14617175d 100644
--- a/src/tbb/concurrent_bounded_queue.cpp
+++ b/src/tbb/concurrent_bounded_queue.cpp
@@ -58,8 +58,8 @@ void __TBB_EXPORTED_FUNC wait_bounded_queue_monitor( concurrent_monitor* monitor
 }
 
 void __TBB_EXPORTED_FUNC abort_bounded_queue_monitors( concurrent_monitor* monitors ) {
-    concurrent_monitor& items_avail = monitors[d1::cbq_items_avail_tag];
-    concurrent_monitor& slots_avail = monitors[d1::cbq_slots_avail_tag];
+    concurrent_monitor& items_avail = monitors[d2::cbq_items_avail_tag];
+    concurrent_monitor& slots_avail = monitors[d2::cbq_slots_avail_tag];
 
     items_avail.abort_all();
     slots_avail.abort_all();

From 1e146ec9dbc76e9fab1c251283e9eb3ec3195044 Mon Sep 17 00:00:00 2001
From: "Serov, Vladimir" <vladimir.serov@intel.com>
Date: Thu, 17 Jun 2021 11:49:41 +0300
Subject: [PATCH 2/3] Adding regression test for concurrent_queue ASAN issue

Signed-off-by: Serov, Vladimir <vladimir.serov@intel.com>
---
 .../conformance/conformance_concurrent_queue.cpp | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/test/conformance/conformance_concurrent_queue.cpp b/test/conformance/conformance_concurrent_queue.cpp
index 00ed32650..752412bb3 100644
--- a/test/conformance/conformance_concurrent_queue.cpp
+++ b/test/conformance/conformance_concurrent_queue.cpp
@@ -1207,19 +1207,29 @@ void TestMoveSupportInPushPop() {
 template<class T>
 class allocator: public oneapi::tbb::cache_aligned_allocator<T> {
 public:
+    state_type state;
     std::size_t m_unique_id;
 
-    allocator() : m_unique_id( 0 ) {}
+    allocator() : state(LIVE), m_unique_id(0) {}
+    allocator(size_t unique_id) : state(LIVE) { m_unique_id = unique_id; }
 
-    allocator(size_t unique_id) { m_unique_id = unique_id; }
+    ~allocator() {
+        REQUIRE_MESSAGE(state == LIVE, "Destroyed allocator has been used.");
+        state = DEAD;
+    }
 
     template<typename U>
-    allocator(const allocator<U>& a) noexcept { m_unique_id = a.m_unique_id; }
+    allocator(const allocator<U>&a) noexcept : state(LIVE) {
+        REQUIRE_MESSAGE(a.state == LIVE, "Destroyed allocator has been used.");
+        m_unique_id = a.m_unique_id;
+    }
 
     template<typename U>
     struct rebind { typedef allocator<U> other; };
 
     friend bool operator==(const allocator& lhs, const allocator& rhs) {
+        REQUIRE_MESSAGE(lhs.state == LIVE, "Destroyed allocator has been used.");
+        REQUIRE_MESSAGE(rhs.state == LIVE, "Destroyed allocator has been used.");
         return lhs.m_unique_id == rhs.m_unique_id;
     }
 };

From 2b77b502400824fea84ea90b699af71a61fadfd6 Mon Sep 17 00:00:00 2001
From: "Serov, Vladimir" <vladimir.serov@intel.com>
Date: Thu, 17 Jun 2021 16:25:31 +0300
Subject: [PATCH 3/3] Update with suggestion from anton-potapov

Signed-off-by: Serov, Vladimir <vladimir.serov@intel.com>
---
 test/conformance/conformance_concurrent_queue.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/test/conformance/conformance_concurrent_queue.cpp b/test/conformance/conformance_concurrent_queue.cpp
index 752412bb3..27eec8942 100644
--- a/test/conformance/conformance_concurrent_queue.cpp
+++ b/test/conformance/conformance_concurrent_queue.cpp
@@ -1207,11 +1207,11 @@ void TestMoveSupportInPushPop() {
 template<class T>
 class allocator: public oneapi::tbb::cache_aligned_allocator<T> {
 public:
-    state_type state;
+    state_type state = LIVE;
     std::size_t m_unique_id;
 
-    allocator() : state(LIVE), m_unique_id(0) {}
-    allocator(size_t unique_id) : state(LIVE) { m_unique_id = unique_id; }
+    allocator() : m_unique_id( 0 ) {}
+    allocator(size_t unique_id) { m_unique_id = unique_id; }
 
     ~allocator() {
         REQUIRE_MESSAGE(state == LIVE, "Destroyed allocator has been used.");
@@ -1219,7 +1219,7 @@ class allocator: public oneapi::tbb::cache_aligned_allocator<T> {
     }
 
     template<typename U>
-    allocator(const allocator<U>&a) noexcept : state(LIVE) {
+    allocator(const allocator<U>& a) noexcept {
         REQUIRE_MESSAGE(a.state == LIVE, "Destroyed allocator has been used.");
         m_unique_id = a.m_unique_id;
     }
