-
Notifications
You must be signed in to change notification settings - Fork 173
Closed
Labels
Description
When running adapter.Connect calls concurrently, I've noticed that connection attempts to a non-existent address sometimes successfully return with the data of other devices.
Minimal repro:
adapter := bluetooth.DefaultAdapter
wg := sync.WaitGroup()
retryConnect := func(addr bluetooth.Addresser, device *bluetooth.Device) {
wg.Add(1)
// Keep retrying until we successfully connect
for {
if d, err := adapter.Connect(addr, bluetooth.ConnectionParams{}); err == nil {
*device = d
break
}
println("Retrying connection to", addr)
}
wg.Done()
}
var dev1, dev2 bluetooth.Device
go retryConnection("addr1", &dev1)
go retryConnection("addr2", &dev2)
wg.Wait()
// At this point, dev1 and dev2 may be swapped or the same device.In the Mac OS implementation of Adapter, newly connected devices are sent over a channel which is shared between all callers (Adapter.connectChan). In Adapter.Connect, we then unconditionally take the first device sent across this channel and return it.
This can lead to a data race in the case where we have multiple goroutines connecting to different devices at once, resulting in adapter.Connect returning successfully with the wrong device.