Repository: node
Issue: Race condition in the inspector calls WriteRaw() on nullptr
Labels: inspector

* **Version**: v12.18.3
* **Platform**: Linux 4.19.127 x86_64
* **Subsystem**: inspector

NOTE: Unable to reproduce this in v14.8.0.

### What steps will reproduce the bug?

A race condition causing the process to abort can be triggered by running `test-inspector-wait-for-connection.js` in a loop.

To make things easier, first apply this patch:
```diff
diff --git a/src/inspector_socket.cc b/src/inspector_socket.cc
index a7019281af..b9d7f85507 100644
--- a/src/inspector_socket.cc
+++ b/src/inspector_socket.cc
@@ -609,6 +609,7 @@ ProtocolHandler::ProtocolHandler(InspectorSocket* inspector,
 
 int ProtocolHandler::WriteRaw(const std::vector<char>& buffer,
                               uv_write_cb write_cb) {
+  CHECK_NOT_NULL(tcp_);
   return tcp_->WriteRaw(buffer, write_cb);
 }
 ```

Fortunately this can be reproduced with a debug build. So I use the following to reproduce it:
```sh
for i in $(seq 1 1000)
  do echo -ne "$i\r"
  ./out/Debug/node test/parallel/test-inspector-wait-for-connection.js > /dev/null
  if [[ $? -ne 0 ]] || [[ -f "./core" ]]; then
    break
  fi
done
```

### How often does it reproduce? Is there a required condition?

Usually triggers the abort within running the test every 100 times.

### Additional information

The specific issue is that `ProtocolHandler::WriteRaw()` attempts a write to `tcp_` when `tcp_ == 0x0`.

Additional debug information from `lldb`:
```cpp
(lldb) bt
* thread #1, name = 'node', stop reason = signal SIGABRT
    ...
    frame #3: node`node::Assert(info=0x0000000002c5d938) at node_errors.cc:253:3
    frame #4: node`node::inspector::ProtocolHandler::WriteRaw(this=0x00007f9c680011b0, buffer=size=1, write_cb=(node`node::inspector::(anonymous namespace)::WriteRequest::Cleanup(uv_write_s*, int) at inspector_socket.cc:123))(uv_write_s*, int)) at inspector_socket.cc:612:3
    frame #5: node`node::inspector::(anonymous namespace)::WsHandler::Write(this=0x00007f9c680011b0, data=<unavailable>) at inspector_socket.cc:351:5
    frame #6: node`node::inspector::InspectorSocket::Write(this=0x00007f9c68001740, data="{\"method\":\"Runtime.executionContextDestroyed\",\"params\":{\"executionContextId\":1}}", len=80) at inspector_socket.cc:769:22
    frame #7: node`node::inspector::SocketSession::Send(this=0x00007f9c680015f0, message=") at inspector_socket_server.cc:495:15
    frame #8: node`node::inspector::InspectorSocketServer::Send(this=0x00007f9c84a7e9f8, session_id=1, message=") at inspector_socket_server.cc:481:14
    ...

(lldb) f 4
frame #4: 0x0000000000ff2017 node`node::inspector::ProtocolHandler::WriteRaw(this=0x00007f9c680011b0, buffer=size=1, write_cb=(node`node::inspector::(anonymous namespace)::WriteRequest::Cleanup(uv_write_s*, int) at inspector_socket.cc:123))(uv_write_s*, int)) at inspector_socket.cc:612:3
   609 
   610  int ProtocolHandler::WriteRaw(const std::vector<char>& buffer,
   611                                uv_write_cb write_cb) {
-> 612    CHECK_NOT_NULL(tcp_);
   613    return tcp_->WriteRaw(buffer, write_cb);
   614  }
   615

(lldb) fr v
(node::inspector::(anonymous namespace)::WsHandler *) this = 0x00007f9c680011b0
(const std::vector<char, std::allocator<char> > &) buffer = size=1: {
  std::_Vector_base<char, std::allocator<char> > = {
    _M_impl = (_M_start = "\x81P{\"method\":\"Runtime.executionContextDestroyed\",\"params\":{\"executionContextId\":1}}", _M_finish = "", _M_end_of_storage = "")
  }
}
(uv_write_cb) write_cb = 0x0000000000ff4790 (node`node::inspector::(anonymous namespace)::WriteRequest::Cleanup(uv_write_s*, int) at inspector_socket.cc:123)


(lldb) p tcp_
(node::inspector::TcpHolder::Pointer) $0 = nullptr {
  pointer = 0x0000000000000000
}
```