Commit 06bb7261 authored by Max Morin's avatar Max Morin Committed by Commit Bot

Fix use-after-free in AudioOutputDevice.

How did this ever work ¯\_(ツ)_/¯.

Bug: 816348
Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: I2fc1767e6c9cf910241938ca85c03bc503039d07
Reviewed-on: https://chromium-review.googlesource.com/937515Reviewed-by: default avatarOlga Sharonova <olka@chromium.org>
Commit-Queue: Max Morin <maxmorin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#539812}
parent f1f0d65d
...@@ -215,8 +215,13 @@ void AudioOutputDevice::CreateStreamOnIOThread() { ...@@ -215,8 +215,13 @@ void AudioOutputDevice::CreateStreamOnIOThread() {
DCHECK(callback_) << "Initialize hasn't been called"; DCHECK(callback_) << "Initialize hasn't been called";
switch (state_) { switch (state_) {
case IPC_CLOSED: case IPC_CLOSED:
if (callback_) // We must make sure to not access |callback_| in case Stop() has already
callback_->OnRenderError(); // been called.
{
base::AutoLock auto_lock_(audio_thread_lock_);
if (!stopping_hack_)
callback_->OnRenderError();
}
break; break;
case IDLE: case IDLE:
......
...@@ -190,7 +190,7 @@ class MEDIA_EXPORT AudioOutputDevice : public AudioRendererSink, ...@@ -190,7 +190,7 @@ class MEDIA_EXPORT AudioOutputDevice : public AudioRendererSink,
// Only used by Unified IO. // Only used by Unified IO.
int session_id_; int session_id_;
// ID of hardware output device to be used (provided session_id_ is zero) // ID of hardware output device to be used (provided |session_id_| is zero)
const std::string device_id_; const std::string device_id_;
const url::Origin security_origin_; const url::Origin security_origin_;
......
...@@ -114,9 +114,7 @@ ACTION_P(QuitLoop, task_runner) { ...@@ -114,9 +114,7 @@ ACTION_P(QuitLoop, task_runner) {
} // namespace. } // namespace.
class AudioOutputDeviceTest class AudioOutputDeviceTest : public testing::Test {
: public testing::Test,
public testing::WithParamInterface<bool> {
public: public:
AudioOutputDeviceTest(); AudioOutputDeviceTest();
~AudioOutputDeviceTest(); ~AudioOutputDeviceTest();
...@@ -309,7 +307,7 @@ void AudioOutputDeviceTest::VerifyBitstreamFields() { ...@@ -309,7 +307,7 @@ void AudioOutputDeviceTest::VerifyBitstreamFields() {
EXPECT_EQ(kBitstreamFrames, buffer->params.bitstream_frames); EXPECT_EQ(kBitstreamFrames, buffer->params.bitstream_frames);
} }
TEST_P(AudioOutputDeviceTest, Initialize) { TEST_F(AudioOutputDeviceTest, Initialize) {
// Tests that the object can be constructed, initialized and destructed // Tests that the object can be constructed, initialized and destructed
// without having ever been started. // without having ever been started.
StopAudioDevice(); StopAudioDevice();
...@@ -317,13 +315,13 @@ TEST_P(AudioOutputDeviceTest, Initialize) { ...@@ -317,13 +315,13 @@ TEST_P(AudioOutputDeviceTest, Initialize) {
// Calls Start() followed by an immediate Stop() and check for the basic message // Calls Start() followed by an immediate Stop() and check for the basic message
// filter messages being sent in that case. // filter messages being sent in that case.
TEST_P(AudioOutputDeviceTest, StartStop) { TEST_F(AudioOutputDeviceTest, StartStop) {
StartAudioDevice(); StartAudioDevice();
StopAudioDevice(); StopAudioDevice();
} }
// AudioOutputDevice supports multiple start/stop sequences. // AudioOutputDevice supports multiple start/stop sequences.
TEST_P(AudioOutputDeviceTest, StartStopStartStop) { TEST_F(AudioOutputDeviceTest, StartStopStartStop) {
StartAudioDevice(); StartAudioDevice();
StopAudioDevice(); StopAudioDevice();
StartAudioDevice(); StartAudioDevice();
...@@ -332,7 +330,7 @@ TEST_P(AudioOutputDeviceTest, StartStopStartStop) { ...@@ -332,7 +330,7 @@ TEST_P(AudioOutputDeviceTest, StartStopStartStop) {
// Simulate receiving OnStreamCreated() prior to processing ShutDownOnIOThread() // Simulate receiving OnStreamCreated() prior to processing ShutDownOnIOThread()
// on the IO loop. // on the IO loop.
TEST_P(AudioOutputDeviceTest, StopBeforeRender) { TEST_F(AudioOutputDeviceTest, StopBeforeRender) {
StartAudioDevice(); StartAudioDevice();
// Call Stop() but don't run the IO loop yet. // Call Stop() but don't run the IO loop yet.
...@@ -345,7 +343,7 @@ TEST_P(AudioOutputDeviceTest, StopBeforeRender) { ...@@ -345,7 +343,7 @@ TEST_P(AudioOutputDeviceTest, StopBeforeRender) {
} }
// Full test with output only. // Full test with output only.
TEST_P(AudioOutputDeviceTest, CreateStream) { TEST_F(AudioOutputDeviceTest, CreateStream) {
StartAudioDevice(); StartAudioDevice();
ExpectRenderCallback(); ExpectRenderCallback();
CreateStream(); CreateStream();
...@@ -354,7 +352,7 @@ TEST_P(AudioOutputDeviceTest, CreateStream) { ...@@ -354,7 +352,7 @@ TEST_P(AudioOutputDeviceTest, CreateStream) {
} }
// Full test with output only with nondefault device. // Full test with output only with nondefault device.
TEST_P(AudioOutputDeviceTest, NonDefaultCreateStream) { TEST_F(AudioOutputDeviceTest, NonDefaultCreateStream) {
SetDevice(kNonDefaultDeviceId); SetDevice(kNonDefaultDeviceId);
StartAudioDevice(); StartAudioDevice();
ExpectRenderCallback(); ExpectRenderCallback();
...@@ -364,7 +362,7 @@ TEST_P(AudioOutputDeviceTest, NonDefaultCreateStream) { ...@@ -364,7 +362,7 @@ TEST_P(AudioOutputDeviceTest, NonDefaultCreateStream) {
} }
// Multiple start/stop with nondefault device // Multiple start/stop with nondefault device
TEST_P(AudioOutputDeviceTest, NonDefaultStartStopStartStop) { TEST_F(AudioOutputDeviceTest, NonDefaultStartStopStartStop) {
SetDevice(kNonDefaultDeviceId); SetDevice(kNonDefaultDeviceId);
StartAudioDevice(); StartAudioDevice();
StopAudioDevice(); StopAudioDevice();
...@@ -378,13 +376,23 @@ TEST_P(AudioOutputDeviceTest, NonDefaultStartStopStartStop) { ...@@ -378,13 +376,23 @@ TEST_P(AudioOutputDeviceTest, NonDefaultStartStopStartStop) {
StopAudioDevice(); StopAudioDevice();
} }
TEST_P(AudioOutputDeviceTest, UnauthorizedDevice) { TEST_F(AudioOutputDeviceTest, UnauthorizedDevice) {
SetDevice(kUnauthorizedDeviceId); SetDevice(kUnauthorizedDeviceId);
StartAudioDevice(); StartAudioDevice();
StopAudioDevice(); StopAudioDevice();
} }
TEST_P(AudioOutputDeviceTest, AuthorizationTimedOut) { TEST_F(AudioOutputDeviceTest,
StartUnauthorizedDeviceAndStopBeforeErrorFires_NoError) {
SetDevice(kUnauthorizedDeviceId);
audio_device_->Start();
// Don't run the runloop. We stop before |audio_device| gets the
// authorization error, so it's not allowed to dereference |callback_|.
EXPECT_CALL(callback_, OnRenderError()).Times(0);
StopAudioDevice();
}
TEST_F(AudioOutputDeviceTest, AuthorizationTimedOut) {
base::Thread thread("DeviceInfo"); base::Thread thread("DeviceInfo");
thread.Start(); thread.Start();
...@@ -415,7 +423,7 @@ TEST_P(AudioOutputDeviceTest, AuthorizationTimedOut) { ...@@ -415,7 +423,7 @@ TEST_P(AudioOutputDeviceTest, AuthorizationTimedOut) {
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
} }
TEST_P(AudioOutputDeviceTest, BitstreamFormatTest) { TEST_F(AudioOutputDeviceTest, BitstreamFormatTest) {
SetupBitstreamParameters(); SetupBitstreamParameters();
StartAudioDevice(); StartAudioDevice();
ExpectRenderCallback(); ExpectRenderCallback();
...@@ -426,6 +434,4 @@ TEST_P(AudioOutputDeviceTest, BitstreamFormatTest) { ...@@ -426,6 +434,4 @@ TEST_P(AudioOutputDeviceTest, BitstreamFormatTest) {
StopAudioDevice(); StopAudioDevice();
} }
INSTANTIATE_TEST_CASE_P(Render, AudioOutputDeviceTest, Values(false));
} // namespace media. } // namespace media.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment