Bug 1414623 - P1: Make state_callback synchronous. r=kinetik
authorDan Glastonbury <dan.glastonbury@gmail.com>
Fri, 10 Nov 2017 12:03:45 +1000
changeset 443391 96e5e96d36e919265f0d4671513b17925dc24914
parent 443390 3b45218edc2ef9b29e4225a9af104fd44cf389d2
child 443392 b69589aa70895d84e2c889e482043b6ae16f2f62
push id8527
push userCallek@gmail.com
push dateThu, 11 Jan 2018 21:05:50 +0000
treeherdermozilla-beta@95342d212a7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik
bugs1414623
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1414623 - P1: Make state_callback synchronous. r=kinetik MozReview-Commit-ID: EvgJiPQAYO6
media/audioipc/audioipc/src/messages.rs
media/audioipc/client/src/stream.rs
media/audioipc/server/src/lib.rs
--- a/media/audioipc/audioipc/src/messages.rs
+++ b/media/audioipc/audioipc/src/messages.rs
@@ -204,17 +204,18 @@ pub enum ServerMessage {
     StreamStop(usize),
     StreamResetDefaultDevice(usize),
     StreamGetPosition(usize),
     StreamGetLatency(usize),
     StreamSetVolume(usize, f32),
     StreamSetPanning(usize, f32),
     StreamGetCurrentDevice(usize),
 
-    StreamDataCallback(isize)
+    StreamDataCallback(isize),
+    StreamStateCallback
 }
 
 // Server -> Client messages.
 // TODO: Streams need id.
 #[derive(Debug, Serialize, Deserialize)]
 pub enum ClientMessage {
     ClientConnected,
     ClientDisconnected,
--- a/media/audioipc/client/src/stream.rs
+++ b/media/audioipc/client/src/stream.rs
@@ -78,16 +78,21 @@ fn stream_thread(
                     return;
                 }
             },
             ClientMessage::StreamStateCallback(state) => {
                 info!("stream_thread: State Callback: {:?}", state);
                 set_in_callback(true);
                 state_cb(ptr::null_mut(), user_ptr as *mut _, state);
                 set_in_callback(false);
+                let r = conn.send(ServerMessage::StreamStateCallback);
+                if r.is_err() {
+                    debug!("stream_thread: Failed to send StreamStateCallback: {:?}", r);
+                    return;
+                }
             },
             m => {
                 info!("Unexpected ClientMessage: {:?}", m);
             },
         }
     }
 }
 
--- a/media/audioipc/server/src/lib.rs
+++ b/media/audioipc/server/src/lib.rs
@@ -105,17 +105,17 @@ impl cubeb::StreamCallback for Callback 
                     let len = cb_result as usize * self.output_frame_size as usize;
                     self.output_shm.read(&mut real_output[..len]).unwrap();
                     cb_result
                 } else {
                     cb_result
                 }
             },
             _ => {
-                debug!("Unexpected message {:?} during callback", r);
+                debug!("Unexpected message {:?} during data_callback", r);
                 -1
             },
         }
     }
 
     fn state_callback(&mut self, state: cubeb::State) {
         info!("Stream state callback: {:?}", state);
         // TODO: Share this conversion with the same code in cubeb-rs?
@@ -126,16 +126,28 @@ impl cubeb::StreamCallback for Callback 
             cubeb::State::Error => ffi::CUBEB_STATE_ERROR,
         };
         let r = self.connection.send(
             ClientMessage::StreamStateCallback(state)
         );
         if r.is_err() {
             debug!("state_callback: Failed to send to client - got={:?}", r);
         }
+
+        // Bug 1414623 - We need to block on an ACK from the client
+        // side to make state_callback synchronous. If not, then there
+        // exists a race on cubeb_stream_stop()/cubeb_stream_destroy()
+        // in Gecko that results in a UAF.
+        let r = self.connection.receive();
+        match r {
+            Ok(ServerMessage::StreamStateCallback) => {},
+            _ => {
+                debug!("Unexpected message {:?} during state_callback", r);
+            },
+        }
     }
 }
 
 impl Drop for Callback {
     fn drop(&mut self) {
         let r = self.connection.send(ClientMessage::StreamDestroyed);
         if r.is_err() {
             debug!("Callback::drop failed to send StreamDestroyed = {:?}", r);