@@ -324,33 +324,32 @@ IOBuf::Block* share_tls_block() {
324324void release_tls_block_chain (IOBuf::Block* b) {
325325 TLSData& tls_data = g_tls_data;
326326 size_t n = 0 ;
327+ size_t n_hit_threshold = 0 ;
327328 if (tls_data.num_blocks >= max_blocks_per_thread ()) {
328329 do {
329330 ++n;
330331 IOBuf::Block* const saved_next = b->u .portal_next ;
331- b->dec_ref ();
332+ // If b is already cached in TLS, dec_ref() would drop a reference
333+ // still owned by the TLS list and leave a dangling pointer behind.
334+ if (!is_in_tls_block_chain (tls_data.block_head , b)) {
335+ b->dec_ref ();
336+ ++n_hit_threshold;
337+ }
332338 b = saved_next;
333339 } while (b);
334- g_num_hit_tls_threshold.fetch_add (n, butil::memory_order_relaxed);
340+ g_num_hit_tls_threshold.fetch_add (
341+ n_hit_threshold, butil::memory_order_relaxed);
335342 return ;
336343 }
337- IOBuf::Block* const old_head = tls_data.block_head ;
338344 IOBuf::Block* first_b = b;
339345 IOBuf::Block* last_b = NULL ;
340346 do {
341347 ++n;
342348 CHECK (!b->full ());
343- // If any block in the incoming chain is already the TLS block_head,
344- // linking last_b->portal_next = block_head would create a cycle:
345- // - Single-block chain [B] where B == block_head:
346- // last_b->portal_next = B, i.e. B->portal_next = B (self-loop)
347- // - Multi-block chain [A -> B] where A == block_head:
348- // last_b(B)->portal_next = A, creating A -> B -> A (cycle)
349- // Return early before any state is modified so that num_blocks stays
350- // consistent with the actual list length (remove_tls_block_chain
351- // verifies this with CHECK_EQ at thread exit).
352- // See https://github.com/apache/brpc/issues/3243
353- if (b == old_head) {
349+ // Guard against overlap with any node already cached in TLS, not just
350+ // block_head. Otherwise returning X into H -> X would create a
351+ // 2-node cycle X -> H -> X and hang later list traversal.
352+ if (is_in_tls_block_chain (tls_data.block_head , b)) {
354353 return ;
355354 }
356355 if (b->u .portal_next == NULL ) {
@@ -359,7 +358,7 @@ void release_tls_block_chain(IOBuf::Block* b) {
359358 }
360359 b = b->u .portal_next ;
361360 } while (true );
362- last_b->u .portal_next = old_head ;
361+ last_b->u .portal_next = tls_data. block_head ;
363362 tls_data.block_head = first_b;
364363 tls_data.num_blocks += n;
365364 if (!tls_data.registered ) {
0 commit comments