diff --git a/net/spdy/spdy_buffer.cc b/net/spdy/spdy_buffer.cc index 61d39009f2dbd..51fbe67856665 100644 --- a/net/spdy/spdy_buffer.cc +++ b/net/spdy/spdy_buffer.cc @@ -104,9 +104,17 @@ void SpdyBuffer::ConsumeHelper(size_t consume_size, DCHECK_GE(consume_size, 1u); DCHECK_LE(consume_size, GetRemainingSize()); offset_ += consume_size; - for (std::vector::const_iterator it = - consume_callbacks_.begin(); it != consume_callbacks_.end(); ++it) { - it->Run(consume_size, consume_source); + // Copy callbacks before iterating: a consume callback may cause `this` to be + // destroyed reentrantly (e.g. SpdySession::OnReadBufferConsumed → + // DoDrainSession → SpdyProxyClientSocket::OnClose → reentrant + // SpdyReadQueue::Dequeue → pop_front of the same SpdyBuffer). Iterating a + // local copy keeps the iterator valid and keeps each callback's BindState + // alive (via RepeatingCallback's scoped_refptr) even after `this` is freed. + // The callbacks themselves are WeakPtr-bound and tolerate the receiver being + // gone. + std::vector callbacks = consume_callbacks_; + for (const auto& callback : callbacks) { + callback.Run(consume_size, consume_source); } }