diff --git a/services/device/serial/serial_port_impl.cc b/services/device/serial/serial_port_impl.cc index e11a4e9f42da2..5501199355279 100644 --- a/services/device/serial/serial_port_impl.cc +++ b/services/device/serial/serial_port_impl.cc @@ -5,6 +5,7 @@ #include "services/device/serial/serial_port_impl.h" #include +#include #include #include "base/functional/bind.h" @@ -48,6 +49,24 @@ SerialPortImpl::SerialPortImpl( SerialPortImpl::~SerialPortImpl() { // Cancel I/O operations so that |io_handler_| drops its self-reference. io_handler_->Close(base::DoNothing()); + + // BANDAID FIX (use-after-unmap): On Windows, CancelRead() -> + // PurgeComm(PURGE_RXABORT) returns immediately, before the overlapped IRP + // completes. The kernel still holds a raw pointer into |out_stream_|'s + // shared-memory ring buffer (passed to ReadFile in + // SerialIoHandlerWin::ReadImpl). If |out_stream_| destructs here, MojoClose + // -> UnmapViewOfFile races the kernel's IRP-completion copy. Intentionally + // leak the data-pipe handle so the mapping outlives the IRP. The leak is + // bounded by the data-pipe buffer size; |io_handler_| (kept alive via + // AddRef) Releases() itself once the IRP eventually completes. + // This mirrors the IsReadPending() guard in Flush(kReceive) above. + // TODO(crbug.com/####): Transfer |out_stream_| to |io_handler_| instead. + if (io_handler_->IsReadPending()) { + std::ignore = out_stream_.release(); + } + if (io_handler_->IsWritePending()) { + std::ignore = in_stream_.release(); + } } void SerialPortImpl::OpenPort(const mojom::SerialConnectionOptions& options,