summaryrefslogtreecommitdiffstats
path: root/mojo
diff options
context:
space:
mode:
authorjam <jam@chromium.org>2015-12-15 15:44:39 -0800
committerCommit bot <commit-bot@chromium.org>2015-12-15 23:45:38 +0000
commitcba3547586790f12aa2cec55f140c87f7aca0c06 (patch)
tree01cb52261a6cbc912e9b303bcb46df58591003c0 /mojo
parentc4bfff28cfbf2944bebc0ee5db6bbd5f1680ec9d (diff)
downloadchromium_src-cba3547586790f12aa2cec55f140c87f7aca0c06.zip
chromium_src-cba3547586790f12aa2cec55f140c87f7aca0c06.tar.gz
chromium_src-cba3547586790f12aa2cec55f140c87f7aca0c06.tar.bz2
Fix race condition with multiplexed message pipes.
The problem was that if a MessagePipeDispatcher was connected to a RoutedRawChannel that had buffered messages to it. OnReadMessage would be called first which would tell the awakables that it's ready for read. But if the awakable called ReadMessage before GotNonTransferableChannel was called, then they wouldn't get any messages because channel_ was null. BUG=561803 TEST=out/Debug/mojo_runner mojo:example_main --use-mus-in-renderer http://www.slashdot.org and then ctrl+n works Review URL: https://codereview.chromium.org/1524333002 Cr-Commit-Position: refs/heads/master@{#365395}
Diffstat (limited to 'mojo')
-rw-r--r--mojo/edk/system/broker_state.cc32
-rw-r--r--mojo/edk/system/broker_state.h5
-rw-r--r--mojo/edk/system/child_broker.cc32
-rw-r--r--mojo/edk/system/child_broker.h5
4 files changed, 44 insertions, 30 deletions
diff --git a/mojo/edk/system/broker_state.cc b/mojo/edk/system/broker_state.cc
index 4fad5a9..739cccd 100644
--- a/mojo/edk/system/broker_state.cc
+++ b/mojo/edk/system/broker_state.cc
@@ -80,15 +80,9 @@ void BrokerState::ConnectMessagePipe(uint64_t pipe_id,
base::Bind(&BrokerState::ChannelDestructed, base::Unretained(this)));
}
- connected_pipes_[pending_connects_[pipe_id]] = in_process_pipes_channel1_;
- connected_pipes_[message_pipe] = in_process_pipes_channel2_;
- in_process_pipes_channel1_->AddRoute(pipe_id, pending_connects_[pipe_id]);
- in_process_pipes_channel2_->AddRoute(pipe_id, message_pipe);
- pending_connects_[pipe_id]->GotNonTransferableChannel(
- in_process_pipes_channel1_->channel());
- message_pipe->GotNonTransferableChannel(
- in_process_pipes_channel2_->channel());
-
+ AttachMessagePipe(pending_connects_[pipe_id], pipe_id,
+ in_process_pipes_channel1_);
+ AttachMessagePipe(message_pipe, pipe_id, in_process_pipes_channel2_);
pending_connects_.erase(pipe_id);
return;
}
@@ -96,11 +90,9 @@ void BrokerState::ConnectMessagePipe(uint64_t pipe_id,
if (pending_child_connects_.find(pipe_id) != pending_child_connects_.end()) {
// A child process has already tried to connect.
ChildBrokerHost* child_host = pending_child_connects_[pipe_id];
- child_host->channel()->AddRoute(pipe_id, message_pipe);
+ AttachMessagePipe(message_pipe, pipe_id, child_host->channel());
child_host->ConnectMessagePipe(pipe_id, 0);
pending_child_connects_.erase(pipe_id);
- connected_pipes_[message_pipe] = child_host->channel();
- message_pipe->GotNonTransferableChannel(child_host->channel()->channel());
return;
}
@@ -178,9 +170,7 @@ void BrokerState::HandleConnectMessagePipe(ChildBrokerHost* pipe_process,
if (pending_connects_.find(pipe_id) != pending_connects_.end()) {
// This parent process is the other side of the given pipe.
MessagePipeDispatcher* pending_pipe = pending_connects_[pipe_id];
- connected_pipes_[pending_pipe] = pipe_process->channel();
- pipe_process->channel()->AddRoute(pipe_id, pending_pipe);
- pending_pipe->GotNonTransferableChannel(pipe_process->channel()->channel());
+ AttachMessagePipe(pending_pipe, pipe_id, pipe_process->channel());
pipe_process->ConnectMessagePipe(pipe_id, 0);
pending_connects_.erase(pipe_id);
return;
@@ -236,5 +226,17 @@ void BrokerState::EnsureProcessesConnected(base::ProcessId pid1,
void BrokerState::ChannelDestructed(RoutedRawChannel* channel) {
}
+void BrokerState::AttachMessagePipe(MessagePipeDispatcher* message_pipe,
+ uint64_t pipe_id,
+ RoutedRawChannel* raw_channel) {
+ connected_pipes_[message_pipe] = raw_channel;
+ // Note: we must call GotNonTransferableChannel before AddRoute because there
+ // could be race conditions if the pipe got queued messages in |AddRoute| but
+ // then when it's read it returns no messages because it doesn't have the
+ // channel yet.
+ message_pipe->GotNonTransferableChannel(raw_channel->channel());
+ raw_channel->AddRoute(pipe_id, message_pipe);
+}
+
} // namespace edk
} // namespace mojo
diff --git a/mojo/edk/system/broker_state.h b/mojo/edk/system/broker_state.h
index 0b017e8..497a2b8 100644
--- a/mojo/edk/system/broker_state.h
+++ b/mojo/edk/system/broker_state.h
@@ -67,6 +67,11 @@ class MOJO_SYSTEM_IMPL_EXPORT BrokerState : NON_EXPORTED_BASE(public Broker) {
// Called on the IO thread.
void ChannelDestructed(RoutedRawChannel* channel);
+ // Helper method to connect the given MessagePipe to the channel.
+ void AttachMessagePipe(MessagePipeDispatcher* message_pipe,
+ uint64_t pipe_id,
+ RoutedRawChannel* raw_channel);
+
#if defined(OS_WIN)
// Used in the parent (unsandboxed) process to hold a mapping between HANDLES
// and tokens. When a child process wants to send a HANDLE to another process,
diff --git a/mojo/edk/system/child_broker.cc b/mojo/edk/system/child_broker.cc
index 2964d20e..d686e74 100644
--- a/mojo/edk/system/child_broker.cc
+++ b/mojo/edk/system/child_broker.cc
@@ -138,15 +138,9 @@ void ChildBroker::ConnectMessagePipe(uint64_t pipe_id,
base::Bind(&ChildBroker::ChannelDestructed, base::Unretained(this)));
}
- connected_pipes_[pending_connects_[pipe_id]] = in_process_pipes_channel1_;
- connected_pipes_[message_pipe] = in_process_pipes_channel2_;
- in_process_pipes_channel1_->AddRoute(pipe_id, pending_connects_[pipe_id]);
- in_process_pipes_channel2_->AddRoute(pipe_id, message_pipe);
- pending_connects_[pipe_id]->GotNonTransferableChannel(
- in_process_pipes_channel1_->channel());
- message_pipe->GotNonTransferableChannel(
- in_process_pipes_channel2_->channel());
-
+ AttachMessagePipe(pending_connects_[pipe_id], pipe_id,
+ in_process_pipes_channel1_);
+ AttachMessagePipe(message_pipe, pipe_id, in_process_pipes_channel2_);
pending_connects_.erase(pipe_id);
return;
}
@@ -212,17 +206,13 @@ void ChildBroker::OnReadMessage(
pending_connects_.erase(pipe_id);
if (peer_pid == 0) {
// The other side is in the parent process.
- connected_pipes_[pipe] = parent_async_channel_;
- parent_async_channel_->AddRoute(pipe_id, pipe);
- pipe->GotNonTransferableChannel(parent_async_channel_->channel());
+ AttachMessagePipe(pipe, pipe_id, parent_async_channel_);
} else if (channels_.find(peer_pid) == channels_.end()) {
// We saw the peer process die before we got the reply from the parent.
pipe->OnError(ERROR_READ_SHUTDOWN);
} else {
CHECK(connected_pipes_.find(pipe) == connected_pipes_.end());
- connected_pipes_[pipe] = channels_[peer_pid];
- channels_[peer_pid]->AddRoute(pipe_id, pipe);
- pipe->GotNonTransferableChannel(channels_[peer_pid]->channel());
+ AttachMessagePipe(pipe, pipe_id, channels_[peer_pid]);
}
} else {
NOTREACHED();
@@ -273,6 +263,18 @@ void ChildBroker::InitAsyncChannel(
}
}
+void ChildBroker::AttachMessagePipe(MessagePipeDispatcher* message_pipe,
+ uint64_t pipe_id,
+ RoutedRawChannel* raw_channel) {
+ connected_pipes_[message_pipe] = raw_channel;
+ // Note: we must call GotNonTransferableChannel before AddRoute because there
+ // could be race conditions if the pipe got queued messages in |AddRoute| but
+ // then when it's read it returns no messages because it doesn't have the
+ // channel yet.
+ message_pipe->GotNonTransferableChannel(raw_channel->channel());
+ raw_channel->AddRoute(pipe_id, message_pipe);
+}
+
#if defined(OS_WIN)
bool ChildBroker::WriteAndReadResponse(BrokerMessage* message,
diff --git a/mojo/edk/system/child_broker.h b/mojo/edk/system/child_broker.h
index 38cef56..c2d09b3 100644
--- a/mojo/edk/system/child_broker.h
+++ b/mojo/edk/system/child_broker.h
@@ -70,6 +70,11 @@ class MOJO_SYSTEM_IMPL_EXPORT ChildBroker
// Initializes |parent_async_channel_|.
void InitAsyncChannel(ScopedPlatformHandle parent_async_channel_handle);
+ // Helper method to connect the given MessagePipe to the channel.
+ void AttachMessagePipe(MessagePipeDispatcher* message_pipe,
+ uint64_t pipe_id,
+ RoutedRawChannel* raw_channel);
+
#if defined(OS_WIN)
// Helper method to write the given message and read back the result.
bool WriteAndReadResponse(BrokerMessage* message,