Skip to content

Commit 4e5f024

Browse files
shinrichmaskit
authored andcommitted
Fix crash in H2 priority tree cleanup.
1 parent 540a628 commit 4e5f024

File tree

3 files changed

+33
-13
lines changed

3 files changed

+33
-13
lines changed

proxy/http2/Http2ConnectionState.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1125,6 +1125,7 @@ bool
11251125
Http2ConnectionState::delete_stream(Http2Stream *stream)
11261126
{
11271127
ink_assert(nullptr != stream);
1128+
SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
11281129

11291130
// If stream has already been removed from the list, just go on
11301131
if (!stream_list.in(stream)) {
@@ -1140,7 +1141,9 @@ Http2ConnectionState::delete_stream(Http2Stream *stream)
11401141
dependency_tree->deactivate(node, 0);
11411142
}
11421143
dependency_tree->remove(node);
1144+
// ink_release_assert(dependency_tree->find(stream->get_id()) == nullptr);
11431145
}
1146+
stream->priority_node = nullptr;
11441147
}
11451148

11461149
if (stream->get_state() != Http2StreamState::HTTP2_STREAM_STATE_CLOSED) {
@@ -1166,7 +1169,6 @@ Http2ConnectionState::release_stream(Http2Stream *stream)
11661169
ink_assert(client_streams_out_count > 0);
11671170
--client_streams_out_count;
11681171
}
1169-
stream_list.remove(stream);
11701172
}
11711173

11721174
if (ua_session) {

proxy/http2/Http2DependencyTree.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ template <typename T> class Tree
119119
void activate(Node *node);
120120
void deactivate(Node *node, uint32_t sent);
121121
void update(Node *node, uint32_t sent);
122+
bool in(Node *current, Node *node);
122123
uint32_t size() const;
123124

124125
private:
@@ -202,6 +203,7 @@ Tree<T>::add(uint32_t parent_id, uint32_t id, uint32_t weight, bool exclusive, T
202203

203204
parent->children.push(node);
204205
if (!node->queue->empty()) {
206+
ink_release_assert(!node->queued);
205207
parent->queue->push(node->entry);
206208
node->queued = true;
207209
}
@@ -210,6 +212,27 @@ Tree<T>::add(uint32_t parent_id, uint32_t id, uint32_t weight, bool exclusive, T
210212
return node;
211213
}
212214

215+
template <typename T>
216+
bool
217+
Tree<T>::in(Node *current, Node *node)
218+
{
219+
bool retval = false;
220+
if (current == nullptr)
221+
current = _root;
222+
if (current->queue->in(node->entry)) {
223+
return true;
224+
} else {
225+
Node *child = current->children.head;
226+
while (child) {
227+
if (in(child, node)) {
228+
return true;
229+
}
230+
child = child->link.next;
231+
}
232+
}
233+
return retval;
234+
}
235+
213236
template <typename T>
214237
void
215238
Tree<T>::remove(Node *node)
@@ -242,6 +265,8 @@ Tree<T>::remove(Node *node)
242265
remove(parent);
243266
}
244267

268+
// ink_release_assert(!this->in(nullptr, node));
269+
245270
--_node_count;
246271
delete node;
247272
}

proxy/http2/Http2Stream.cc

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -671,21 +671,14 @@ Http2Stream::destroy()
671671

672672
// Safe to initiate SSN_CLOSE if this is the last stream
673673
if (parent) {
674-
// release_stream and delete_stream indirectly call each other and seem to have a lot of commonality
675-
// Should get resolved at somepoint.
676674
Http2ClientSession *h2_parent = static_cast<Http2ClientSession *>(parent);
677675
SCOPED_MUTEX_LOCK(lock, h2_parent->connection_state.mutex, this_ethread());
678-
h2_parent->connection_state.release_stream(this);
676+
// Make sure the stream is removed from the stream list and priority tree
677+
// In many cases, this has been called earlier, so this call is a no-op
678+
h2_parent->connection_state.delete_stream(this);
679679

680-
// Current Http2ConnectionState implementation uses a memory pool for instantiating streams and DLL<> stream_list for storing
681-
// active streams. Destroying a stream before deleting it from stream_list and then creating a new one + reusing the same chunk
682-
// from the memory pool right away always leads to destroying the DLL structure (deadlocks, inconsistencies).
683-
// The following is meant as a safety net since the consequences are disastrous. Until the design/implementation changes it
684-
// seems
685-
// less error prone to (double) delete before destroying (noop if already deleted).
686-
if (h2_parent->connection_state.delete_stream(this)) {
687-
Warning("Http2Stream was about to be deallocated without removing it from the active stream list");
688-
}
680+
// Update session's stream counts, so it accurately goes into keep-alive state
681+
h2_parent->connection_state.release_stream(this);
689682
}
690683

691684
// Clean up the write VIO in case of inactivity timeout

0 commit comments

Comments
 (0)