You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2017/11/13 02:30:01 UTC

[trafficserver] branch 7.1.x updated: Fix crash in H2 priority tree cleanup.

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

zwoop pushed a commit to branch 7.1.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/7.1.x by this push:
     new 87f8b46  Fix crash in H2 priority tree cleanup.
87f8b46 is described below

commit 87f8b46a5abc403d29b1ae4e598c8ba9a11996c5
Author: Susan Hinrichs <sh...@apache.org>
AuthorDate: Tue Nov 7 00:08:36 2017 +0000

    Fix crash in H2 priority tree cleanup.
    
    (cherry picked from commit 4e5f024ebc0ea439371aa079f9a90a4bc419170e)
---
 proxy/http2/Http2ConnectionState.cc |  4 +++-
 proxy/http2/Http2DependencyTree.h   | 25 +++++++++++++++++++++++++
 proxy/http2/Http2Stream.cc          | 17 +++++------------
 3 files changed, 33 insertions(+), 13 deletions(-)

diff --git a/proxy/http2/Http2ConnectionState.cc b/proxy/http2/Http2ConnectionState.cc
index 8337615..10e20c6 100644
--- a/proxy/http2/Http2ConnectionState.cc
+++ b/proxy/http2/Http2ConnectionState.cc
@@ -1100,6 +1100,7 @@ bool
 Http2ConnectionState::delete_stream(Http2Stream *stream)
 {
   ink_assert(nullptr != stream);
+  SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
 
   // If stream has already been removed from the list, just go on
   if (!stream_list.in(stream)) {
@@ -1115,7 +1116,9 @@ Http2ConnectionState::delete_stream(Http2Stream *stream)
         dependency_tree->deactivate(node, 0);
       }
       dependency_tree->remove(node);
+      // ink_release_assert(dependency_tree->find(stream->get_id()) == nullptr);
     }
+    stream->priority_node = nullptr;
   }
 
   if (stream->get_state() != Http2StreamState::HTTP2_STREAM_STATE_CLOSED) {
@@ -1141,7 +1144,6 @@ Http2ConnectionState::release_stream(Http2Stream *stream)
       ink_assert(client_streams_out_count > 0);
       --client_streams_out_count;
     }
-    stream_list.remove(stream);
   }
 
   if (ua_session) {
diff --git a/proxy/http2/Http2DependencyTree.h b/proxy/http2/Http2DependencyTree.h
index f0a5692..39b2165 100644
--- a/proxy/http2/Http2DependencyTree.h
+++ b/proxy/http2/Http2DependencyTree.h
@@ -118,6 +118,7 @@ public:
   void activate(Node *node);
   void deactivate(Node *node, uint32_t sent);
   void update(Node *node, uint32_t sent);
+  bool in(Node *current, Node *node);
   uint32_t size() const;
 
 private:
@@ -201,6 +202,7 @@ Tree<T>::add(uint32_t parent_id, uint32_t id, uint32_t weight, bool exclusive, T
 
   parent->children.push(node);
   if (!node->queue->empty()) {
+    ink_release_assert(!node->queued);
     parent->queue->push(node->entry);
     node->queued = true;
   }
@@ -210,6 +212,27 @@ Tree<T>::add(uint32_t parent_id, uint32_t id, uint32_t weight, bool exclusive, T
 }
 
 template <typename T>
+bool
+Tree<T>::in(Node *current, Node *node)
+{
+  bool retval = false;
+  if (current == nullptr)
+    current = _root;
+  if (current->queue->in(node->entry)) {
+    return true;
+  } else {
+    Node *child = current->children.head;
+    while (child) {
+      if (in(child, node)) {
+        return true;
+      }
+      child = child->link.next;
+    }
+  }
+  return retval;
+}
+
+template <typename T>
 void
 Tree<T>::remove(Node *node)
 {
@@ -241,6 +264,8 @@ Tree<T>::remove(Node *node)
     remove(parent);
   }
 
+  // ink_release_assert(!this->in(nullptr, node));
+
   --_node_count;
   delete node;
 }
diff --git a/proxy/http2/Http2Stream.cc b/proxy/http2/Http2Stream.cc
index 8ba5e19..7028704 100644
--- a/proxy/http2/Http2Stream.cc
+++ b/proxy/http2/Http2Stream.cc
@@ -666,21 +666,14 @@ Http2Stream::destroy()
 
   // Safe to initiate SSN_CLOSE if this is the last stream
   if (parent) {
-    // release_stream and delete_stream indirectly call each other and seem to have a lot of commonality
-    // Should get resolved at somepoint.
     Http2ClientSession *h2_parent = static_cast<Http2ClientSession *>(parent);
     SCOPED_MUTEX_LOCK(lock, h2_parent->connection_state.mutex, this_ethread());
-    h2_parent->connection_state.release_stream(this);
+    // Make sure the stream is removed from the stream list and priority tree
+    // In many cases, this has been called earlier, so this call is a no-op
+    h2_parent->connection_state.delete_stream(this);
 
-    // Current Http2ConnectionState implementation uses a memory pool for instantiating streams and DLL<> stream_list for storing
-    // active streams. Destroying a stream before deleting it from stream_list and then creating a new one + reusing the same chunk
-    // from the memory pool right away always leads to destroying the DLL structure (deadlocks, inconsistencies).
-    // The following is meant as a safety net since the consequences are disastrous. Until the design/implementation changes it
-    // seems
-    // less error prone to (double) delete before destroying (noop if already deleted).
-    if (h2_parent->connection_state.delete_stream(this)) {
-      Warning("Http2Stream was about to be deallocated without removing it from the active stream list");
-    }
+    // Update session's stream counts, so it accurately goes into keep-alive state
+    h2_parent->connection_state.release_stream(this);
   }
 
   // Clean up the write VIO in case of inactivity timeout

-- 
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].