diff --git a/device/bluetooth/bluetooth_socket_mac.mm b/device/bluetooth/bluetooth_socket_mac.mm index 0000000..1111111 100644 --- a/device/bluetooth/bluetooth_socket_mac.mm +++ b/device/bluetooth/bluetooth_socket_mac.mm @@ -771,14 +771,24 @@ void BluetoothSocketMac::Send(scoped_refptr buffer, uint16_t mtu = channel_->GetOutgoingMTU(); auto send_buffer = base::MakeRefCounted(buffer.get(), buffer_size); while (send_buffer->BytesRemaining() > 0) { int byte_count = send_buffer->BytesRemaining(); if (byte_count > mtu) byte_count = mtu; + // Increment the in-flight counter BEFORE issuing the write. IOBluetooth is + // known to synchronously dispatch delegate selectors from inside the + // initiating call (see the OpenComplete handling above). If + // -[IOBluetoothRFCOMMChannel writeAsync:length:refcon:] does the same and + // synchronously fires rfcommChannelWriteComplete:, OnChannelWriteComplete + // would observe active_async_writes==0, decrement to -1, prematurely pop + // |request| from |send_queue_|, and the post-call increment below would be + // a write-after-free into the freed SendRequest slot. + request_ptr->active_async_writes++; IOReturn status = channel_->WriteAsync(send_buffer->data(), byte_count, request_ptr); if (status != kIOReturnSuccess) { + request_ptr->active_async_writes--; std::stringstream error; error << "Failed to connect bluetooth socket (" << channel_->GetDeviceAddress() << "): (" << status << ")"; @@ -794,9 +804,8 @@ void BluetoothSocketMac::Send(scoped_refptr buffer, send_queue_.pop(); } return; } - request_ptr->active_async_writes++; send_buffer->DidConsume(byte_count); } }