http2: safer Http2Session destructor

It's hypothetically (and with certain V8 flags) possible for the session
to be garbage collected before all the streams are. In that case, trying
to remove the stream from the session will lead to a segfault due to
attempting to access no longer valid memory. Fix this by unsetting the
session on any streams still around when destroying.

PR-URL: https://github.com/nodejs/node/pull/21194
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com>
This commit is contained in:
Anatoli Papirovski 2018-06-05 20:34:47 -04:00
parent f86a181d47
commit 083139d440
No known key found for this signature in database
GPG Key ID: 614E2E1ABEB4B2C0

View File

@ -499,6 +499,8 @@ Http2Session::Http2Session(Environment* env,
Http2Session::~Http2Session() {
CHECK_EQ(flags_ & SESSION_STATE_HAS_SCOPE, 0);
Debug(this, "freeing nghttp2 session");
for (const auto& stream : streams_)
stream.second->session_ = nullptr;
nghttp2_session_del(session_);
}
@ -1706,11 +1708,11 @@ Http2Stream::Http2Stream(
Http2Stream::~Http2Stream() {
if (session_ == nullptr)
return;
Debug(this, "tearing down stream");
if (session_ != nullptr) {
session_->RemoveStream(this);
session_ = nullptr;
}
session_->RemoveStream(this);
session_ = nullptr;
}
std::string Http2Stream::diagnostic_name() const {
@ -1785,7 +1787,8 @@ void Http2Stream::Destroy() {
// We can destroy the stream now if there are no writes for it
// already on the socket. Otherwise, we'll wait for the garbage collector
// to take care of cleaning up.
if (!stream->session()->HasWritesOnSocketForStream(stream))
if (stream->session() == nullptr ||
!stream->session()->HasWritesOnSocketForStream(stream))
delete stream;
}, this, this->object());