- From: Jan-Ivar Bruaroey via GitHub <sysbot+gh@w3.org>
- Date: Sat, 15 Feb 2020 01:22:00 +0000
- To: public-webrtc-logs@w3.org
jan-ivar has just created a new issue for https://github.com/w3c/webrtc-pc: == JSEP reads & modifies transceivers in parallel, causing racy behavior. == [Webrtc-pc](https://w3c.github.io/webrtc-pc/#set-description) runs JSEP in the background (*"In parallel, start the process to apply description as described in [JSEP]"* and *"If ... applied successfully"* will *"queue a task"* to main thread with results). But [section 5.9](https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-25#section-5.9) ("Apply a Local Description") reads the transceiver list and read/writes the `mid` property ("[associated](https://w3c.github.io/webrtc-pc/#dfn-associated)"). Those are main-thread properties read/written from the wrong thread: ``` * If there is no RtpTransceiver associated with this m= section, find one and associate it with this m= section according to the following steps. Note that this situation will only occur when applying an offer. + Find the RtpTransceiver that corresponds to this m= section, using the mapping between transceivers and m= section indices established when creating the offer. + Set the value of this RtpTransceiver's mid property to the MID of the m= section. ``` The read may be fine, since the only havoc JS can wreak here is stop a transceiver, which JSEP doesn't seem to care about. But it writes the `mid` which may race with JS-reads & [ONN](https://w3c.github.io/webrtc-pc/#dfn-check-if-negotiation-is-needed). E.g.: ```js const [transceiver] = pc.getTransceivers(); pc.setLocalDescription(offer); // note: no await console.log(transceiver.mid); // null? transceiver.sender.setStreams(streams); // will negotiationneeded fire? ``` [Section 5.10](https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-25#section-5.10) ("Apply a Remote Description") also reads the transceiver list & read/writes the `mid`: * If the m= section is not associated with any RtpTransceiver (possibly because it was dissociated in the previous step), either find an RtpTransceiver or create one according to the following steps: + If the m= section is sendrecv or recvonly, and there are RtpTransceivers of the same type that were added to the PeerConnection by addTrack and are not associated with any m= section and are not stopped, find the first (according to the canonical order described in Section 5.2.1) such RtpTransceiver. + If no RtpTransceiver was found in the previous step, create one with a recvonly direction. + Associate the found or created RtpTransceiver with the m= section by setting the value of the RtpTransceiver's mid property to the MID of the m= section, and establish a mapping between the transceiver and the index of the m= section. If the m= section does not include a MID (i.e., the remote endpoint does not support the MID extension), generate a value for the RtpTransceiver mid property, following the guidance for "a=mid" mentioned in Section 5.2.1. This suffers from the same `mid` write problem, but additionally, the transceiver list changing under JSEP may cause racy behavior as well. E.g.: ```js pc.setRemoteDescription(offer); // note: no await pc.addTrack(track, stream); // Supposed to always get associated ``` Now, there's also language in _addTrack_ to associate post-SRD _success_, but it looks at **[[CurrentDescription]]**, so there's potentially the tiniest window between the steps above the queued SRD success-task, where the transceiver would not get associated. I was unable to verify this (the 3rd test in [this fiddle](https://jsfiddle.net/jib1/q2rgco6t/) fails in Safari, but for slightly different timing reasons). Ironically, fixing this to not read across threads likely widens that time window. cc @docfaraday Please view or discuss this issue at https://github.com/w3c/webrtc-pc/issues/2476 using your GitHub account
Received on Saturday, 15 February 2020 01:22:04 UTC