This is an automated email from the ASF dual-hosted git repository.

tqchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git


The following commit(s) were added to refs/heads/main by this push:
     new f6aab98ace [Bugfix][Support] Fix copy constructor for 
support::OrderedSet (#17044)
f6aab98ace is described below

commit f6aab98ace3c7c15df309b5a89f39ac3e92e5a6c
Author: Eric Lunderberg <[email protected]>
AuthorDate: Thu May 30 06:28:35 2024 -0500

    [Bugfix][Support] Fix copy constructor for support::OrderedSet (#17044)
    
    Prior to this commit, the `support::OrderedSet<T>` utility used the
    default copy constructor and copy assignment, which would copy both
    the `OrderedSet::elements_` and `OrderedSet::elem_to_iter_` members.
    While this is the correct behavior for `elements_`, the copy of
    `elem_to_iter_` would contain references to the original's `element_`,
    rather than to its own.
    
    While `elem_to_iter_` is used in both `OrderedSet::push_back` and
    `OrderedSet::erase`, the implementation of `OrderedSet::push_back`
    only depends on the keys used in `elem_to_iter_`, and does not depend
    on the values stored.  As a result, this bug could go undetected for
    append-only usage, which is the most frequent use of `OrderedSet`.
    
    This commit updates `support::OrderedSet` to have an explicit copy
    constructor and copy assignment.  Only the `std::list<T> elements_`
    member may be copied, while the `elem_to_iter_` must instead be
    rebuilt.
---
 src/support/ordered_set.h | 31 +++++++++++++++++++++++++++----
 1 file changed, 27 insertions(+), 4 deletions(-)

diff --git a/src/support/ordered_set.h b/src/support/ordered_set.h
index 741f0b18e6..11acb8c3fe 100644
--- a/src/support/ordered_set.h
+++ b/src/support/ordered_set.h
@@ -54,11 +54,28 @@ class OrderedSet {
  public:
   OrderedSet() = default;
 
+  /* \brief Explicit copy constructor
+   *
+   * The default copy constructor would copy both `elements_` and
+   * `elem_to_iter_`.  While this is the correct behavior for
+   * `elements_`, the copy of `elem_to_iter_` would contain references
+   * to the original's `element_`, rather than to its own
+   */
+  OrderedSet(const OrderedSet<T>& other) : elements_(other.elements_) { 
InitElementToIter(); }
+
+  /* \brief Explicit copy assignment
+   *
+   * Implemented in terms of the copy constructor, and the default
+   * move assignment.
+   */
+  OrderedSet& operator=(const OrderedSet<T>& other) { return *this = 
OrderedSet(other); }
+
+  OrderedSet(OrderedSet<T>&&) = default;
+  OrderedSet& operator=(OrderedSet<T>&&) = default;
+
   template <typename Iter>
-  OrderedSet(Iter begin, Iter end) {
-    for (auto it = begin; it != end; it++) {
-      push_back(*it);
-    }
+  OrderedSet(Iter begin, Iter end) : elements_(begin, end) {
+    InitElementToIter();
   }
 
   void push_back(const T& t) {
@@ -90,6 +107,12 @@ class OrderedSet {
   auto empty() const { return elements_.empty(); }
 
  private:
+  void InitElementToIter() {
+    for (auto it = elements_.begin(); it != elements_.end(); it++) {
+      elem_to_iter_[*it] = it;
+    }
+  }
+
   std::list<T> elements_;
   typename detail::OrderedSetLookupType<T>::MapType elem_to_iter_;
 };

Reply via email to